]> Pileus Git - ~andy/linux/blobdiff - arch/sparc/kernel/signal32.c
Merge remote-tracking branch 'asoc/fix/wm8960' into tmp
[~andy/linux] / arch / sparc / kernel / signal32.c
index 9d9eb91d0de1114ea7632db4bb74e54775397c7d..b524f91dd0e51ad4a09119759c403843b9a7e3f9 100644 (file)
@@ -323,7 +323,7 @@ static int invalid_frame_pointer(void __user *fp, int fplen)
        return 0;
 }
 
-static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
+static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
 {
        unsigned long sp;
        
@@ -338,12 +338,7 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns
                return (void __user *) -1L;
 
        /* This is the X/Open sanctioned signal stack switching.  */
-       if (sa->sa_flags & SA_ONSTACK) {
-               if (sas_ss_flags(sp) == 0)
-                       sp = current->sas_ss_sp + current->sas_ss_size;
-       }
-
-       sp -= framesize;
+       sp = sigsp(sp, ksig) - framesize;
 
        /* Always align the stack frame.  This handles two cases.  First,
         * sigaltstack need not be mindful of platform specific stack
@@ -414,8 +409,8 @@ out_irqs_on:
 
 }
 
-static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
-                        int signo, sigset_t *oldset)
+static int setup_frame32(struct ksignal *ksig, struct pt_regs *regs,
+                        sigset_t *oldset)
 {
        struct signal_frame32 __user *sf;
        int i, err, wsaved;
@@ -437,10 +432,12 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                sigframe_size += sizeof(__siginfo_rwin_t);
 
        sf = (struct signal_frame32 __user *)
-               get_sigframe(&ka->sa, regs, sigframe_size);
+               get_sigframe(ksig, regs, sigframe_size);
        
-       if (invalid_frame_pointer(sf, sigframe_size))
-               goto sigill;
+       if (invalid_frame_pointer(sf, sigframe_size)) {
+               do_exit(SIGILL);
+               return -EINVAL;
+       }
 
        tail = (sf + 1);
 
@@ -514,16 +511,16 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
        }       
        if (err)
-               goto sigsegv;
+               return err;
 
        /* 3. signal handler back-trampoline and parameters */
        regs->u_regs[UREG_FP] = (unsigned long) sf;
-       regs->u_regs[UREG_I0] = signo;
+       regs->u_regs[UREG_I0] = ksig->sig;
        regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
        regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
 
        /* 4. signal handler */
-       regs->tpc = (unsigned long) ka->sa.sa_handler;
+       regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;
        regs->tnpc = (regs->tpc + 4);
        if (test_thread_flag(TIF_32BIT)) {
                regs->tpc &= 0xffffffff;
@@ -531,8 +528,8 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
        }
 
        /* 5. return to kernel instructions */
-       if (ka->ka_restorer) {
-               regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+       if (ksig->ka.ka_restorer) {
+               regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
        } else {
                unsigned long address = ((unsigned long)&(sf->insns[0]));
 
@@ -541,23 +538,14 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                err  = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/
                err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
                if (err)
-                       goto sigsegv;
+                       return err;
                flush_signal_insns(address);
        }
        return 0;
-
-sigill:
-       do_exit(SIGILL);
-       return -EINVAL;
-
-sigsegv:
-       force_sigsegv(signo, current);
-       return -EFAULT;
 }
 
-static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
-                           unsigned long signr, sigset_t *oldset,
-                           siginfo_t *info)
+static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs,
+                           sigset_t *oldset)
 {
        struct rt_signal_frame32 __user *sf;
        int i, err, wsaved;
@@ -579,10 +567,12 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                sigframe_size += sizeof(__siginfo_rwin_t);
 
        sf = (struct rt_signal_frame32 __user *)
-               get_sigframe(&ka->sa, regs, sigframe_size);
+               get_sigframe(ksig, regs, sigframe_size);
        
-       if (invalid_frame_pointer(sf, sigframe_size))
-               goto sigill;
+       if (invalid_frame_pointer(sf, sigframe_size)) {
+               do_exit(SIGILL);
+               return -EINVAL;
+       }
 
        tail = (sf + 1);
 
@@ -627,7 +617,7 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
        }
 
        /* Update the siginfo structure.  */
-       err |= copy_siginfo_to_user32(&sf->info, info);
+       err |= copy_siginfo_to_user32(&sf->info, &ksig->info);
        
        /* Setup sigaltstack */
        err |= __compat_save_altstack(&sf->stack, regs->u_regs[UREG_FP]);
@@ -660,16 +650,16 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
        }
        if (err)
