arm64: signal: push the unwinding prologue on the signal stack
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm64 / kernel / signal.c
index 8807ba2cf262a5ddb463ba4f6e2e0691633695c4..051bb523ba2c6599745d53e63d3e966bcca51563 100644 (file)
@@ -41,6 +41,8 @@
 struct rt_sigframe {
        struct siginfo info;
        struct ucontext uc;
+       u64 fp;
+       u64 lr;
 };
 
 static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
@@ -175,6 +177,10 @@ static int setup_sigframe(struct rt_sigframe __user *sf,
        struct aux_context __user *aux =
                (struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
 
+       /* set up the stack frame for unwinding */
+       __put_user_error(regs->regs[29], &sf->fp, err);
+       __put_user_error(regs->regs[30], &sf->lr, err);
+
        for (i = 0; i < 31; i++)
                __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
                                 err);
@@ -210,9 +216,6 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
        if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
                sp = sp_top = current->sas_ss_sp + current->sas_ss_size;
 
-       /* room for stack frame (FP, LR) */
-       sp -= 16;
-
        sp = (sp - framesize) & ~15;
        frame = (void __user *)sp;
 
@@ -225,20 +228,14 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
        return frame;
 }
 
-static int setup_return(struct pt_regs *regs, struct k_sigaction *ka,
-                       void __user *frame, int usig)
+static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+                        void __user *frame, int usig)
 {
-       int err = 0;
        __sigrestore_t sigtramp;
-       unsigned long __user *sp = (unsigned long __user *)regs->sp;
-
-       /* set up the stack frame */
-       __put_user_error(regs->regs[29], sp - 2, err);
-       __put_user_error(regs->regs[30], sp - 1, err);
 
        regs->regs[0] = usig;
-       regs->regs[29] = regs->sp - 16;
        regs->sp = (unsigned long)frame;
+       regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp);
        regs->pc = (unsigned long)ka->sa.sa_handler;
 
        if (ka->sa.sa_flags & SA_RESTORER)
@@ -247,8 +244,6 @@ static int setup_return(struct pt_regs *regs, struct k_sigaction *ka,
                sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
 
        regs->regs[30] = (unsigned long)sigtramp;
-
-       return err;
 }
 
 static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
@@ -272,13 +267,13 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
        err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack));
 
        err |= setup_sigframe(frame, regs, set);
-       if (err == 0)
-               err = setup_return(regs, ka, frame, usig);
-
-       if (err == 0 && ka->sa.sa_flags & SA_SIGINFO) {
-               err |= copy_siginfo_to_user(&frame->info, info);
-               regs->regs[1] = (unsigned long)&frame->info;
-               regs->regs[2] = (unsigned long)&frame->uc;
+       if (err == 0) {
+               setup_return(regs, ka, frame, usig);
+               if (ka->sa.sa_flags & SA_SIGINFO) {
+                       err |= copy_siginfo_to_user(&frame->info, info);
+                       regs->regs[1] = (unsigned long)&frame->info;
+                       regs->regs[2] = (unsigned long)&frame->uc;
+               }
        }
 
        return err;