aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-06-04 03:22:48 -0400
committerPaul Mackerras <paulus@samba.org>2007-06-14 08:29:58 -0400
commita3f61dc0a5335334958ec3b97d0b1946b4ae5375 (patch)
treee7b151d724dca73220d8346c2a0c2a3525c5c91c /arch/powerpc/kernel
parent5f9f375a62d3fd3d7f0d5adc23039ade523e62ba (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.c39
-rw-r--r--arch/powerpc/kernel/signal.h6
-rw-r--r--arch/powerpc/kernel/signal_32.c52
-rw-r--r--arch/powerpc/kernel/signal_64.c24
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 */
35void __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
15extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
16 size_t frame_size);
15extern void restore_sigmask(sigset_t *set); 17extern void restore_sigmask(sigset_t *set);
16 18
17extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, 19extern 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
21extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, 23extern 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
25extern int handle_rt_signal64(int signr, struct k_sigaction *ka, 27extern 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 */
292struct sigregs { 294struct 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 */
699int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, 702int 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 */
990int handle_signal32(unsigned long sig, struct k_sigaction *ka, 992int 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 */
201static 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 */
220static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) 201static 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. */