From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

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


---

 25-akpm/arch/ppc/kernel/align.c  |    8 ++++++--
 25-akpm/arch/ppc/kernel/head.S   |    4 ++--
 25-akpm/arch/ppc/kernel/ptrace.c |    8 ++++++++
 25-akpm/arch/ppc/kernel/signal.c |    9 +++++++--
 4 files changed, 23 insertions(+), 6 deletions(-)

diff -puN arch/ppc/kernel/align.c~ppc32-preempt-fixes arch/ppc/kernel/align.c
--- 25/arch/ppc/kernel/align.c~ppc32-preempt-fixes	2004-03-28 22:54:47.842801856 -0800
+++ 25-akpm/arch/ppc/kernel/align.c	2004-03-28 22:54:47.849800792 -0800
@@ -262,8 +262,12 @@ fix_alignment(struct pt_regs *regs)
 			return -EFAULT;	/* bad address */
 	}
 
-	if ((flags & F) && (regs->msr & MSR_FP))
-		giveup_fpu(current);
+	if (flags & F) {
+		preempt_disable();
+		if (regs->msr & MSR_FP)
+			giveup_fpu(current);
+		preempt_enable();
+	}
 	if (flags & M)
 		return 0;		/* too hard for now */
 
diff -puN arch/ppc/kernel/head.S~ppc32-preempt-fixes arch/ppc/kernel/head.S
--- 25/arch/ppc/kernel/head.S~ppc32-preempt-fixes	2004-03-28 22:54:47.843801704 -0800
+++ 25-akpm/arch/ppc/kernel/head.S	2004-03-28 22:54:47.851800488 -0800
@@ -462,7 +462,7 @@ Alignment:
 	EXC_XFER_EE(0x600, AlignmentException)
 
 /* Program check exception */
-	EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_EE)
+	EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD)
 
 /* Floating-point unavailable */
 	. = 0x800
@@ -485,7 +485,7 @@ SystemCall:
 	EXC_XFER_EE_LITE(0xc00, DoSyscall)
 
 /* 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)
 
 /*
diff -puN arch/ppc/kernel/ptrace.c~ppc32-preempt-fixes arch/ppc/kernel/ptrace.c
--- 25/arch/ppc/kernel/ptrace.c~ppc32-preempt-fixes	2004-03-28 22:54:47.845801400 -0800
+++ 25-akpm/arch/ppc/kernel/ptrace.c	2004-03-28 22:54:47.851800488 -0800
@@ -242,8 +242,10 @@ int sys_ptrace(long request, long pid, l
 		if (index < PT_FPR0) {
 			tmp = get_reg(child, (int) index);
 		} else {
+			preempt_disable();
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
+			preempt_enable();
 			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
 		}
 		ret = put_user(tmp,(unsigned long *) data);
@@ -276,8 +278,10 @@ int sys_ptrace(long request, long pid, l
 		if (index < PT_FPR0) {
 			ret = put_reg(child, index, data);
 		} else {
+			preempt_disable();
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
+			preempt_enable();
 			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
 			ret = 0;
 		}
@@ -338,8 +342,10 @@ int sys_ptrace(long request, long pid, l
 #ifdef CONFIG_ALTIVEC
 	case PTRACE_GETVRREGS:
 		/* Get the child altivec register state. */
+		preempt_disable();
 		if (child->thread.regs->msr & MSR_VEC)
 			giveup_altivec(child);
+		preempt_enable();
 		ret = get_vrregs((unsigned long *)data, child);
 		break;
 
@@ -347,8 +353,10 @@ int sys_ptrace(long request, long pid, l
 		/* Set the child altivec register state. */
 		/* this is to clear the MSR_VEC bit to force a reload
 		 * of register state from memory */
+		preempt_disable();
 		if (child->thread.regs->msr & MSR_VEC)
 			giveup_altivec(child);
+		preempt_enable();
 		ret = set_vrregs(child, (unsigned long *)data);
 		break;
 #endif
diff -puN arch/ppc/kernel/signal.c~ppc32-preempt-fixes arch/ppc/kernel/signal.c
--- 25/arch/ppc/kernel/signal.c~ppc32-preempt-fixes	2004-03-28 22:54:47.847801096 -0800
+++ 25-akpm/arch/ppc/kernel/signal.c	2004-03-28 22:54:47.852800336 -0800
@@ -191,8 +191,15 @@ save_user_regs(struct pt_regs *regs, str
 {
 	/* save general and floating-point registers */
 	CHECK_FULL_REGS(regs);
+	preempt_disable();
 	if (regs->msr & MSR_FP)
 		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)
 	    || __copy_to_user(&frame->mc_fregs, current->thread.fpr,
 			      ELF_NFPREG * sizeof(double)))
@@ -203,8 +210,6 @@ save_user_regs(struct pt_regs *regs, str
 #ifdef CONFIG_ALTIVEC
 	/* save altivec registers */
 	if (current->thread.used_vr) {
-		if (regs->msr & MSR_VEC)
-			giveup_altivec(current);
 		if (__copy_to_user(&frame->mc_vregs, current->thread.vr,
 				   ELF_NVRREG * sizeof(vector128)))
 			return 1;

_