Include the new stack frame inside the user access block and set it up
using unsafe_put_user().

On an mpc 8321 (book3s/32) the improvment is about 4% on a process
sending a signal to itself.

Signed-off-by: Christophe Leroy (CS GROUP) <[email protected]>
---
 arch/powerpc/kernel/signal_32.c | 28 ++++++++++++----------------
 arch/powerpc/kernel/signal_64.c | 13 ++++++-------
 2 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index f5d5139a1426..6b1fbd95b07d 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -730,7 +730,7 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t 
*oldset,
                       struct task_struct *tsk)
 {
        struct rt_sigframe __user *frame;
-       unsigned long newsp = 0;
+       unsigned long __user *newsp;
        unsigned long tramp;
        struct pt_regs *regs = tsk->thread.regs;
        /* Save the thread's msr before get_tm_stackpointer() changes it */
@@ -738,12 +738,13 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t 
*oldset,
 
        /* Set up Signal Frame */
        frame = get_sigframe(ksig, tsk, sizeof(*frame), 1);
+       newsp = (unsigned long __user *)((unsigned long)frame - 
(__SIGNAL_FRAMESIZE + 16));
        if (MSR_TM_ACTIVE(msr))
                prepare_save_tm_user_regs();
        else
                prepare_save_user_regs(1);
 
-       scoped_user_rw_access(frame, badframe) {
+       scoped_user_rw_access_size(newsp, __SIGNAL_FRAMESIZE + 16 + 
sizeof(*frame), badframe) {
                struct mcontext __user *mctx;
                struct mcontext __user *tm_mctx = NULL;
 
@@ -784,6 +785,9 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t 
*oldset,
                        asm("dcbst %y0; sync; icbi %y0; sync" :: "Z" 
(mctx->mc_pad[0]));
                }
                unsafe_put_sigset_t(&frame->uc.uc_sigmask, oldset, badframe);
+
+               /* create a stack frame for the caller of the handler */
+               unsafe_put_user(regs->gpr[1], newsp, badframe);
        }
 
        if (copy_siginfo_to_user(&frame->info, &ksig->info))
@@ -795,13 +799,8 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t 
*oldset,
        tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
 #endif
 
-       /* create a stack frame for the caller of the handler */
-       newsp = ((unsigned long)frame) - (__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[1] = (unsigned long)newsp;
        regs->gpr[3] = ksig->sig;
        regs->gpr[4] = (unsigned long)&frame->info;
        regs->gpr[5] = (unsigned long)&frame->uc;
@@ -826,7 +825,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
 {
        struct sigcontext __user *sc;
        struct sigframe __user *frame;
-       unsigned long newsp = 0;
+       unsigned long __user *newsp;
        unsigned long tramp;
        struct pt_regs *regs = tsk->thread.regs;
        /* Save the thread's msr before get_tm_stackpointer() changes it */
@@ -834,12 +833,13 @@ int handle_signal32(struct ksignal *ksig, sigset_t 
*oldset,
 
        /* Set up Signal Frame */
        frame = get_sigframe(ksig, tsk, sizeof(*frame), 1);
+       newsp = (unsigned long __user *)((unsigned long)frame - 
__SIGNAL_FRAMESIZE);
        if (MSR_TM_ACTIVE(msr))
                prepare_save_tm_user_regs();
        else
                prepare_save_user_regs(1);
 
-       scoped_user_rw_access(frame, badframe) {
+       scoped_user_rw_access_size(newsp, __SIGNAL_FRAMESIZE + sizeof(*frame), 
badframe) {
                struct mcontext __user *mctx;
                struct mcontext __user *tm_mctx = NULL;
 
@@ -876,6 +876,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
                        unsafe_put_user(PPC_RAW_SC(), &mctx->mc_pad[1], 
badframe);
                        asm("dcbst %y0; sync; icbi %y0; sync" :: "Z" 
(mctx->mc_pad[0]));
                }
+               unsafe_put_user(regs->gpr[1], newsp, badframe);
        }
 
        regs->link = tramp;
@@ -884,12 +885,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
        tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
 #endif
 
-       /* 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[1] = (unsigned long)newsp;
        regs->gpr[3] = ksig->sig;
        regs->gpr[4] = (unsigned long) sc;
        regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler);
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index bf7fc579d572..67de29cf581a 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -846,13 +846,14 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t 
*set,
                struct task_struct *tsk)
 {
        struct rt_sigframe __user *frame;
-       unsigned long newsp = 0;
+       unsigned long __user *newsp;
        long err = 0;
        struct pt_regs *regs = tsk->thread.regs;
        /* Save the thread's msr before get_tm_stackpointer() changes it */
        unsigned long msr = regs->msr;
 
        frame = get_sigframe(ksig, tsk, sizeof(*frame), 0);
+       newsp = (unsigned long __user *)((unsigned long)frame - 
__SIGNAL_FRAMESIZE);
 
        /*
         * This only applies when calling unsafe_setup_sigcontext() and must be
@@ -870,7 +871,7 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
                                            msr);
 
 #endif
-       scoped_user_write_access(frame, badframe) {
+       scoped_user_write_access_size(newsp, __SIGNAL_FRAMESIZE + 
sizeof(*frame), badframe) {
                unsafe_put_user(&frame->info, &frame->pinfo, badframe);
                unsafe_put_user(&frame->uc, &frame->puc, badframe);
 
@@ -892,6 +893,8 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
                }
 
                unsafe_copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set), 
badframe);
+               /* Allocate a dummy caller frame for the signal handler. */
+               unsafe_put_user(regs->gpr[1], newsp, badframe);
        }
 
        /* Save the siginfo outside of the unsafe block. */
@@ -911,10 +914,6 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
                regs_set_return_ip(regs, (unsigned long) &frame->tramp[0]);
        }
 
-       /* Allocate a dummy caller frame for the signal handler. */
-       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. */
        if (is_elf2_task()) {
                regs->ctr = (unsigned long) ksig->ka.sa.sa_handler;
@@ -936,7 +935,7 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
 
        /* enter the signal handler in native-endian mode */
        regs_set_return_msr(regs, (regs->msr & ~MSR_LE) | (MSR_KERNEL & 
MSR_LE));
-       regs->gpr[1] = newsp;
+       regs->gpr[1] = (unsigned long)newsp;
        regs->gpr[3] = ksig->sig;
        regs->result = 0;
        if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
-- 
2.54.0


Reply via email to