Commit 379092d2 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] ppc32: More preempt fixes

This patch fixes more cases of possible preempt issue when testing
MSR for FP or VEC bits and then doing giveup_fpu or giveup_altivec
that I missed in my previous round of fixes (bk get helps before
grepping ;)

I also change the single step and program check exceptions to not
re-enable interrupts right away on C code entry, it was useless and
would cause interesting issues with preempt & xmon
parent 1a336f5d
...@@ -262,8 +262,12 @@ fix_alignment(struct pt_regs *regs) ...@@ -262,8 +262,12 @@ fix_alignment(struct pt_regs *regs)
return -EFAULT; /* bad address */ return -EFAULT; /* bad address */
} }
if ((flags & F) && (regs->msr & MSR_FP)) if (flags & F) {
preempt_disable();
if (regs->msr & MSR_FP)
giveup_fpu(current); giveup_fpu(current);
preempt_enable();
}
if (flags & M) if (flags & M)
return 0; /* too hard for now */ return 0; /* too hard for now */
......
...@@ -462,7 +462,7 @@ Alignment: ...@@ -462,7 +462,7 @@ Alignment:
EXC_XFER_EE(0x600, AlignmentException) EXC_XFER_EE(0x600, AlignmentException)
/* Program check exception */ /* Program check exception */
EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_EE) EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD)
/* Floating-point unavailable */ /* Floating-point unavailable */
. = 0x800 . = 0x800
...@@ -485,7 +485,7 @@ SystemCall: ...@@ -485,7 +485,7 @@ SystemCall:
EXC_XFER_EE_LITE(0xc00, DoSyscall) EXC_XFER_EE_LITE(0xc00, DoSyscall)
/* Single step - not used on 601 */ /* Single step - not used on 601 */
EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_EE) EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD)
EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE) EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE)
/* /*
......
...@@ -242,8 +242,10 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -242,8 +242,10 @@ int sys_ptrace(long request, long pid, long addr, long data)
if (index < PT_FPR0) { if (index < PT_FPR0) {
tmp = get_reg(child, (int) index); tmp = get_reg(child, (int) index);
} else { } else {
preempt_disable();
if (child->thread.regs->msr & MSR_FP) if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child); giveup_fpu(child);
preempt_enable();
tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
} }
ret = put_user(tmp,(unsigned long *) data); ret = put_user(tmp,(unsigned long *) data);
...@@ -276,8 +278,10 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -276,8 +278,10 @@ int sys_ptrace(long request, long pid, long addr, long data)
if (index < PT_FPR0) { if (index < PT_FPR0) {
ret = put_reg(child, index, data); ret = put_reg(child, index, data);
} else { } else {
preempt_disable();
if (child->thread.regs->msr & MSR_FP) if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child); giveup_fpu(child);
preempt_enable();
((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
ret = 0; ret = 0;
} }
...@@ -338,8 +342,10 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -338,8 +342,10 @@ int sys_ptrace(long request, long pid, long addr, long data)
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS: case PTRACE_GETVRREGS:
/* Get the child altivec register state. */ /* Get the child altivec register state. */
preempt_disable();
if (child->thread.regs->msr & MSR_VEC) if (child->thread.regs->msr & MSR_VEC)
giveup_altivec(child); giveup_altivec(child);
preempt_enable();
ret = get_vrregs((unsigned long *)data, child); ret = get_vrregs((unsigned long *)data, child);
break; break;
...@@ -347,8 +353,10 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -347,8 +353,10 @@ int sys_ptrace(long request, long pid, long addr, long data)
/* Set the child altivec register state. */ /* Set the child altivec register state. */
/* this is to clear the MSR_VEC bit to force a reload /* this is to clear the MSR_VEC bit to force a reload
* of register state from memory */ * of register state from memory */
preempt_disable();
if (child->thread.regs->msr & MSR_VEC) if (child->thread.regs->msr & MSR_VEC)
giveup_altivec(child); giveup_altivec(child);
preempt_enable();
ret = set_vrregs(child, (unsigned long *)data); ret = set_vrregs(child, (unsigned long *)data);
break; break;
#endif #endif
......
...@@ -191,8 +191,15 @@ save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret) ...@@ -191,8 +191,15 @@ save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret)
{ {
/* save general and floating-point registers */ /* save general and floating-point registers */
CHECK_FULL_REGS(regs); CHECK_FULL_REGS(regs);
preempt_disable();
if (regs->msr & MSR_FP) if (regs->msr & MSR_FP)
giveup_fpu(current); giveup_fpu(current);
#ifdef CONFIG_ALTIVEC
if (current->thread.used_vr && (regs->msr & MSR_VEC))
giveup_altivec(current);
#endif /* CONFIG_ALTIVEC */
preempt_enable();
if (__copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE) if (__copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE)
|| __copy_to_user(&frame->mc_fregs, current->thread.fpr, || __copy_to_user(&frame->mc_fregs, current->thread.fpr,
ELF_NFPREG * sizeof(double))) ELF_NFPREG * sizeof(double)))
...@@ -203,8 +210,6 @@ save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret) ...@@ -203,8 +210,6 @@ save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret)
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
/* save altivec registers */ /* save altivec registers */
if (current->thread.used_vr) { if (current->thread.used_vr) {
if (regs->msr & MSR_VEC)
giveup_altivec(current);
if (__copy_to_user(&frame->mc_vregs, current->thread.vr, if (__copy_to_user(&frame->mc_vregs, current->thread.vr,
ELF_NVRREG * sizeof(vector128))) ELF_NVRREG * sizeof(vector128)))
return 1; return 1;
......
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