Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a3f61dc0a5335334958ec3b97d0b1946b4ae5375
Commit:     a3f61dc0a5335334958ec3b97d0b1946b4ae5375
Parent:     5f9f375a62d3fd3d7f0d5adc23039ade523e62ba
Author:     Benjamin Herrenschmidt <[EMAIL PROTECTED]>
AuthorDate: Mon Jun 4 17:22:48 2007 +1000
Committer:  Paul Mackerras <[EMAIL PROTECTED]>
CommitDate: Thu Jun 14 22:29:58 2007 +1000

    [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 <[EMAIL PROTECTED]>
    Signed-off-by: Paul Mackerras <[EMAIL PROTECTED]>
---
 arch/powerpc/kernel/signal.c    |   39 +++++++++++++++++++++-------
 arch/powerpc/kernel/signal.h    |    6 +++-
 arch/powerpc/kernel/signal_32.c |   52 ++++++++++++++++++---------------------
 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 a9c148a..dee2750 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -11,6 +11,7 @@
 
 #include <linux/ptrace.h>
 #include <linux/signal.h>
+#include <asm/uaccess.h>
 #include <asm/unistd.h>
 
 #include "signal.h"
@@ -28,6 +29,32 @@ static inline int is_32bit_task(void)
 }
 #endif
 
+/*
+ * Allocate space for the signal frame
+ */
+void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+                          size_t frame_size)
+{
+        unsigned long oldsp, newsp;
+
+        /* Default to using normal stack */
+        oldsp = regs->gpr[1];
+
+       /* Check for alt stack */
+       if ((ka->sa.sa_flags & SA_ONSTACK) &&
+           current->sas_ss_size && !on_sig_stack(oldsp))
+               oldsp = (current->sas_ss_sp + current->sas_ss_size);
+
+       /* Get aligned frame */
+       newsp = (oldsp - frame_size) & ~0xFUL;
+
+       /* Check access */
+       if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp))
+               return NULL;
+
+        return (void __user *)newsp;
+}
+
 
 /*
  * Restore the user process's signal mask
@@ -130,20 +157,12 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
 #endif
 
        if (is32) {
-               unsigned int newsp;
-
-               if ((ka.sa.sa_flags & SA_ONSTACK) &&
-                   current->sas_ss_size && !on_sig_stack(regs->gpr[1]))
-                       newsp = current->sas_ss_sp + current->sas_ss_size;
-               else
-                       newsp = regs->gpr[1];
-
                if (ka.sa.sa_flags & SA_SIGINFO)
                        ret = handle_rt_signal32(signr, &ka, &info, oldset,
-                                       regs, newsp);
+                                       regs);
                else
                        ret = handle_signal32(signr, &ka, &info, oldset,
-                                       regs, newsp);
+                                       regs);
 #ifdef CONFIG_PPC64
        } else {
                ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h
index 190d432..c284f75 100644
--- a/arch/powerpc/kernel/signal.h
+++ b/arch/powerpc/kernel/signal.h
@@ -12,15 +12,17 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
+extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+                                 size_t frame_size);
 extern void restore_sigmask(sigset_t *set);
 
 extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
                           siginfo_t *info, sigset_t *oldset,
-                          struct pt_regs *regs, unsigned long newsp);
+                          struct pt_regs *regs);
 
 extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
                              siginfo_t *info, sigset_t *oldset,
-                             struct pt_regs *regs, unsigned long newsp);
+                             struct pt_regs *regs);
 
 extern int handle_rt_signal64(int signr, struct k_sigaction *ka,
                              siginfo_t *info, sigset_t *set,
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 32481e7..590057e 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,
 /*
  * When we have signals to deliver, we set up on the
  * user stack, going down from the original stack pointer:
- *     a sigregs struct
+ *     an ABI gap of 56 words
+ *     an mcontext struct
  *     a sigcontext struct
  *     a gap of __SIGNAL_FRAMESIZE bytes
  *
- * Each of these things must be a multiple of 16 bytes in size.
+ * Each of these things must be a multiple of 16 bytes in size. The following
+ * structure represent all of this except the __SIGNAL_FRAMESIZE gap
  *
  */
