From 62e160b5b2716b92068eb9ecd9ad2c3538b449aa Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 25 Mar 2004 06:07:08 -0800 Subject: [PATCH] [PATCH] ppc32: arch code preempt fixes I figured the best way to stop beeing bothered by users trying to run preempt was to fix it ;) Here's a first batch that close some races we had when testing regs->msr for altivec or FPU enable, then doing the giveup_* function. A preempt in between those would have caused us to save a stale altivec or FPU context. --- arch/ppc/kernel/process.c | 12 +++++++++++- arch/ppc/kernel/traps.c | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 3eb61658b8d93..e94ead3eac9b7 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -163,6 +163,7 @@ dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) void enable_kernel_altivec(void) { + preempt_disable(); #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) giveup_altivec(current); @@ -171,12 +172,14 @@ enable_kernel_altivec(void) #else giveup_altivec(last_task_used_altivec); #endif /* __SMP __ */ + preempt_enable(); } #endif /* CONFIG_ALTIVEC */ void enable_kernel_fp(void) { + preempt_disable(); #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) giveup_fpu(current); @@ -185,13 +188,16 @@ enable_kernel_fp(void) #else giveup_fpu(last_task_used_math); #endif /* CONFIG_SMP */ + preempt_enable(); } int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) { - if (tsk->thread.regs && tsk->thread.regs->msr & MSR_FP) + preempt_disable(); + if (tsk->thread.regs && (tsk->thread.regs->msr & MSR_FP)) giveup_fpu(tsk); + preempt_enable(); memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); return 1; } @@ -329,12 +335,14 @@ void prepare_to_copy(struct task_struct *tsk) if (regs == NULL) return; + preempt_disable(); if (regs->msr & MSR_FP) giveup_fpu(current); #ifdef CONFIG_ALTIVEC if (regs->msr & MSR_VEC) giveup_altivec(current); #endif /* CONFIG_ALTIVEC */ + preempt_enable(); } /* @@ -479,12 +487,14 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; + preempt_disable(); if (regs->msr & MSR_FP) giveup_fpu(current); #ifdef CONFIG_ALTIVEC if (regs->msr & MSR_VEC) giveup_altivec(current); #endif /* CONFIG_ALTIVEC */ + preempt_enable(); error = do_execve(filename, (char __user *__user *) a1, (char __user *__user *) a2, regs); if (error == 0) diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index e5a2c336e3113..197b8629b9ae7 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -391,14 +391,25 @@ check_bug_trap(struct pt_regs *regs) return 0; if (bug->line & BUG_WARNING_TRAP) { /* this is a WARN_ON rather than BUG/BUG_ON */ +#ifdef CONFIG_XMON + xmon_printf(KERN_ERR "Badness in %s at %s:%d\n", + bug->function, bug->file, + bug->line & ~BUG_WARNING_TRAP); +#endif /* CONFIG_XMON */ printk(KERN_ERR "Badness in %s at %s:%d\n", bug->function, bug->file, bug->line & ~BUG_WARNING_TRAP); dump_stack(); return 1; } +#ifdef CONFIG_XMON + xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%d!\n", + bug->function, bug->file, bug->line); + xmon(regs); +#endif /* CONFIG_XMON */ printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n", bug->function, bug->file, bug->line); + return 0; } @@ -427,8 +438,14 @@ ProgramCheckException(struct pt_regs *regs) int code = 0; u32 fpscr; + /* We must make sure the FP state is consistent with + * our MSR_FP in regs + */ + preempt_disable(); if (regs->msr & MSR_FP) giveup_fpu(current); + preempt_enable(); + fpscr = current->thread.fpscr; fpscr &= fpscr << 22; /* mask summary bits with enables */ if (fpscr & FPSCR_VX) @@ -592,13 +609,17 @@ TAUException(struct pt_regs *regs) void AltivecAssistException(struct pt_regs *regs) { + preempt_disable(); if (regs->msr & MSR_VEC) giveup_altivec(current); + preempt_enable(); + /* XXX quick hack for now: set the non-Java bit in the VSCR */ current->thread.vscr.u[3] |= 0x10000; } #endif /* CONFIG_ALTIVEC */ + void __init trap_init(void) { } -- 2.53.0