Re: apparent math-emu hang on movf instruction

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



greg.roelofs@xxxxxxxxxxx writes:
> I've just started looking at the kernel's emulation code, and one thing
> that pops out immediately is that there's no mention of movf anywhere
> in arch/mips/math-emu, though cp1emu.c does cover movc, movn, movz, and
> plain mov (at least, their .fmt variants).

"movc" covers both movf and movt (bit 16 says which).

But yes, it does look like an emulation bug.  It seems that the code
to handle GPR conditional moves (in cop1Emulate) was copied from the
code to handle FPR moves (in fpu_emu).  The cop1Emulate() code reads:

		if (((ctx->fcr31 & cond) != 0) != ((MIPSInst_RT(ir) & 1) != 0))
			return 0;
		xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];

"return 0" was fine in fpu_emu(), but not here, since it skips the
all-important:

	/* we did it !! */
	xcp->cp0_epc = VA_TO_REG(contpc);
	xcp->cp0_cause &= ~CAUSEF_BD;
	return 0;

So we'd reenter the exception handler on exit.

Does the patch below (against 2.6) fix things?  Only the first hunk
is needed to fix the bug, the rest is just there for consistency.

Richard


Index: arch/mips/math-emu/cp1emu.c
===================================================================
RCS file: /home/cvs/linux/arch/mips/math-emu/cp1emu.c,v
retrieving revision 1.32
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.32 cp1emu.c
--- arch/mips/math-emu/cp1emu.c	19 Jan 2004 16:25:21 -0000	1.32
+++ arch/mips/math-emu/cp1emu.c	29 Jul 2004 06:42:53 -0000
@@ -528,9 +528,8 @@ static int cop1Emulate(struct pt_regs *x
 		if (MIPSInst_FUNC(ir) != movc_op)
 			return SIGILL;
 		cond = fpucondbit[MIPSInst_RT(ir) >> 2];
-		if (((ctx->fcr31 & cond) != 0) != ((MIPSInst_RT(ir) & 1) != 0))
-			return 0;
-		xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];
+		if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0))
+			xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];
 		break;
 #endif
 
@@ -850,20 +849,17 @@ static int fpu_emu(struct pt_regs *xcp, 
 #if __mips >= 4
 		case fmovc_op:
 			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
-			if (((ctx->fcr31 & cond) != 0) !=
+			if (((ctx->fcr31 & cond) != 0) ==
 				((MIPSInst_FT(ir) & 1) != 0))
-				return 0;
-			SPFROMREG(rv.s, MIPSInst_FS(ir));
+				SPFROMREG(rv.s, MIPSInst_FS(ir));
 			break;
 		case fmovz_op:
-			if (xcp->regs[MIPSInst_FT(ir)] != 0)
-				return 0;
-			SPFROMREG(rv.s, MIPSInst_FS(ir));
+			if (xcp->regs[MIPSInst_FT(ir)] == 0)
+				SPFROMREG(rv.s, MIPSInst_FS(ir));
 			break;
 		case fmovn_op:
-			if (xcp->regs[MIPSInst_FT(ir)] == 0)
-				return 0;
-			SPFROMREG(rv.s, MIPSInst_FS(ir));
+			if (xcp->regs[MIPSInst_FT(ir)] != 0)
+				SPFROMREG(rv.s, MIPSInst_FS(ir));
 			break;
 #endif
 		case fabs_op:
@@ -1040,20 +1036,17 @@ static int fpu_emu(struct pt_regs *xcp, 
 #if __mips >= 4
 		case fmovc_op:
 			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
-			if (((ctx->fcr31 & cond) != 0) !=
+			if (((ctx->fcr31 & cond) != 0) ==
 				((MIPSInst_FT(ir) & 1) != 0))
-				return 0;
-			DPFROMREG(rv.d, MIPSInst_FS(ir));
+				DPFROMREG(rv.d, MIPSInst_FS(ir));
 			break;
 		case fmovz_op:
-			if (xcp->regs[MIPSInst_FT(ir)] != 0)
-				return 0;
-			DPFROMREG(rv.d, MIPSInst_FS(ir));
+			if (xcp->regs[MIPSInst_FT(ir)] == 0)
+				DPFROMREG(rv.d, MIPSInst_FS(ir));
 			break;
 		case fmovn_op:
-			if (xcp->regs[MIPSInst_FT(ir)] == 0)
-				return 0;
-			DPFROMREG(rv.d, MIPSInst_FS(ir));
+			if (xcp->regs[MIPSInst_FT(ir)] != 0)
+				DPFROMREG(rv.d, MIPSInst_FS(ir));
 			break;
 #endif
 		case fabs_op:


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux