diff options
Diffstat (limited to 'arch/sh/kernel/signal_64.c')
-rw-r--r-- | arch/sh/kernel/signal_64.c | 166 |
1 files changed, 88 insertions, 78 deletions
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 552eb810cd85..1d62dfef77f1 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/unistd.h> | 23 | #include <linux/unistd.h> |
24 | #include <linux/stddef.h> | 24 | #include <linux/stddef.h> |
25 | #include <linux/tracehook.h> | ||
25 | #include <asm/ucontext.h> | 26 | #include <asm/ucontext.h> |
26 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
27 | #include <asm/pgtable.h> | 28 | #include <asm/pgtable.h> |
@@ -42,7 +43,84 @@ | |||
42 | 43 | ||
43 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 44 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
44 | 45 | ||
45 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | 46 | /* |
47 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
48 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
49 | * mistake. | ||
50 | * | ||
51 | * Note that we go through the signals twice: once to check the signals that | ||
52 | * the kernel can handle, and then we build all the user-level signal handling | ||
53 | * stack-frames in one go after that. | ||
54 | */ | ||
55 | static int do_signal(struct pt_regs *regs, sigset_t *oldset) | ||
56 | { | ||
57 | siginfo_t info; | ||
58 | int signr; | ||
59 | struct k_sigaction ka; | ||
60 | |||
61 | /* | ||
62 | * We want the common case to go fast, which | ||
63 | * is why we may in certain cases get here from | ||
64 | * kernel mode. Just return without doing anything | ||
65 | * if so. | ||
66 | */ | ||
67 | if (!user_mode(regs)) | ||
68 | return 1; | ||
69 | |||
70 | if (try_to_freeze()) | ||
71 | goto no_signal; | ||
72 | |||
73 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
74 | oldset = ¤t->saved_sigmask; | ||
75 | else if (!oldset) | ||
76 | oldset = ¤t->blocked; | ||
77 | |||
78 | signr = get_signal_to_deliver(&info, &ka, regs, 0); | ||
79 | |||
80 | if (signr > 0) { | ||
81 | /* Whee! Actually deliver the signal. */ | ||
82 | handle_signal(signr, &info, &ka, oldset, regs); | ||
83 | |||
84 | /* | ||
85 | * If a signal was successfully delivered, the saved sigmask | ||
86 | * is in its frame, and we can clear the TIF_RESTORE_SIGMASK | ||
87 | * flag. | ||
88 | */ | ||
89 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
90 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
91 | |||
92 | tracehook_signal_handler(signr, &info, &ka, regs, 0); | ||
93 | return 1; | ||
94 | } | ||
95 | |||
96 | no_signal: | ||
97 | /* Did we come from a system call? */ | ||
98 | if (regs->syscall_nr >= 0) { | ||
99 | /* Restart the system call - no handlers present */ | ||
100 | switch (regs->regs[REG_RET]) { | ||
101 | case -ERESTARTNOHAND: | ||
102 | case -ERESTARTSYS: | ||
103 | case -ERESTARTNOINTR: | ||
104 | /* Decode Syscall # */ | ||
105 | regs->regs[REG_RET] = regs->syscall_nr; | ||
106 | regs->pc -= 4; | ||
107 | break; | ||
108 | |||
109 | case -ERESTART_RESTARTBLOCK: | ||
110 | regs->regs[REG_RET] = __NR_restart_syscall; | ||
111 | regs->pc -= 4; | ||
112 | break; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* No signal to deliver -- put the saved sigmask back */ | ||
117 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
118 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
119 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
120 | } | ||
121 | |||
122 | return 0; | ||
123 | } | ||
46 | 124 | ||
47 | /* | 125 | /* |
48 | * Atomically swap in the new signal mask, and wait for a signal. | 126 | * Atomically swap in the new signal mask, and wait for a signal. |
@@ -643,14 +721,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
643 | switch (regs->regs[REG_RET]) { | 721 | switch (regs->regs[REG_RET]) { |
644 | case -ERESTART_RESTARTBLOCK: | 722 | case -ERESTART_RESTARTBLOCK: |
645 | case -ERESTARTNOHAND: | 723 | case -ERESTARTNOHAND: |
724 | no_system_call_restart: | ||
646 | regs->regs[REG_RET] = -EINTR; | 725 | regs->regs[REG_RET] = -EINTR; |
647 | break; | 726 | break; |
648 | 727 | ||
649 | case -ERESTARTSYS: | 728 | case -ERESTARTSYS: |
650 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 729 | if (!(ka->sa.sa_flags & SA_RESTART)) |
651 | regs->regs[REG_RET] = -EINTR; | 730 | goto no_system_call_restart; |
652 | break; | ||
653 | } | ||
654 | /* fallthrough */ | 731 | /* fallthrough */ |
655 | case -ERESTARTNOINTR: | 732 | case -ERESTARTNOINTR: |
656 | /* Decode syscall # */ | 733 | /* Decode syscall # */ |
@@ -673,80 +750,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
673 | spin_unlock_irq(¤t->sighand->siglock); | 750 | spin_unlock_irq(¤t->sighand->siglock); |
674 | } | 751 | } |
675 | 752 | ||
676 | /* | 753 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) |
677 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
678 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
679 | * mistake. | ||
680 | * | ||
681 | * Note that we go through the signals twice: once to check the signals that | ||
682 | * the kernel can handle, and then we build all the user-level signal handling | ||
683 | * stack-frames in one go after that. | ||
684 | */ | ||
685 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | ||
686 | { | 754 | { |
687 | siginfo_t info; | 755 | if (thread_info_flags & _TIF_SIGPENDING) |
688 | int signr; | 756 | do_signal(regs, 0); |
689 | struct k_sigaction ka; | ||
690 | |||
691 | /* | ||
692 | * We want the common case to go fast, which | ||
693 | * is why we may in certain cases get here from | ||
694 | * kernel mode. Just return without doing anything | ||
695 | * if so. | ||
696 | */ | ||
697 | if (!user_mode(regs)) | ||
698 | return 1; | ||
699 | |||
700 | if (try_to_freeze()) | ||
701 | goto no_signal; | ||
702 | |||
703 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
704 | oldset = ¤t->saved_sigmask; | ||
705 | else if (!oldset) | ||
706 | oldset = ¤t->blocked; | ||
707 | |||
708 | signr = get_signal_to_deliver(&info, &ka, regs, 0); | ||
709 | |||
710 | if (signr > 0) { | ||
711 | /* Whee! Actually deliver the signal. */ | ||
712 | handle_signal(signr, &info, &ka, oldset, regs); | ||
713 | 757 | ||
714 | /* | 758 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
715 | * If a signal was successfully delivered, the saved sigmask | 759 | clear_thread_flag(TIF_NOTIFY_RESUME); |
716 | * is in its frame, and we can clear the TIF_RESTORE_SIGMASK | 760 | tracehook_notify_resume(regs); |
717 | * flag. | ||
718 | */ | ||
719 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
720 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
721 | |||
722 | return 1; | ||
723 | } | 761 | } |
724 | |||
725 | no_signal: | ||
726 | /* Did we come from a system call? */ | ||
727 | if (regs->syscall_nr >= 0) { | ||
728 | /* Restart the system call - no handlers present */ | ||
729 | switch (regs->regs[REG_RET]) { | ||
730 | case -ERESTARTNOHAND: | ||
731 | case -ERESTARTSYS: | ||
732 | case -ERESTARTNOINTR: | ||
733 | /* Decode Syscall # */ | ||
734 | regs->regs[REG_RET] = regs->syscall_nr; | ||
735 | regs->pc -= 4; | ||
736 | break; | ||
737 | |||
738 | case -ERESTART_RESTARTBLOCK: | ||
739 | regs->regs[REG_RET] = __NR_restart_syscall; | ||
740 | regs->pc -= 4; | ||
741 | break; | ||
742 | } | ||
743 | } | ||
744 | |||
745 | /* No signal to deliver -- put the saved sigmask back */ | ||
746 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
747 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
748 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
749 | } | ||
750 | |||
751 | return 0; | ||
752 | } | 762 | } |