-               goto sigsegv;
+               return err;
        
        /* 3. signal handler back-trampoline and parameters */
        regs->u_regs[UREG_FP] = (unsigned long) sf;
-       regs->u_regs[UREG_I0] = signr;
+       regs->u_regs[UREG_I0] = ksig->sig;
        regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
        regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
 
        /* 4. signal handler */
-       regs->tpc = (unsigned long) ka->sa.sa_handler;
+       regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;
        regs->tnpc = (regs->tpc + 4);
        if (test_thread_flag(TIF_32BIT)) {
                regs->tpc &= 0xffffffff;
@@ -677,8 +667,8 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
        }
 
        /* 5. return to kernel instructions */
-       if (ka->ka_restorer)
-               regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+       if (ksig->ka.ka_restorer)
+               regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
        else {
                unsigned long address = ((unsigned long)&(sf->insns[0]));
 
@@ -690,36 +680,25 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
                /* t 0x10 */
                err |= __put_user(0x91d02010, &sf->insns[1]);
                if (err)
-                       goto sigsegv;
+                       return err;
 
                flush_signal_insns(address);
        }
        return 0;
-
-sigill:
-       do_exit(SIGILL);
-       return -EINVAL;
-
-sigsegv:
-       force_sigsegv(signr, current);
-       return -EFAULT;
 }
 
-static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
-                                 siginfo_t *info,
-                                 sigset_t *oldset, struct pt_regs *regs)
+static inline void handle_signal32(struct ksignal *ksig, 
+                                 struct pt_regs *regs)
 {
+       sigset_t *oldset = sigmask_to_save();
        int err;
 
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               err = setup_rt_frame32(ka, regs, signr, oldset, info);
+       if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+               err = setup_rt_frame32(ksig, regs, oldset);
        else
-               err = setup_frame32(ka, regs, signr, oldset);
+               err = setup_frame32(ksig, regs, oldset);
 
-       if (err)
-               return;
-
-       signal_delivered(signr, info, ka, regs, 0);
+       signal_setup_done(err, ksig, 0);
 }
 
 static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
@@ -747,52 +726,43 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-void do_signal32(sigset_t *oldset, struct pt_regs * regs)
+void do_signal32(struct pt_regs * regs)
 {
-       struct k_sigaction ka;
-       unsigned long orig_i0;
-       int restart_syscall;
-       siginfo_t info;
-       int signr;
-       
-       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+       struct ksignal ksig;
+       unsigned long orig_i0 = 0;
+       int restart_syscall = 0;
+       bool has_handler = get_signal(&ksig);
 
-       restart_syscall = 0;
-       orig_i0 = 0;
        if (pt_regs_is_syscall(regs) &&
            (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
                restart_syscall = 1;
                orig_i0 = regs->u_regs[UREG_G6];
        }
 
-       if (signr > 0) {
+       if (has_handler) {
                if (restart_syscall)
-                       syscall_restart32(orig_i0, regs, &ka.sa);
-               handle_signal32(signr, &ka, &info, oldset, regs);
-               return;
-       }
-       if (restart_syscall &&
-           (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
-            regs->u_regs[UREG_I0] == ERESTARTSYS ||
-            regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
-               /* replay the system call when we are done */
-               regs->u_regs[UREG_I0] = orig_i0;
-               regs->tpc -= 4;
-               regs->tnpc -= 4;
-               pt_regs_clear_syscall(regs);
-       }
-       if (restart_syscall &&
-           regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
-               regs->u_regs[UREG_G1] = __NR_restart_syscall;
-               regs->tpc -= 4;
-               regs->tnpc -= 4;
-               pt_regs_clear_syscall(regs);
+                       syscall_restart32(orig_i0, regs, &ksig.ka.sa);
+               handle_signal32(&ksig, regs);
+       } else {
+               if (restart_syscall) {
+                       switch (regs->u_regs[UREG_I0]) {
+                       case ERESTARTNOHAND:
+                       case ERESTARTSYS:
+                       case ERESTARTNOINTR:
+                               /* replay the system call when we are done */
+                               regs->u_regs[UREG_I0] = orig_i0;
+                               regs->tpc -= 4;
+                               regs->tnpc -= 4;
+                               pt_regs_clear_syscall(regs);
+                       case ERESTART_RESTARTBLOCK:
+                               regs->u_regs[UREG_G1] = __NR_restart_syscall;
+                               regs->tpc -= 4;
+                               regs->tnpc -= 4;
+                               pt_regs_clear_syscall(regs);
+                       }
+               }
+               restore_saved_sigmask();
        }
-
-       /* If there's no signal to deliver, we just put the saved sigmask
-        * back
-        */
-       restore_saved_sigmask();
 }
 
 struct sigstack32 {