diff options
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 191 |
1 files changed, 28 insertions, 163 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index dd1dca5bfa81..590057e9e987 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -51,12 +51,11 @@ | |||
51 | #include <asm/pgtable.h> | 51 | #include <asm/pgtable.h> |
52 | #endif | 52 | #endif |
53 | 53 | ||
54 | #undef DEBUG_SIG | 54 | #include "signal.h" |
55 | 55 | ||
56 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 56 | #undef DEBUG_SIG |
57 | 57 | ||
58 | #ifdef CONFIG_PPC64 | 58 | #ifdef CONFIG_PPC64 |
59 | #define do_signal do_signal32 | ||
60 | #define sys_sigsuspend compat_sys_sigsuspend | 59 | #define sys_sigsuspend compat_sys_sigsuspend |
61 | #define sys_rt_sigsuspend compat_sys_rt_sigsuspend | 60 | #define sys_rt_sigsuspend compat_sys_rt_sigsuspend |
62 | #define sys_rt_sigreturn compat_sys_rt_sigreturn | 61 | #define sys_rt_sigreturn compat_sys_rt_sigreturn |
@@ -231,8 +230,6 @@ static inline int restore_general_regs(struct pt_regs *regs, | |||
231 | 230 | ||
232 | #endif /* CONFIG_PPC64 */ | 231 | #endif /* CONFIG_PPC64 */ |
233 | 232 | ||
234 | int do_signal(sigset_t *oldset, struct pt_regs *regs); | ||
235 | |||
236 | /* | 233 | /* |
237 | * Atomically swap in the new signal mask, and wait for a signal. | 234 | * Atomically swap in the new signal mask, and wait for a signal. |
238 | */ | 235 | */ |
@@ -251,14 +248,6 @@ long sys_sigsuspend(old_sigset_t mask) | |||
251 | return -ERESTARTNOHAND; | 248 | return -ERESTARTNOHAND; |
252 | } | 249 | } |
253 | 250 | ||
254 | #ifdef CONFIG_PPC32 | ||
255 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, int r5, | ||
256 | int r6, int r7, int r8, struct pt_regs *regs) | ||
257 | { | ||
258 | return do_sigaltstack(uss, uoss, regs->gpr[1]); | ||
259 | } | ||
260 | #endif | ||
261 | |||
262 | long sys_sigaction(int sig, struct old_sigaction __user *act, | 251 | long sys_sigaction(int sig, struct old_sigaction __user *act, |
263 | struct old_sigaction __user *oact) | 252 | struct old_sigaction __user *oact) |
264 | { | 253 | { |
@@ -293,14 +282,17 @@ long sys_sigaction(int sig, struct old_sigaction __user *act, | |||
293 | /* | 282 | /* |
294 | * When we have signals to deliver, we set up on the | 283 | * When we have signals to deliver, we set up on the |
295 | * user stack, going down from the original stack pointer: | 284 | * user stack, going down from the original stack pointer: |
296 | * a sigregs struct | 285 | * an ABI gap of 56 words |
286 | * an mcontext struct | ||
297 | * a sigcontext struct | 287 | * a sigcontext struct |
298 | * a gap of __SIGNAL_FRAMESIZE bytes | 288 | * a gap of __SIGNAL_FRAMESIZE bytes |
299 | * | 289 | * |
300 | * Each of these things must be a multiple of 16 bytes in size. | 290 | * Each of these things must be a multiple of 16 bytes in size. The following |
291 | * structure represent all of this except the __SIGNAL_FRAMESIZE gap | ||
301 | * | 292 | * |
302 | */ | 293 | */ |
303 | struct sigregs { | 294 | struct sigframe { |
295 | struct sigcontext sctx; /* the sigcontext */ | ||
304 | struct mcontext mctx; /* all the register values */ | 296 | struct mcontext mctx; /* all the register values */ |
305 | /* | 297 | /* |
306 | * Programs using the rs6000/xcoff abi can save up to 19 gp | 298 | * Programs using the rs6000/xcoff abi can save up to 19 gp |
@@ -703,44 +695,22 @@ int compat_sys_sigaltstack(u32 __new, u32 __old, int r5, | |||
703 | } | 695 | } |
704 | #endif /* CONFIG_PPC64 */ | 696 | #endif /* CONFIG_PPC64 */ |
705 | 697 | ||
706 | |||
707 | /* | ||
708 | * Restore the user process's signal mask | ||
709 | */ | ||
710 | #ifdef CONFIG_PPC64 | ||
711 | extern void restore_sigmask(sigset_t *set); | ||
712 | #else /* CONFIG_PPC64 */ | ||
713 | static void restore_sigmask(sigset_t *set) | ||
714 | { | ||
715 | sigdelsetmask(set, ~_BLOCKABLE); | ||
716 | spin_lock_irq(¤t->sighand->siglock); | ||
717 | current->blocked = *set; | ||
718 | recalc_sigpending(); | ||
719 | spin_unlock_irq(¤t->sighand->siglock); | ||
720 | } | ||
721 | #endif | ||
722 | |||
723 | /* | 698 | /* |
724 | * Set up a signal frame for a "real-time" signal handler | 699 | * Set up a signal frame for a "real-time" signal handler |
725 | * (one which gets siginfo). | 700 | * (one which gets siginfo). |
726 | */ | 701 | */ |
727 | static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, | 702 | int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, |
728 | siginfo_t *info, sigset_t *oldset, | 703 | siginfo_t *info, sigset_t *oldset, |
729 | struct pt_regs *regs, unsigned long newsp) | 704 | struct pt_regs *regs) |
730 | { | 705 | { |
731 | struct rt_sigframe __user *rt_sf; | 706 | struct rt_sigframe __user *rt_sf; |
732 | struct mcontext __user *frame; | 707 | struct mcontext __user *frame; |
733 | unsigned long origsp = newsp; | 708 | unsigned long newsp = 0; |
734 | 709 | ||
735 | /* Set up Signal Frame */ | 710 | /* Set up Signal Frame */ |
736 | /* Put a Real Time Context onto stack */ | 711 | /* Put a Real Time Context onto stack */ |
737 | newsp -= sizeof(*rt_sf); | 712 | rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf)); |
738 | rt_sf = (struct rt_sigframe __user *)newsp; | 713 | if (unlikely(rt_sf == NULL)) |
739 | |||
740 | /* create a stack frame for the caller of the handler */ | ||
741 | newsp -= __SIGNAL_FRAMESIZE + 16; | ||
742 | |||
743 | if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp)) | ||
744 | goto badframe; | 714 | goto badframe; |
745 | 715 | ||
746 | /* Put the siginfo & fill in most of the ucontext */ | 716 | /* Put the siginfo & fill in most of the ucontext */ |
@@ -770,8 +740,12 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, | |||
770 | 740 | ||
771 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ | 741 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ |
772 | 742 | ||
743 | /* create a stack frame for the caller of the handler */ | ||
744 | newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16); | ||
773 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) | 745 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) |
774 | goto badframe; | 746 | goto badframe; |
747 | |||
748 | /* Fill registers for signal handler */ | ||
775 | regs->gpr[1] = newsp; | 749 | regs->gpr[1] = newsp; |
776 | regs->gpr[3] = sig; | 750 | regs->gpr[3] = sig; |
777 | regs->gpr[4] = (unsigned long) &rt_sf->info; | 751 | regs->gpr[4] = (unsigned long) &rt_sf->info; |
@@ -1015,27 +989,18 @@ int sys_debug_setcontext(struct ucontext __user *ctx, | |||
1015 | /* | 989 | /* |
1016 | * OK, we're invoking a handler | 990 | * OK, we're invoking a handler |
1017 | */ | 991 | */ |
1018 | static int handle_signal(unsigned long sig, struct k_sigaction *ka, | 992 | int handle_signal32(unsigned long sig, struct k_sigaction *ka, |
1019 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, | 993 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) |
1020 | unsigned long newsp) | ||
1021 | { | 994 | { |
1022 | struct sigcontext __user *sc; | 995 | struct sigcontext __user *sc; |
1023 | struct sigregs __user *frame; | 996 | struct sigframe __user *frame; |
1024 | unsigned long origsp = newsp; | 997 | unsigned long newsp = 0; |
1025 | 998 | ||
1026 | /* Set up Signal Frame */ | 999 | /* Set up Signal Frame */ |
1027 | newsp -= sizeof(struct sigregs); | 1000 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
1028 | frame = (struct sigregs __user *) newsp; | 1001 | if (unlikely(frame == NULL)) |
1029 | |||
1030 | /* Put a sigcontext on the stack */ | ||
1031 | newsp -= sizeof(*sc); | ||
1032 | sc = (struct sigcontext __user *) newsp; | ||
1033 | |||
1034 | /* create a stack frame for the caller of the handler */ | ||
1035 | newsp -= __SIGNAL_FRAMESIZE; | ||
1036 | |||
1037 | if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp)) | ||
1038 | goto badframe; | 1002 | goto badframe; |
1003 | sc = (struct sigcontext __user *) &frame->sctx; | ||
1039 | 1004 | ||
1040 | #if _NSIG != 64 | 1005 | #if _NSIG != 64 |
1041 | #error "Please adjust handle_signal()" | 1006 | #error "Please adjust handle_signal()" |
@@ -1047,7 +1012,7 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
1047 | #else | 1012 | #else |
1048 | || __put_user(oldset->sig[1], &sc->_unused[3]) | 1013 | || __put_user(oldset->sig[1], &sc->_unused[3]) |
1049 | #endif | 1014 | #endif |
1050 | || __put_user(to_user_ptr(frame), &sc->regs) | 1015 | || __put_user(to_user_ptr(&frame->mctx), &sc->regs) |
1051 | || __put_user(sig, &sc->signal)) | 1016 | || __put_user(sig, &sc->signal)) |
1052 | goto badframe; | 1017 | goto badframe; |
1053 | 1018 | ||
@@ -1063,8 +1028,11 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
1063 | 1028 | ||
1064 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ | 1029 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ |
1065 | 1030 | ||
1031 | /* create a stack frame for the caller of the handler */ | ||
1032 | newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; | ||
1066 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) | 1033 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) |
1067 | goto badframe; | 1034 | goto badframe; |
1035 | |||
1068 | regs->gpr[1] = newsp; | 1036 | regs->gpr[1] = newsp; |
1069 | regs->gpr[3] = sig; | 1037 | regs->gpr[3] = sig; |
1070 | regs->gpr[4] = (unsigned long) sc; | 1038 | regs->gpr[4] = (unsigned long) sc; |
@@ -1126,106 +1094,3 @@ badframe: | |||
1126 | force_sig(SIGSEGV, current); | 1094 | force_sig(SIGSEGV, current); |
1127 | return 0; | 1095 | return 0; |
1128 | } | 1096 | } |
1129 | |||
1130 | /* | ||
1131 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
1132 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
1133 | * mistake. | ||
1134 | */ | ||
1135 | int do_signal(sigset_t *oldset, struct pt_regs *regs) | ||
1136 | { | ||
1137 | siginfo_t info; | ||
1138 | struct k_sigaction ka; | ||
1139 | unsigned int newsp; | ||
1140 | int signr, ret; | ||
1141 | |||
1142 | #ifdef CONFIG_PPC32 | ||
1143 | if (try_to_freeze()) { | ||
1144 | signr = 0; | ||
1145 | if (!signal_pending(current)) | ||
1146 | goto no_signal; | ||
1147 | } | ||
1148 | #endif | ||
1149 | |||
1150 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
1151 | oldset = ¤t->saved_sigmask; | ||
1152 | else if (!oldset) | ||
1153 | oldset = ¤t->blocked; | ||
1154 | |||
1155 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
1156 | #ifdef CONFIG_PPC32 | ||
1157 | no_signal: | ||
1158 | #endif | ||
1159 | if (TRAP(regs) == 0x0C00 /* System Call! */ | ||
1160 | && regs->ccr & 0x10000000 /* error signalled */ | ||
1161 | && ((ret = regs->gpr[3]) == ERESTARTSYS | ||
1162 | || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR | ||
1163 | || ret == ERESTART_RESTARTBLOCK)) { | ||
1164 | |||
1165 | if (signr > 0 | ||
1166 | && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK | ||
1167 | || (ret == ERESTARTSYS | ||
1168 | && !(ka.sa.sa_flags & SA_RESTART)))) { | ||
1169 | /* make the system call return an EINTR error */ | ||
1170 | regs->result = -EINTR; | ||
1171 | regs->gpr[3] = EINTR; | ||
1172 | /* note that the cr0.SO bit is already set */ | ||
1173 | } else { | ||
1174 | regs->nip -= 4; /* Back up & retry system call */ | ||
1175 | regs->result = 0; | ||
1176 | regs->trap = 0; | ||
1177 | if (ret == ERESTART_RESTARTBLOCK) | ||
1178 | regs->gpr[0] = __NR_restart_syscall; | ||
1179 | else | ||
1180 | regs->gpr[3] = regs->orig_gpr3; | ||
1181 | } | ||
1182 | } | ||
1183 | |||
1184 | if (signr == 0) { | ||
1185 | /* No signal to deliver -- put the saved sigmask back */ | ||
1186 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
1187 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
1188 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
1189 | } | ||
1190 | return 0; /* no signals delivered */ | ||
1191 | } | ||
1192 | |||
1193 | if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size | ||
1194 | && !on_sig_stack(regs->gpr[1])) | ||
1195 | newsp = current->sas_ss_sp + current->sas_ss_size; | ||
1196 | else | ||
1197 | newsp = regs->gpr[1]; | ||
1198 | newsp &= ~0xfUL; | ||
1199 | |||
1200 | #ifdef CONFIG_PPC64 | ||
1201 | /* | ||
1202 | * Reenable the DABR before delivering the signal to | ||
1203 | * user space. The DABR will have been cleared if it | ||
1204 | * triggered inside the kernel. | ||
1205 | */ | ||
1206 | if (current->thread.dabr) | ||
1207 | set_dabr(current->thread.dabr); | ||
1208 | #endif | ||
1209 | |||
1210 | /* Whee! Actually deliver the signal. */ | ||
1211 | if (ka.sa.sa_flags & SA_SIGINFO) | ||
1212 | ret = handle_rt_signal(signr, &ka, &info, oldset, regs, newsp); | ||
1213 | else | ||
1214 | ret = handle_signal(signr, &ka, &info, oldset, regs, newsp); | ||
1215 | |||
1216 | if (ret) { | ||
1217 | spin_lock_irq(¤t->sighand->siglock); | ||
1218 | sigorsets(¤t->blocked, ¤t->blocked, | ||
1219 | &ka.sa.sa_mask); | ||
1220 | if (!(ka.sa.sa_flags & SA_NODEFER)) | ||
1221 | sigaddset(¤t->blocked, signr); | ||
1222 | recalc_sigpending(); | ||
1223 | spin_unlock_irq(¤t->sighand->siglock); | ||
1224 | /* A signal was successfully delivered; the saved sigmask is in | ||
1225 | its frame, and we can clear the TIF_RESTORE_SIGMASK flag */ | ||
1226 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
1227 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
1228 | } | ||
1229 | |||
1230 | return ret; | ||
1231 | } | ||