diff options
| -rw-r--r-- | arch/cris/arch-v32/kernel/signal.c | 144 |
1 files changed, 56 insertions, 88 deletions
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 024cc6901974..58c1866804e3 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c | |||
| @@ -50,7 +50,7 @@ struct rt_signal_frame { | |||
| 50 | unsigned char retcode[8]; /* Trampoline code. */ | 50 | unsigned char retcode[8]; /* Trampoline code. */ |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs); | 53 | void do_signal(int restart, struct pt_regs *regs); |
| 54 | void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, | 54 | void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, |
| 55 | struct pt_regs *regs); | 55 | struct pt_regs *regs); |
| 56 | /* | 56 | /* |
| @@ -61,74 +61,16 @@ int | |||
| 61 | sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, | 61 | sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, |
| 62 | long srp, struct pt_regs *regs) | 62 | long srp, struct pt_regs *regs) |
| 63 | { | 63 | { |
| 64 | sigset_t saveset; | ||
| 65 | |||
| 66 | mask &= _BLOCKABLE; | 64 | mask &= _BLOCKABLE; |
| 67 | |||
| 68 | spin_lock_irq(¤t->sighand->siglock); | 65 | spin_lock_irq(¤t->sighand->siglock); |
| 69 | 66 | current->saved_sigmask = current->blocked; | |
| 70 | saveset = current->blocked; | ||
| 71 | |||
| 72 | siginitset(¤t->blocked, mask); | 67 | siginitset(¤t->blocked, mask); |
| 73 | |||
| 74 | recalc_sigpending(); | ||
| 75 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 76 | |||
| 77 | regs->r10 = -EINTR; | ||
| 78 | |||
| 79 | while (1) { | ||
| 80 | current->state = TASK_INTERRUPTIBLE; | ||
| 81 | schedule(); | ||
| 82 | |||
| 83 | if (do_signal(0, &saveset, regs)) { | ||
| 84 | /* | ||
| 85 | * This point is reached twice: once to call | ||
| 86 | * the signal handler, then again to return | ||
| 87 | * from the sigsuspend system call. When | ||
| 88 | * calling the signal handler, R10 hold the | ||
| 89 | * signal number as set by do_signal(). The | ||
| 90 | * sigsuspend call will always return with | ||
| 91 | * the restored value above; -EINTR. | ||
| 92 | */ | ||
| 93 | return regs->r10; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | /* Define some dummy arguments to be able to reach the regs argument. */ | ||
| 99 | int | ||
| 100 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, | ||
| 101 | long mof, long srp, struct pt_regs *regs) | ||
| 102 | { | ||
| 103 | sigset_t saveset; | ||
| 104 | sigset_t newset; | ||
| 105 | |||
| 106 | if (sigsetsize != sizeof(sigset_t)) | ||
| 107 | return -EINVAL; | ||
| 108 | |||
| 109 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
| 110 | return -EFAULT; | ||
| 111 | |||
| 112 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
| 113 | spin_lock_irq(¤t->sighand->siglock); | ||
| 114 | |||
| 115 | saveset = current->blocked; | ||
| 116 | current->blocked = newset; | ||
| 117 | |||
| 118 | recalc_sigpending(); | 68 | recalc_sigpending(); |
| 119 | spin_unlock_irq(¤t->sighand->siglock); | 69 | spin_unlock_irq(¤t->sighand->siglock); |
| 120 | 70 | current->state = TASK_INTERRUPTIBLE; | |
| 121 | regs->r10 = -EINTR; | 71 | schedule(); |
| 122 | 72 | set_thread_flag(TIF_RESTORE_SIGMASK); | |
| 123 | while (1) { | 73 | return -ERESTARTNOHAND; |
| 124 | current->state = TASK_INTERRUPTIBLE; | ||
| 125 | schedule(); | ||
| 126 | |||
| 127 | if (do_signal(0, &saveset, regs)) { | ||
| 128 | /* See comment in function above. */ | ||
| 129 | return regs->r10; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | } | 74 | } |
| 133 | 75 | ||
| 134 | int | 76 | int |
| @@ -290,7 +232,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, | |||
| 290 | goto badframe; | 232 | goto badframe; |
| 291 | 233 | ||
| 292 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT) | 234 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT) |
| 293 | goto badframe; | 235 | goto badframe; |
| 294 | 236 | ||
| 295 | keep_debug_flags(oldccs, oldspc, regs); | 237 | keep_debug_flags(oldccs, oldspc, regs); |
| 296 | 238 | ||
| @@ -347,11 +289,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) | |||
| 347 | /* Grab and setup a signal frame. | 289 | /* Grab and setup a signal frame. |
| 348 | * | 290 | * |
| 349 | * Basically a lot of state-info is stacked, and arranged for the | 291 | * Basically a lot of state-info is stacked, and arranged for the |
| 350 | * user-mode program to return to the kernel using either a trampoline | 292 | * user-mode program to return to the kernel using either a trampiline |
| 351 | * which performs the syscall sigreturn(), or a provided user-mode | 293 | * which performs the syscall sigreturn(), or a provided user-mode |
| 352 | * trampoline. | 294 | * trampoline. |
| 353 | */ | 295 | */ |
| 354 | static void | 296 | static int |
| 355 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 297 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
| 356 | struct pt_regs * regs) | 298 | struct pt_regs * regs) |
| 357 | { | 299 | { |
| @@ -417,16 +359,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
| 417 | /* Actually move the USP to reflect the stacked frame. */ | 359 | /* Actually move the USP to reflect the stacked frame. */ |
| 418 | wrusp((unsigned long)frame); | 360 | wrusp((unsigned long)frame); |
| 419 | 361 | ||
| 420 | return; | 362 | return 0; |
| 421 | 363 | ||
| 422 | give_sigsegv: | 364 | give_sigsegv: |
| 423 | if (sig == SIGSEGV) | 365 | if (sig == SIGSEGV) |
| 424 | ka->sa.sa_handler = SIG_DFL; | 366 | ka->sa.sa_handler = SIG_DFL; |
| 425 | 367 | ||
| 426 | force_sig(SIGSEGV, current); | 368 | force_sig(SIGSEGV, current); |
| 369 | return -EFAULT; | ||
| 427 | } | 370 | } |
| 428 | 371 | ||
| 429 | static void | 372 | static int |
| 430 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 373 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 431 | sigset_t *set, struct pt_regs * regs) | 374 | sigset_t *set, struct pt_regs * regs) |
| 432 | { | 375 | { |
| @@ -503,21 +446,24 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 503 | /* Actually move the usp to reflect the stacked frame. */ | 446 | /* Actually move the usp to reflect the stacked frame. */ |
| 504 | wrusp((unsigned long)frame); | 447 | wrusp((unsigned long)frame); |
| 505 | 448 | ||
| 506 | return; | 449 | return 0; |
| 507 | 450 | ||
| 508 | give_sigsegv: | 451 | give_sigsegv: |
| 509 | if (sig == SIGSEGV) | 452 | if (sig == SIGSEGV) |
| 510 | ka->sa.sa_handler = SIG_DFL; | 453 | ka->sa.sa_handler = SIG_DFL; |
| 511 | 454 | ||
| 512 | force_sig(SIGSEGV, current); | 455 | force_sig(SIGSEGV, current); |
| 456 | return -EFAULT; | ||
| 513 | } | 457 | } |
| 514 | 458 | ||
| 515 | /* Invoke a singal handler to, well, handle the signal. */ | 459 | /* Invoke a singal handler to, well, handle the signal. */ |
| 516 | static inline void | 460 | static inline int |
| 517 | handle_signal(int canrestart, unsigned long sig, | 461 | handle_signal(int canrestart, unsigned long sig, |
| 518 | siginfo_t *info, struct k_sigaction *ka, | 462 | siginfo_t *info, struct k_sigaction *ka, |
| 519 | sigset_t *oldset, struct pt_regs * regs) | 463 | sigset_t *oldset, struct pt_regs * regs) |
| 520 | { | 464 | { |
| 465 | int ret; | ||
| 466 | |||
| 521 | /* Check if this got called from a system call. */ | 467 | /* Check if this got called from a system call. */ |
| 522 | if (canrestart) { | 468 | if (canrestart) { |
| 523 | /* If so, check system call restarting. */ | 469 | /* If so, check system call restarting. */ |
| @@ -561,19 +507,24 @@ handle_signal(int canrestart, unsigned long sig, | |||
| 561 | 507 | ||
| 562 | /* Set up the stack frame. */ | 508 | /* Set up the stack frame. */ |
| 563 | if (ka->sa.sa_flags & SA_SIGINFO) | 509 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 564 | setup_rt_frame(sig, ka, info, oldset, regs); | 510 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
| 565 | else | 511 | else |
| 566 | setup_frame(sig, ka, oldset, regs); | 512 | ret = setup_frame(sig, ka, oldset, regs); |
| 567 | 513 | ||
| 568 | if (ka->sa.sa_flags & SA_ONESHOT) | 514 | if (ka->sa.sa_flags & SA_ONESHOT) |
| 569 | ka->sa.sa_handler = SIG_DFL; | 515 | ka->sa.sa_handler = SIG_DFL; |
| 570 | 516 | ||
| 571 | spin_lock_irq(¤t->sighand->siglock); | 517 | if (ret == 0) { |
| 572 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 518 | spin_lock_irq(¤t->sighand->siglock); |
| 573 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 519 | sigorsets(¤t->blocked, ¤t->blocked, |
| 574 | sigaddset(¤t->blocked,sig); | 520 | &ka->sa.sa_mask); |
| 575 | recalc_sigpending(); | 521 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 576 | spin_unlock_irq(¤t->sighand->siglock); | 522 | sigaddset(¤t->blocked, sig); |
| 523 | recalc_sigpending(); | ||
| 524 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 525 | } | ||
| 526 | |||
| 527 | return ret; | ||
| 577 | } | 528 | } |
| 578 | 529 | ||
| 579 | /* | 530 | /* |
| @@ -587,12 +538,13 @@ handle_signal(int canrestart, unsigned long sig, | |||
| 587 | * we can use user_mode(regs) to see if we came directly from kernel or user | 538 | * we can use user_mode(regs) to see if we came directly from kernel or user |
| 588 | * mode below. | 539 | * mode below. |
| 589 | */ | 540 | */ |
| 590 | int | 541 | void |
| 591 | do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | 542 | do_signal(int canrestart, struct pt_regs *regs) |
| 592 | { | 543 | { |
| 593 | int signr; | 544 | int signr; |
| 594 | siginfo_t info; | 545 | siginfo_t info; |
| 595 | struct k_sigaction ka; | 546 | struct k_sigaction ka; |
| 547 | sigset_t *oldset; | ||
| 596 | 548 | ||
| 597 | /* | 549 | /* |
| 598 | * The common case should go fast, which is why this point is | 550 | * The common case should go fast, which is why this point is |
| @@ -600,17 +552,28 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | |||
| 600 | * without doing anything. | 552 | * without doing anything. |
| 601 | */ | 553 | */ |
| 602 | if (!user_mode(regs)) | 554 | if (!user_mode(regs)) |
| 603 | return 1; | 555 | return; |
| 604 | 556 | ||
| 605 | if (!oldset) | 557 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 558 | oldset = ¤t->saved_sigmask; | ||
| 559 | else | ||
| 606 | oldset = ¤t->blocked; | 560 | oldset = ¤t->blocked; |
| 607 | 561 | ||
| 608 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 562 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 609 | 563 | ||
| 610 | if (signr > 0) { | 564 | if (signr > 0) { |
| 611 | /* Deliver the signal. */ | 565 | /* Whee! Actually deliver the signal. */ |
| 612 | handle_signal(canrestart, signr, &info, &ka, oldset, regs); | 566 | if (handle_signal(canrestart, signr, &info, &ka, |
| 613 | return 1; | 567 | oldset, regs)) { |
| 568 | /* a signal was successfully delivered; the saved | ||
| 569 | * sigmask will have been stored in the signal frame, | ||
| 570 | * and will be restored by sigreturn, so we can simply | ||
| 571 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
| 572 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 573 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 574 | } | ||
| 575 | |||
| 576 | return; | ||
| 614 | } | 577 | } |
| 615 | 578 | ||
| 616 | /* Got here from a system call? */ | 579 | /* Got here from a system call? */ |
| @@ -628,7 +591,12 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | |||
| 628 | } | 591 | } |
| 629 | } | 592 | } |
| 630 | 593 | ||
| 631 | return 0; | 594 | /* if there's no signal to deliver, we just put the saved sigmask |
| 595 | * back */ | ||
| 596 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 597 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 598 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 599 | } | ||
| 632 | } | 600 | } |
| 633 | 601 | ||
| 634 | asmlinkage void | 602 | asmlinkage void |
| @@ -641,7 +609,7 @@ ugdb_trap_user(struct thread_info *ti, int sig) | |||
| 641 | user_regs(ti)->spc = 0; | 609 | user_regs(ti)->spc = 0; |
| 642 | } | 610 | } |
| 643 | /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA | 611 | /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA |
| 644 | not within any configured h/w breakpoint range). Synchronize with | 612 | not withing any configured h/w breakpoint range). Synchronize with |
| 645 | what already exists for kernel debugging. */ | 613 | what already exists for kernel debugging. */ |
| 646 | if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) { | 614 | if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) { |
| 647 | /* Break 8: subtract 2 from ERP unless in a delay slot. */ | 615 | /* Break 8: subtract 2 from ERP unless in a delay slot. */ |