-struct sigregs {
+struct sigframe {
+       struct sigcontext sctx;         /* the sigcontext */
        struct mcontext mctx;           /* all the register values */
        /*
         * 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,
  */
 int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
                siginfo_t *info, sigset_t *oldset,
-               struct pt_regs *regs, unsigned long newsp)
+               struct pt_regs *regs)
 {
        struct rt_sigframe __user *rt_sf;
        struct mcontext __user *frame;
-       unsigned long origsp = newsp;
+       unsigned long newsp = 0;
 
        /* Set up Signal Frame */
        /* Put a Real Time Context onto stack */
-       newsp -= sizeof(*rt_sf);
-       rt_sf = (struct rt_sigframe __user *)newsp;
-
-       /* create a stack frame for the caller of the handler */
-       newsp -= __SIGNAL_FRAMESIZE + 16;
-
-       if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp))
+       rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
+       if (unlikely(rt_sf == NULL))
                goto badframe;
 
        /* Put the siginfo & fill in most of the ucontext */
@@ -742,8 +740,12 @@ int handle_rt_signal32(unsigned long sig, struct 
k_sigaction *ka,
 
        current->thread.fpscr.val = 0;  /* turn off all fp exceptions */
 
+       /* create a stack frame for the caller of the handler */
+       newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16);
        if (put_user(regs->gpr[1], (u32 __user *)newsp))
                goto badframe;
+
+       /* Fill registers for signal handler */
        regs->gpr[1] = newsp;
        regs->gpr[3] = sig;
        regs->gpr[4] = (unsigned long) &rt_sf->info;
@@ -988,26 +990,17 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
  * OK, we're invoking a handler
  */
 int handle_signal32(unsigned long sig, struct k_sigaction *ka,
-               siginfo_t *info, sigset_t *oldset, struct pt_regs *regs,
-               unsigned long newsp)
+                   siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
        struct sigcontext __user *sc;
-       struct sigregs __user *frame;
-       unsigned long origsp = newsp;
+       struct sigframe __user *frame;
+       unsigned long newsp = 0;
 
        /* Set up Signal Frame */
-       newsp -= sizeof(struct sigregs);
-       frame = (struct sigregs __user *) newsp;
-
-       /* Put a sigcontext on the stack */
-       newsp -= sizeof(*sc);
-       sc = (struct sigcontext __user *) newsp;
-
-       /* create a stack frame for the caller of the handler */
-       newsp -= __SIGNAL_FRAMESIZE;
-
-       if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
+       frame = get_sigframe(ka, regs, sizeof(*frame));
+       if (unlikely(frame == NULL))
                goto badframe;
+       sc = (struct sigcontext __user *) &frame->sctx;
 
 #if _NSIG != 64
 #error "Please adjust handle_signal()"
@@ -1019,7 +1012,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction 
*ka,
 #else
            || __put_user(oldset->sig[1], &sc->_unused[3])
 #endif
-           || __put_user(to_user_ptr(frame), &sc->regs)
+           || __put_user(to_user_ptr(&frame->mctx), &sc->regs)
            || __put_user(sig, &sc->signal))
                goto badframe;
 
@@ -1035,8 +1028,11 @@ int handle_signal32(unsigned long sig, struct 
k_sigaction *ka,
 
        current->thread.fpscr.val = 0;  /* turn off all fp exceptions */
 
+       /* create a stack frame for the caller of the handler */
+       newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
        if (put_user(regs->gpr[1], (u32 __user *)newsp))
                goto badframe;
+
        regs->gpr[1] = newsp;
        regs->gpr[3] = sig;
        regs->gpr[4] = (unsigned long) sc;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index c17903c..5004a97 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,
 }
 
 /*
- * Allocate space for the signal frame
- */
-static inline void __user * get_sigframe(struct k_sigaction *ka, struct 
pt_regs *regs,
-                                 size_t frame_size)
-{
-        unsigned long newsp;
-
-        /* Default to using normal stack */
-        newsp = regs->gpr[1];
-
-       if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) {
-               if (! on_sig_stack(regs->gpr[1]))
-                       newsp = (current->sas_ss_sp + current->sas_ss_size);
-       }
-
-        return (void __user *)((newsp - frame_size) & -16ul);
-}
-
-/*
  * Setup the trampoline code on the stack
  */
 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,
        long err = 0;
 
        frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+       if (unlikely(frame == NULL))
                goto badframe;
 
        err |= __put_user(&frame->info, &frame->pinfo);
@@ -386,7 +366,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, 
siginfo_t *info,
        funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler;
 
        /* Allocate a dummy caller frame for the signal handler. */
-       newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+       newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
        err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);
 
        /* Set up "regs" so we "return" to the signal handler. */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to