Commit 4aab1539 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] ppc32/64: FPU/vector register restore after signal

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: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a85f54d7
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment