From 4aab1539a2dea7c6efe80f7e69bfa46d9af90465 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 18 Oct 2004 08:23:09 -0700 Subject: [PATCH] [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: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- arch/ppc/kernel/signal.c | 5 +++++ arch/ppc64/kernel/signal.c | 17 +++++++++++++---- arch/ppc64/kernel/signal32.c | 6 +++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 260716af587d5..e5135acda0054 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -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; } diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index ce616280b7bd8..b72ee1c26002f 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -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(¤t->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); diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index 79f7b844610ea..67c9a198afe9c 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -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(¤t->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; } -- 2.53.0