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) |