diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-06-04 03:22:48 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-06-14 08:29:58 -0400 |
commit | a3f61dc0a5335334958ec3b97d0b1946b4ae5375 (patch) | |
tree | e7b151d724dca73220d8346c2a0c2a3525c5c91c /arch/powerpc/kernel | |
parent | 5f9f375a62d3fd3d7f0d5adc23039ade523e62ba (diff) |
[POWERPC] Merge creation of signal frame
The code for creating signal frames was still duplicated and split
in strange ways between 32 and 64 bits, including the SA_ONSTACK
handling being in do_signal on 32 bits but inside handle_rt_signal
on 64 bits etc...
This moves the 64 bits get_sigframe() to the generic signal.c,
cleans it a bit, moves the access_ok() call done by all callers to
it as well, and adapts/cleanups the 3 different signal handling cases
to use that common function.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/signal.c | 39 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.h | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 52 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 24 |
4 files changed, 59 insertions, 62 deletions
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index a9c148a09361..dee275014e00 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/ptrace.h> | 12 | #include <linux/ptrace.h> |
13 | #include <linux/signal.h> | 13 | #include <linux/signal.h> |
14 | #include <asm/uaccess.h> | ||
14 | #include <asm/unistd.h> | 15 | #include <asm/unistd.h> |
15 | 16 | ||
16 | #include "signal.h" | 17 | #include "signal.h" |
@@ -28,6 +29,32 @@ static inline int is_32bit_task(void) | |||
28 | } | 29 | } |
29 | #endif | 30 | #endif |
30 | 31 | ||
32 | /* | ||
33 | * Allocate space for the signal frame | ||
34 | */ | ||
35 | void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
36 | size_t frame_size) | ||
37 | { | ||
38 | unsigned long oldsp, newsp; | ||
39 | |||
40 | /* Default to using normal stack */ | ||
41 | oldsp = regs->gpr[1]; | ||
42 | |||
43 | /* Check for alt stack */ | ||
44 | if ((ka->sa.sa_flags & SA_ONSTACK) && | ||
45 | current->sas_ss_size && !on_sig_stack(oldsp)) | ||
46 | oldsp = (current->sas_ss_sp + current->sas_ss_size); | ||
47 | |||
48 | /* Get aligned frame */ | ||
49 | newsp = (oldsp - frame_size) & ~0xFUL; | ||
50 | |||
51 | /* Check access */ | ||
52 | if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp)) | ||
53 | return NULL; | ||
54 | |||
55 | return (void __user *)newsp; | ||
56 | } | ||
57 | |||
31 | 58 | ||
32 | /* | 59 | /* |
33 | * Restore the user process's signal mask | 60 | * Restore the user process's signal mask |
@@ -130,20 +157,12 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
130 | #endif | 157 | #endif |
131 | 158 | ||
132 | if (is32) { | 159 | if (is32) { |
133 | unsigned int newsp; | ||
134 | |||
135 | if ((ka.sa.sa_flags & SA_ONSTACK) && | ||
136 | current->sas_ss_size && !on_sig_stack(regs->gpr[1])) | ||
137 | newsp = current->sas_ss_sp + current->sas_ss_size; | ||
138 | else | ||
139 | newsp = regs->gpr[1]; | ||
140 | |||
141 | if (ka.sa.sa_flags & SA_SIGINFO) | 160 | if (ka.sa.sa_flags & SA_SIGINFO) |
142 | ret = handle_rt_signal32(signr, &ka, &info, oldset, | 161 | ret = handle_rt_signal32(signr, &ka, &info, oldset, |
143 | regs, newsp); | 162 | regs); |
144 | else | 163 | else |
145 | ret = handle_signal32(signr, &ka, &info, oldset, | 164 | ret = handle_signal32(signr, &ka, &info, oldset, |
146 | regs, newsp); | 165 | regs); |
147 | #ifdef CONFIG_PPC64 | 166 | #ifdef CONFIG_PPC64 |
148 | } else { | 167 | } else { |
149 | ret = handle_rt_signal64(signr, &ka, &info, oldset, regs); | 168 | ret = handle_rt_signal64(signr, &ka, &info, oldset, regs); |
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h index 190d4325f974..c284f75afe77 100644 --- a/arch/powerpc/kernel/signal.h +++ b/arch/powerpc/kernel/signal.h | |||
@@ -12,15 +12,17 @@ | |||
12 | 12 | ||
13 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 13 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
14 | 14 | ||
15 | extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
16 | size_t frame_size); | ||
15 | extern void restore_sigmask(sigset_t *set); | 17 | extern void restore_sigmask(sigset_t *set); |
16 | 18 | ||
17 | extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, | 19 | extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, |
18 | siginfo_t *info, sigset_t *oldset, | 20 | siginfo_t *info, sigset_t *oldset, |
19 | struct pt_regs *regs, unsigned long newsp); | 21 | struct pt_regs *regs); |
20 | 22 | ||
21 | extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, | 23 | extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, |
22 | siginfo_t *info, sigset_t *oldset, | 24 | siginfo_t *info, sigset_t *oldset, |
23 | struct pt_regs *regs, unsigned long newsp); | 25 | struct pt_regs *regs); |
24 | 26 | ||
25 | extern int handle_rt_signal64(int signr, struct k_sigaction *ka, | 27 | extern int handle_rt_signal64(int signr, struct k_sigaction *ka, |
26 | siginfo_t *info, sigset_t *set, | 28 | siginfo_t *info, sigset_t *set, |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 32481e71d71e..590057e9e987 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -282,14 +282,17 @@ long sys_sigaction(int sig, struct old_sigaction __user *act, | |||
282 | /* | 282 | /* |
283 | * When we have signals to deliver, we set up on the | 283 | * When we have signals to deliver, we set up on the |
284 | * user stack, going down from the original stack pointer: | 284 | * user stack, going down from the original stack pointer: |
285 | * a sigregs struct | 285 | * an ABI gap of 56 words |
286 | * an mcontext struct | ||
286 | * a sigcontext struct | 287 | * a sigcontext struct |
287 | * a gap of __SIGNAL_FRAMESIZE bytes | 288 | * a gap of __SIGNAL_FRAMESIZE bytes |
288 | * | 289 | * |
289 | * 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 | ||
290 | * | 292 | * |
291 | */ | 293 | */ |
292 | struct sigregs { | 294 | struct sigframe { |
295 | struct sigcontext sctx; /* the sigcontext */ | ||
293 | struct mcontext mctx; /* all the register values */ | 296 | struct mcontext mctx; /* all the register values */ |
294 | /* | 297 | /* |
295 | * 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 |
@@ -698,21 +701,16 @@ int compat_sys_sigaltstack(u32 __new, u32 __old, int r5, | |||
698 | */ | 701 | */ |
699 | int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, | 702 | int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, |
700 | siginfo_t *info, sigset_t *oldset, | 703 | siginfo_t *info, sigset_t *oldset, |
701 | struct pt_regs *regs, unsigned long newsp) | 704 | struct pt_regs *regs) |
702 | { | 705 | { |
703 | struct rt_sigframe __user *rt_sf; | 706 | struct rt_sigframe __user *rt_sf; |
704 | struct mcontext __user *frame; | 707 | struct mcontext __user *frame; |
705 | unsigned long origsp = newsp; | 708 | unsigned long newsp = 0; |
706 | 709 | ||
707 | /* Set up Signal Frame */ | 710 | /* Set up Signal Frame */ |
708 | /* Put a Real Time Context onto stack */ | 711 | /* Put a Real Time Context onto stack */ |
709 | newsp -= sizeof(*rt_sf); | 712 | rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf)); |
710 | rt_sf = (struct rt_sigframe __user *)newsp; | 713 | if (unlikely(rt_sf == NULL)) |
711 | |||
712 | /* create a stack frame for the caller of the handler */ | ||
713 | newsp -= __SIGNAL_FRAMESIZE + 16; | ||
714 | |||
715 | if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp)) | ||
716 | goto badframe; | 714 | goto badframe; |
717 | 715 | ||
718 | /* Put the siginfo & fill in most of the ucontext */ | 716 | /* Put the siginfo & fill in most of the ucontext */ |
@@ -742,8 +740,12 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, | |||
742 | 740 | ||
743 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ | 741 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ |
744 | 742 | ||
743 | /* create a stack frame for the caller of the handler */ | ||
744 | newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16); | ||
745 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) | 745 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) |
746 | goto badframe; | 746 | goto badframe; |
747 | |||
748 | /* Fill registers for signal handler */ | ||
747 | regs->gpr[1] = newsp; | 749 | regs->gpr[1] = newsp; |
748 | regs->gpr[3] = sig; | 750 | regs->gpr[3] = sig; |
749 | regs->gpr[4] = (unsigned long) &rt_sf->info; | 751 | regs->gpr[4] = (unsigned long) &rt_sf->info; |
@@ -988,26 +990,17 @@ int sys_debug_setcontext(struct ucontext __user *ctx, | |||
988 | * OK, we're invoking a handler | 990 | * OK, we're invoking a handler |
989 | */ | 991 | */ |
990 | int handle_signal32(unsigned long sig, struct k_sigaction *ka, | 992 | int handle_signal32(unsigned long sig, struct k_sigaction *ka, |
991 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, | 993 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) |
992 | unsigned long newsp) | ||
993 | { | 994 | { |
994 | struct sigcontext __user *sc; | 995 | struct sigcontext __user *sc; |
995 | struct sigregs __user *frame; | 996 | struct sigframe __user *frame; |
996 | unsigned long origsp = newsp; | 997 | unsigned long newsp = 0; |
997 | 998 | ||
998 | /* Set up Signal Frame */ | 999 | /* Set up Signal Frame */ |
999 | newsp -= sizeof(struct sigregs); | 1000 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
1000 | frame = (struct sigregs __user *) newsp; | 1001 | if (unlikely(frame == NULL)) |
1001 | |||
1002 | /* Put a sigcontext on the stack */ | ||
1003 | newsp -= sizeof(*sc); | ||
1004 | sc = (struct sigcontext __user *) newsp; | ||
1005 | |||
1006 | /* create a stack frame for the caller of the handler */ | ||
1007 | newsp -= __SIGNAL_FRAMESIZE; | ||
1008 | |||
1009 | if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp)) | ||
1010 | goto badframe; | 1002 | goto badframe; |
1003 | sc = (struct sigcontext __user *) &frame->sctx; | ||
1011 | 1004 | ||
1012 | #if _NSIG != 64 | 1005 | #if _NSIG != 64 |
1013 | #error "Please adjust handle_signal()" | 1006 | #error "Please adjust handle_signal()" |
@@ -1019,7 +1012,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, | |||
1019 | #else | 1012 | #else |
1020 | || __put_user(oldset->sig[1], &sc->_unused[3]) | 1013 | || __put_user(oldset->sig[1], &sc->_unused[3]) |
1021 | #endif | 1014 | #endif |
1022 | || __put_user(to_user_ptr(frame), &sc->regs) | 1015 | || __put_user(to_user_ptr(&frame->mctx), &sc->regs) |
1023 | || __put_user(sig, &sc->signal)) | 1016 | || __put_user(sig, &sc->signal)) |
1024 | goto badframe; | 1017 | goto badframe; |
1025 | 1018 | ||
@@ -1035,8 +1028,11 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, | |||
1035 | 1028 | ||
1036 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ | 1029 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ |
1037 | 1030 | ||
1031 | /* create a stack frame for the caller of the handler */ | ||
1032 | newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; | ||
1038 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) | 1033 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) |
1039 | goto badframe; | 1034 | goto badframe; |
1035 | |||
1040 | regs->gpr[1] = newsp; | 1036 | regs->gpr[1] = newsp; |
1041 | regs->gpr[3] = sig; | 1037 | regs->gpr[3] = sig; |
1042 | regs->gpr[4] = (unsigned long) sc; | 1038 | regs->gpr[4] = (unsigned long) sc; |
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index c17903cd384a..5004a979ebc0 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -196,25 +196,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, | |||
196 | } | 196 | } |
197 | 197 | ||
198 | /* | 198 | /* |
199 | * Allocate space for the signal frame | ||
200 | */ | ||
201 | static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
202 | size_t frame_size) | ||
203 | { | ||
204 | unsigned long newsp; | ||
205 | |||
206 | /* Default to using normal stack */ | ||
207 | newsp = regs->gpr[1]; | ||
208 | |||
209 | if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) { | ||
210 | if (! on_sig_stack(regs->gpr[1])) | ||
211 | newsp = (current->sas_ss_sp + current->sas_ss_size); | ||
212 | } | ||
213 | |||
214 | return (void __user *)((newsp - frame_size) & -16ul); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Setup the trampoline code on the stack | 199 | * Setup the trampoline code on the stack |
219 | */ | 200 | */ |
220 | static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) | 201 | static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) |
@@ -348,8 +329,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
348 | long err = 0; | 329 | long err = 0; |
349 | 330 | ||
350 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 331 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
351 | 332 | if (unlikely(frame == NULL)) | |
352 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
353 | goto badframe; | 333 | goto badframe; |
354 | 334 | ||
355 | err |= __put_user(&frame->info, &frame->pinfo); | 335 | err |= __put_user(&frame->info, &frame->pinfo); |
@@ -386,7 +366,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
386 | funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler; | 366 | funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler; |
387 | 367 | ||
388 | /* Allocate a dummy caller frame for the signal handler. */ | 368 | /* Allocate a dummy caller frame for the signal handler. */ |
389 | newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE; | 369 | newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; |
390 | err |= put_user(regs->gpr[1], (unsigned long __user *)newsp); | 370 | err |= put_user(regs->gpr[1], (unsigned long __user *)newsp); |
391 | 371 | ||
392 | /* Set up "regs" so we "return" to the signal handler. */ | 372 | /* Set up "regs" so we "return" to the signal handler. */ |