Skip to contentSkip to conversation

ppc32: More preempt fixes

PATCH New Benjamin Herrenschmidt 1 participant 1 message Mar 29, 2004 ptrace support

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ppc32: More preempt fixes

Hi !

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

arch/ppc/kernel/align.c +6 -2
diff -urN linux-2.5/arch/ppc/kernel/align.c linuxppc-2.5-benh/arch/ppc/kernel/align.c
@@ -262,8 +262,12 @@
 			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 */
 
arch/ppc/kernel/head.S +2 -2
diff -urN linux-2.5/arch/ppc/kernel/head.S linuxppc-2.5-benh/arch/ppc/kernel/head.S
@@ -462,7 +462,7 @@
 	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 @@
 	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)
 
 /*
arch/ppc/kernel/ptrace.c +8 -0
diff -urN linux-2.5/arch/ppc/kernel/ptrace.c linuxppc-2.5-benh/arch/ppc/kernel/ptrace.c
@@ -242,8 +242,10 @@
 		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 @@
 		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 @@
 #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 @@
 		/* 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
arch/ppc/kernel/signal.c +7 -2
diff -urN linux-2.5/arch/ppc/kernel/signal.c linuxppc-2.5-benh/arch/ppc/kernel/signal.c
@@ -191,8 +191,15 @@
 {
 	/* 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 @@
 #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;