diff options
Diffstat (limited to 'arch/sh/kernel/signal_64.c')
| -rw-r--r-- | arch/sh/kernel/signal_64.c | 154 |
1 files changed, 80 insertions, 74 deletions
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index ce3e851dffcb..b22fdfaaa191 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * arch/sh/kernel/signal_64.c | 2 | * arch/sh/kernel/signal_64.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2000, 2001 Paolo Alberelli | 4 | * Copyright (C) 2000, 2001 Paolo Alberelli |
| 5 | * Copyright (C) 2003 Paul Mundt | 5 | * Copyright (C) 2003 - 2008 Paul Mundt |
| 6 | * Copyright (C) 2004 Richard Curnow | 6 | * Copyright (C) 2004 Richard Curnow |
| 7 | * | 7 | * |
| 8 | * This file is subject to the terms and conditions of the GNU General Public | 8 | * This file is subject to the terms and conditions of the GNU General Public |
| @@ -43,10 +43,38 @@ | |||
| 43 | 43 | ||
| 44 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 44 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 45 | 45 | ||
| 46 | static void | 46 | static int |
| 47 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 47 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| 48 | sigset_t *oldset, struct pt_regs * regs); | 48 | sigset_t *oldset, struct pt_regs * regs); |
| 49 | 49 | ||
| 50 | static inline void | ||
| 51 | handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa) | ||
| 52 | { | ||
| 53 | /* If we're not from a syscall, bail out */ | ||
| 54 | if (regs->syscall_nr < 0) | ||
| 55 | return; | ||
| 56 | |||
| 57 | /* check for system call restart.. */ | ||
| 58 | switch (regs->regs[REG_RET]) { | ||
| 59 | case -ERESTART_RESTARTBLOCK: | ||
| 60 | case -ERESTARTNOHAND: | ||
| 61 | no_system_call_restart: | ||
| 62 | regs->regs[REG_RET] = -EINTR; | ||
| 63 | regs->sr |= 1; | ||
| 64 | break; | ||
| 65 | |||
| 66 | case -ERESTARTSYS: | ||
| 67 | if (!(sa->sa_flags & SA_RESTART)) | ||
| 68 | goto no_system_call_restart; | ||
| 69 | /* fallthrough */ | ||
| 70 | case -ERESTARTNOINTR: | ||
| 71 | /* Decode syscall # */ | ||
| 72 | regs->regs[REG_RET] = regs->syscall_nr; | ||
| 73 | regs->pc -= 4; | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 50 | /* | 78 | /* |
| 51 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 79 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 52 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 80 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| @@ -80,21 +108,23 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
| 80 | oldset = ¤t->blocked; | 108 | oldset = ¤t->blocked; |
| 81 | 109 | ||
| 82 | signr = get_signal_to_deliver(&info, &ka, regs, 0); | 110 | signr = get_signal_to_deliver(&info, &ka, regs, 0); |
| 83 | |||
| 84 | if (signr > 0) { | 111 | if (signr > 0) { |
| 85 | /* Whee! Actually deliver the signal. */ | 112 | if (regs->sr & 1) |
| 86 | handle_signal(signr, &info, &ka, oldset, regs); | 113 | handle_syscall_restart(regs, &ka.sa); |
| 87 | 114 | ||
| 88 | /* | 115 | /* Whee! Actually deliver the signal. */ |
| 89 | * If a signal was successfully delivered, the saved sigmask | 116 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { |
| 90 | * is in its frame, and we can clear the TIF_RESTORE_SIGMASK | 117 | /* |
| 91 | * flag. | 118 | * If a signal was successfully delivered, the |
| 92 | */ | 119 | * saved sigmask is in its frame, and we can |
| 93 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 120 | * clear the TIF_RESTORE_SIGMASK flag. |
| 94 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 121 | */ |
| 95 | 122 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | |
| 96 | tracehook_signal_handler(signr, &info, &ka, regs, 0); | 123 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
| 97 | return 1; | 124 | |
| 125 | tracehook_signal_handler(signr, &info, &ka, regs, 0); | ||
| 126 | return 1; | ||
| 127 | } | ||
| 98 | } | 128 | } |
| 99 | 129 | ||
| 100 | no_signal: | 130 | no_signal: |
| @@ -129,7 +159,6 @@ no_signal: | |||
| 129 | /* | 159 | /* |
| 130 | * Atomically swap in the new signal mask, and wait for a signal. | 160 | * Atomically swap in the new signal mask, and wait for a signal. |
| 131 | */ | 161 | */ |
| 132 | |||
| 133 | asmlinkage int | 162 | asmlinkage int |
| 134 | sys_sigsuspend(old_sigset_t mask, | 163 | sys_sigsuspend(old_sigset_t mask, |
| 135 | unsigned long r3, unsigned long r4, unsigned long r5, | 164 | unsigned long r3, unsigned long r4, unsigned long r5, |
| @@ -235,20 +264,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
| 235 | return do_sigaltstack(uss, uoss, REF_REG_SP); | 264 | return do_sigaltstack(uss, uoss, REF_REG_SP); |
| 236 | } | 265 | } |
| 237 | 266 | ||
| 238 | |||
| 239 | /* | 267 | /* |
| 240 | * Do a signal return; undo the signal stack. | 268 | * Do a signal return; undo the signal stack. |
| 241 | */ | 269 | */ |
| 242 | 270 | struct sigframe { | |
| 243 | struct sigframe | ||
| 244 | { | ||
| 245 | struct sigcontext sc; | 271 | struct sigcontext sc; |
| 246 | unsigned long extramask[_NSIG_WORDS-1]; | 272 | unsigned long extramask[_NSIG_WORDS-1]; |
| 247 | long long retcode[2]; | 273 | long long retcode[2]; |
| 248 | }; | 274 | }; |
| 249 | 275 | ||
| 250 | struct rt_sigframe | 276 | struct rt_sigframe { |
| 251 | { | ||
| 252 | struct siginfo __user *pinfo; | 277 | struct siginfo __user *pinfo; |
| 253 | void *puc; | 278 | void *puc; |
| 254 | struct siginfo info; | 279 | struct siginfo info; |
| @@ -450,7 +475,6 @@ badframe: | |||
| 450 | /* | 475 | /* |
| 451 | * Set up a signal frame. | 476 | * Set up a signal frame. |
| 452 | */ | 477 | */ |
| 453 | |||
| 454 | static int | 478 | static int |
| 455 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 479 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
| 456 | unsigned long mask) | 480 | unsigned long mask) |
| @@ -504,8 +528,8 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | |||
| 504 | void sa_default_restorer(void); /* See comments below */ | 528 | void sa_default_restorer(void); /* See comments below */ |
| 505 | void sa_default_rt_restorer(void); /* See comments below */ | 529 | void sa_default_rt_restorer(void); /* See comments below */ |
| 506 | 530 | ||
| 507 | static void setup_frame(int sig, struct k_sigaction *ka, | 531 | static int setup_frame(int sig, struct k_sigaction *ka, |
| 508 | sigset_t *set, struct pt_regs *regs) | 532 | sigset_t *set, struct pt_regs *regs) |
| 509 | { | 533 | { |
| 510 | struct sigframe __user *frame; | 534 | struct sigframe __user *frame; |
| 511 | int err = 0; | 535 | int err = 0; |
| @@ -596,23 +620,21 @@ static void setup_frame(int sig, struct k_sigaction *ka, | |||
| 596 | 620 | ||
| 597 | set_fs(USER_DS); | 621 | set_fs(USER_DS); |
| 598 | 622 | ||
| 599 | #if DEBUG_SIG | ||
| 600 | /* Broken %016Lx */ | 623 | /* Broken %016Lx */ |
| 601 | printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", | 624 | pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", |
| 602 | signal, | 625 | signal, current->comm, current->pid, frame, |
| 603 | current->comm, current->pid, frame, | 626 | regs->pc >> 32, regs->pc & 0xffffffff, |
| 604 | regs->pc >> 32, regs->pc & 0xffffffff, | 627 | DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); |
| 605 | DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); | ||
| 606 | #endif | ||
| 607 | 628 | ||
| 608 | return; | 629 | return 0; |
| 609 | 630 | ||
| 610 | give_sigsegv: | 631 | give_sigsegv: |
| 611 | force_sigsegv(sig, current); | 632 | force_sigsegv(sig, current); |
| 633 | return -EFAULT; | ||
| 612 | } | 634 | } |
| 613 | 635 | ||
| 614 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 636 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 615 | sigset_t *set, struct pt_regs *regs) | 637 | sigset_t *set, struct pt_regs *regs) |
| 616 | { | 638 | { |
| 617 | struct rt_sigframe __user *frame; | 639 | struct rt_sigframe __user *frame; |
| 618 | int err = 0; | 640 | int err = 0; |
| @@ -702,62 +724,46 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 702 | 724 | ||
| 703 | set_fs(USER_DS); | 725 | set_fs(USER_DS); |
| 704 | 726 | ||
| 705 | #if DEBUG_SIG | 727 | pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", |
| 706 | /* Broken %016Lx */ | 728 | signal, current->comm, current->pid, frame, |
| 707 | printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", | 729 | regs->pc >> 32, regs->pc & 0xffffffff, |
| 708 | signal, | 730 | DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); |
| 709 | current->comm, current->pid, frame, | ||
| 710 | regs->pc >> 32, regs->pc & 0xffffffff, | ||
| 711 | DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); | ||
| 712 | #endif | ||
| 713 | 731 | ||
| 714 | return; | 732 | return 0; |
| 715 | 733 | ||
| 716 | give_sigsegv: | 734 | give_sigsegv: |
| 717 | force_sigsegv(sig, current); | 735 | force_sigsegv(sig, current); |
| 736 | return -EFAULT; | ||
| 718 | } | 737 | } |
| 719 | 738 | ||
| 720 | /* | 739 | /* |
| 721 | * OK, we're invoking a handler | 740 | * OK, we're invoking a handler |
| 722 | */ | 741 | */ |
| 723 | 742 | static int | |
| 724 | static void | ||
| 725 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 743 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| 726 | sigset_t *oldset, struct pt_regs * regs) | 744 | sigset_t *oldset, struct pt_regs * regs) |
| 727 | { | 745 | { |
| 728 | /* Are we from a system call? */ | 746 | int ret; |
| 729 | if (regs->syscall_nr >= 0) { | ||
| 730 | /* If so, check system call restarting.. */ | ||
| 731 | switch (regs->regs[REG_RET]) { | ||
| 732 | case -ERESTART_RESTARTBLOCK: | ||
| 733 | case -ERESTARTNOHAND: | ||
| 734 | no_system_call_restart: | ||
| 735 | regs->regs[REG_RET] = -EINTR; | ||
| 736 | break; | ||
| 737 | |||
| 738 | case -ERESTARTSYS: | ||
| 739 | if (!(ka->sa.sa_flags & SA_RESTART)) | ||
| 740 | goto no_system_call_restart; | ||
| 741 | /* fallthrough */ | ||
| 742 | case -ERESTARTNOINTR: | ||
| 743 | /* Decode syscall # */ | ||
| 744 | regs->regs[REG_RET] = regs->syscall_nr; | ||
| 745 | regs->pc -= 4; | ||
| 746 | } | ||
| 747 | } | ||
| 748 | 747 | ||
| 749 | /* Set up the stack frame */ | 748 | /* Set up the stack frame */ |
| 750 | if (ka->sa.sa_flags & SA_SIGINFO) | 749 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 751 | setup_rt_frame(sig, ka, info, oldset, regs); | 750 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
| 752 | else | 751 | else |
| 753 | setup_frame(sig, ka, oldset, regs); | 752 | ret = setup_frame(sig, ka, oldset, regs); |
| 753 | |||
| 754 | if (ka->sa.sa_flags & SA_ONESHOT) | ||
| 755 | ka->sa.sa_handler = SIG_DFL; | ||
| 756 | |||
| 757 | if (ret == 0) { | ||
| 758 | spin_lock_irq(¤t->sighand->siglock); | ||
| 759 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
| 760 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
| 761 | sigaddset(¤t->blocked,sig); | ||
| 762 | recalc_sigpending(); | ||
| 763 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 764 | } | ||
| 754 | 765 | ||
| 755 | spin_lock_irq(¤t->sighand->siglock); | 766 | return ret; |
| 756 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
| 757 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
| 758 | sigaddset(¤t->blocked,sig); | ||
| 759 | recalc_sigpending(); | ||
| 760 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 761 | } | 767 | } |
| 762 | 768 | ||
| 763 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) | 769 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) |
