]> git.hungrycats.org Git - linux/commitdiff
[PATCH] ppc32/64: FPU/vector register restore after signal
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 18 Oct 2004 15:23:09 +0000 (08:23 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 18 Oct 2004 15:23:09 +0000 (08:23 -0700)
This fixes some issues with restoring the altivec and/or FPU registers
upon return from a signal or when setting a context.  It also add a
proper stack backlink to the signal frames created for 64 bits
applications.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/ppc/kernel/signal.c
arch/ppc64/kernel/signal.c
arch/ppc64/kernel/signal32.c

index 260716af587d5dcf265a43ef87aaa58971d2314b..e5135acda005432eb47f9712c0c1822d7e5bd831 100644 (file)
@@ -329,6 +329,11 @@ restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr, int sig)
                return 1;
 #endif /* CONFIG_SPE */
 
+#ifndef CONFIG_SMP
+       last_task_used_math = NULL;
+       last_task_used_altivec = NULL;
+       last_task_used_spe = NULL;
+#endif
        return 0;
 }
 
index ce616280b7bd85cb107be2e337fe7b2e59c8c3ed..b72ee1c26002f14124cf57e8972d631224449fab 100644 (file)
@@ -179,6 +179,9 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
        unsigned long err = 0;
        unsigned long save_r13 = 0;
        elf_greg_t *gregs = (elf_greg_t *)regs;
+#ifdef CONFIG_ALTIVEC
+       unsigned long msr;
+#endif
        int i;
 
        /* If this is not a signal return, we preserve the TLS in r13 */
@@ -204,13 +207,15 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
 
 #ifdef CONFIG_ALTIVEC
        err |= __get_user(v_regs, &sc->v_regs);
+       err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
        if (err)
                return err;
        /* Copy 33 vec registers (vr0..31 and vscr) from the stack */
-       if (v_regs != 0 && (regs->msr & MSR_VEC) != 0)
-               err |= __copy_from_user(current->thread.vr, v_regs, 33 * sizeof(vector128));
+       if (v_regs != 0 && (msr & MSR_VEC) != 0)
+               err |= __copy_from_user(current->thread.vr, v_regs,
+                                       33 * sizeof(vector128));
        else if (current->thread.used_vr)
-               memset(&current->thread.vr, 0, 33);
+               memset(current->thread.vr, 0, 33 * sizeof(vector128));
        /* Always get VRSAVE back */
        if (v_regs != 0)
                err |= __get_user(current->thread.vrsave, (u32 __user *)&v_regs[33]);
@@ -218,6 +223,10 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
                current->thread.vrsave = 0;
 #endif /* CONFIG_ALTIVEC */
 
+#ifndef CONFIG_SMP
+       last_task_used_math = NULL;
+       last_task_used_altivec = NULL;
+#endif
        /* Force reload of FP/VEC */
        regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC);
 
@@ -420,7 +429,7 @@ static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
 
        /* Allocate a dummy caller frame for the signal handler. */
        newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
-       err |= put_user(0, (unsigned long __user *)newsp);
+       err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);
 
        /* Set up "regs" so we "return" to the signal handler. */
        err |= get_user(regs->nip, &funct_desc_ptr->entry);
index 79f7b844610eac4a6a4c63beca3eae343475a718..67c9a198afe9c7d97b6f21a077325d9f62a4027f 100644 (file)
@@ -227,13 +227,17 @@ static long restore_user_regs(struct pt_regs *regs,
                                     sizeof(sr->mc_vregs)))
                        return 1;
        } else if (current->thread.used_vr)
-               memset(&current->thread.vr, 0, ELF_NVRREG32 * sizeof(vector128));
+               memset(current->thread.vr, 0, ELF_NVRREG32 * sizeof(vector128));
 
        /* Always get VRSAVE back */
        if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32]))
                return 1;
 #endif /* CONFIG_ALTIVEC */
 
+#ifndef CONFIG_SMP
+       last_task_used_math = NULL;
+       last_task_used_altivec = NULL;
+#endif
        return 0;
 }