[PATCH 37/48] MIPS: math-emu: Correct delay-slot exception propagation

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

 



Restore EPC at the branch whose delay slot is emulated if the delay-slot 
instruction signals.  This is so that code in `fpu_emulator_cop1Handler' 
does not see EPC having advanced and mistakenly successfully resume 
userland execution from the location at the branch target in that case.
Restoring EPC guarantees an immediate exit from the emulation loop and 
if EPC hasn't advanced at all since entering the loop, also issuing the 
signal reported by the delay-slot instruction.

Signed-off-by: Maciej W. Rozycki <macro@xxxxxxxxxxxxxx>
---
linux-mips-emu-bc1x-sigill.patch
Index: linux/arch/mips/math-emu/cp1emu.c
===================================================================
--- linux.orig/arch/mips/math-emu/cp1emu.c	2015-04-02 20:27:57.493218000 +0100
+++ linux/arch/mips/math-emu/cp1emu.c	2015-04-02 20:27:57.710224000 +0100
@@ -1134,6 +1134,14 @@ static int cop1Emulate(struct pt_regs *x
 				/*
 				 * Branch taken: emulate dslot instruction
 				 */
+				unsigned long bcpc;
+
+				/*
+				 * Remember EPC at the branch to point back
+				 * at so that any delay-slot instruction
+				 * signal is not silently ignored.
+				 */
+				bcpc = xcp->cp0_epc;
 				xcp->cp0_epc += dec_insn.pc_inc;
 
 				contpc = MIPSInst_SIMM(ir);
@@ -1159,7 +1167,15 @@ static int cop1Emulate(struct pt_regs *x
 						 * Single step the non-CP1
 						 * instruction in the dslot.
 						 */
-						return mips_dsemul(xcp, ir, contpc);
+						sig = mips_dsemul(xcp, ir,
+								  contpc);
+						if (sig)
+							xcp->cp0_epc = bcpc;
+						/*
+						 * SIGILL forces out of
+						 * the emulation loop.
+						 */
+						return sig ? sig : SIGILL;
 					}
 				} else
 					contpc = (xcp->cp0_epc + (contpc << 2));
@@ -1174,7 +1190,7 @@ static int cop1Emulate(struct pt_regs *x
 					if (cpu_has_mips_2_3_4_5_r)
 						goto emul;
 
-					return SIGILL;
+					goto bc_sigill;
 
 				case cop1_op:
 					goto emul;
@@ -1184,7 +1200,7 @@ static int cop1Emulate(struct pt_regs *x
 						/* its one of ours */
 						goto emul;
 
-					return SIGILL;
+					goto bc_sigill;
 
 				case spec_op:
 					switch (MIPSInst_FUNC(ir)) {
@@ -1192,16 +1208,24 @@ static int cop1Emulate(struct pt_regs *x
 						if (cpu_has_mips_4_5_r)
 							goto emul;
 
-						return SIGILL;
+						goto bc_sigill;
 					}
 					break;
+
+				bc_sigill:
+					xcp->cp0_epc = bcpc;
+					return SIGILL;
 				}
 
 				/*
 				 * Single step the non-cp1
 				 * instruction in the dslot
 				 */
-				return mips_dsemul(xcp, ir, contpc);
+				sig = mips_dsemul(xcp, ir, contpc);
+				if (sig)
+					xcp->cp0_epc = bcpc;
+				/* SIGILL forces out of the emulation loop.  */
+				return sig ? sig : SIGILL;
 			} else if (likely) {	/* branch not taken */
 				/*
 				 * branch likely nullifies
Index: linux/arch/mips/math-emu/dsemul.c
===================================================================
--- linux.orig/arch/mips/math-emu/dsemul.c	2015-04-02 20:27:57.133225000 +0100
+++ linux/arch/mips/math-emu/dsemul.c	2015-04-02 20:27:57.713219000 +0100
@@ -96,7 +96,7 @@ int mips_dsemul(struct pt_regs *regs, mi
 
 	flush_cache_sigtramp((unsigned long)&fr->emul);
 
-	return SIGILL;		/* force out of emulation loop */
+	return 0;
 }
 
 int do_dsemulret(struct pt_regs *xcp)





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

  Powered by Linux