vserver 1.9.3
[linux-2.6.git] / arch / ppc / kernel / signal.c
index e4f2390..260716a 100644 (file)
@@ -183,11 +183,11 @@ struct rt_sigframe
 
 /*
  * Save the current user registers on the user stack.
- * We only save the altivec registers if the process has used
- * altivec instructions at some point.
+ * We only save the altivec/spe registers if the process has used
+ * altivec/spe instructions at some point.
  */
 static int
-save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret)
+save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, int sigret)
 {
        /* save general and floating-point registers */
        CHECK_FULL_REGS(regs);
@@ -197,6 +197,10 @@ save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret)
 #ifdef CONFIG_ALTIVEC
        if (current->thread.used_vr && (regs->msr & MSR_VEC))
                giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+       if (current->thread.used_spe && (regs->msr & MSR_SPE))
+               giveup_spe(current);
 #endif /* CONFIG_ALTIVEC */
        preempt_enable();
 
@@ -225,10 +229,28 @@ save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret)
         * significant bits of a vector, we "cheat" and stuff VRSAVE in the
         * most significant bits of that same vector. --BenH
         */
-       if (__put_user(current->thread.vrsave, (u32 *)&frame->mc_vregs[32]))
+       if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32]))
                return 1;
 #endif /* CONFIG_ALTIVEC */
 
+#ifdef CONFIG_SPE
+       /* save spe registers */
+       if (current->thread.used_spe) {
+               if (__copy_to_user(&frame->mc_vregs, current->thread.evr,
+                                  ELF_NEVRREG * sizeof(u32)))
+                       return 1;
+               /* set MSR_SPE in the saved MSR value to indicate that
+                  frame->mc_vregs contains valid data */
+               if (__put_user(regs->msr | MSR_SPE, &frame->mc_gregs[PT_MSR]))
+                       return 1;
+       }
+       /* else assert((regs->msr & MSR_SPE) == 0) */
+
+       /* We always copy to/from spefscr */
+       if (__put_user(current->thread.spefscr, (u32 *)&frame->mc_vregs + ELF_NEVRREG))
+               return 1;
+#endif /* CONFIG_SPE */
+
        if (sigret) {
                /* Set up the sigreturn trampoline: li r0,sigret; sc */
                if (__put_user(0x38000000UL + sigret, &frame->tramp[0])
@@ -248,8 +270,8 @@ save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret)
 static int
 restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr, int sig)
 {
-       unsigned long save_r2;
-#ifdef CONFIG_ALTIVEC
+       unsigned long save_r2 = 0;
+#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE)
        unsigned long msr;
 #endif
 
@@ -286,10 +308,27 @@ restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr, int sig)
                memset(&current->thread.vr, 0, ELF_NVRREG * sizeof(vector128));
 
        /* Always get VRSAVE back */
-       if (__get_user(current->thread.vrsave, (u32 *)&sr->mc_vregs[32]))
+       if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32]))
                return 1;
 #endif /* CONFIG_ALTIVEC */
 
+#ifdef CONFIG_SPE
+       /* force the process to reload the spe registers from
+          current->thread when it next does spe instructions */
+       regs->msr &= ~MSR_SPE;
+       if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_SPE) != 0) {
+               /* restore spe registers from the stack */
+               if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
+                                    sizeof(sr->mc_vregs)))
+                       return 1;
+       } else if (current->thread.used_spe)
+               memset(&current->thread.evr, 0, ELF_NEVRREG * sizeof(u32));
+
+       /* Always get SPEFSCR back */
+       if (__get_user(current->thread.spefscr, (u32 *)&sr->mc_vregs + ELF_NEVRREG))
+               return 1;
+#endif /* CONFIG_SPE */
+
        return 0;
 }
 
@@ -365,15 +404,13 @@ badframe:
        printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
               regs, frame, newsp);
 #endif
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
+       force_sigsegv(sig, current);
 }
 
 static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int sig)
 {
        sigset_t set;
-       struct mcontext *mcp;
+       struct mcontext __user *mcp;
 
        if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(set))
            || __get_user(mcp, &ucp->uc_regs))
@@ -408,8 +445,8 @@ int sys_swapcontext(struct ucontext __user *old_ctx,
        if (new_ctx == NULL)
                return 0;
        if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx))
-           || __get_user(tmp, (u8 *) new_ctx)
-           || __get_user(tmp, (u8 *) (new_ctx + 1) - 1))
+           || __get_user(tmp, (u8 __user *) new_ctx)
+           || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1))
                return -EFAULT;
 
        /*
@@ -485,7 +522,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
        /* create a stack frame for the caller of the handler */
        newsp -= __SIGNAL_FRAMESIZE;
 
-       if (verify_area(VERIFY_WRITE, (void *) newsp, origsp - newsp))
+       if (verify_area(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
                goto badframe;
 
 #if _NSIG != 64
@@ -517,9 +554,7 @@ badframe:
        printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n",
               regs, frame, newsp);
 #endif
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
+       force_sigsegv(sig, current);
 }
 
 /*
@@ -544,7 +579,7 @@ int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
        set.sig[1] = sigctx._unused[3];
        restore_sigmask(&set);
 
-       sr = (struct mcontext *) sigctx.regs;
+       sr = (struct mcontext __user *) sigctx.regs;
        if (verify_area(VERIFY_READ, sr, sizeof(*sr))
            || restore_user_regs(regs, sr, 1))
                goto badframe;
@@ -565,7 +600,7 @@ badframe:
 int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
        siginfo_t info;
-       struct k_sigaction *ka;
+       struct k_sigaction ka;
        unsigned long frame, newsp;
        int signr, ret;
 
@@ -574,9 +609,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
 
        newsp = frame = 0;
 
-       signr = get_signal_to_deliver(&info, regs, NULL);
-
-       ka = (signr == 0)? NULL: &current->sighand->action[signr-1];
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
        if (TRAP(regs) == 0x0C00                /* System Call! */
            && regs->ccr & 0x10000000           /* error signalled */
@@ -587,7 +620,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
                if (signr > 0
                    && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK
                        || (ret == ERESTARTSYS
-                           && !(ka->sa.sa_flags & SA_RESTART)))) {
+                           && !(ka.sa.sa_flags & SA_RESTART)))) {
                        /* make the system call return an EINTR error */
                        regs->result = -EINTR;
                        regs->gpr[3] = EINTR;
@@ -606,7 +639,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        if (signr == 0)
                return 0;               /* no signals delivered */
 
-       if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
+       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
@@ -614,17 +647,14 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        newsp &= ~0xfUL;
 
        /* Whee!  Actually deliver the signal.  */
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               handle_rt_signal(signr, ka, &info, oldset, regs, newsp);
+       if (ka.sa.sa_flags & SA_SIGINFO)
+               handle_rt_signal(signr, &ka, &info, oldset, regs, newsp);
        else
-               handle_signal(signr, ka, &info, oldset, regs, newsp);
-
-       if (ka->sa.sa_flags & SA_ONESHOT)
-               ka->sa.sa_handler = SIG_DFL;
+               handle_signal(signr, &ka, &info, oldset, regs, newsp);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
+       if (!(ka.sa.sa_flags & SA_NODEFER)) {
                spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+               sigorsets(&current->blocked,&current->blocked,&ka.sa.sa_mask);
                sigaddset(&current->blocked, signr);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);