Commit 9ab4471c authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Ralf Baechle

MIPS: math-emu: Correct delay-slot exception propagation

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: default avatarMaciej W. Rozycki <macro@linux-mips.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/9701/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 2d83fea7
...@@ -1134,6 +1134,14 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -1134,6 +1134,14 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
/* /*
* Branch taken: emulate dslot instruction * 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; xcp->cp0_epc += dec_insn.pc_inc;
contpc = MIPSInst_SIMM(ir); contpc = MIPSInst_SIMM(ir);
...@@ -1159,7 +1167,15 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -1159,7 +1167,15 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
* Single step the non-CP1 * Single step the non-CP1
* instruction in the dslot. * 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 } else
contpc = (xcp->cp0_epc + (contpc << 2)); contpc = (xcp->cp0_epc + (contpc << 2));
...@@ -1174,7 +1190,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -1174,7 +1190,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (cpu_has_mips_2_3_4_5_r) if (cpu_has_mips_2_3_4_5_r)
goto emul; goto emul;
return SIGILL; goto bc_sigill;
case cop1_op: case cop1_op:
goto emul; goto emul;
...@@ -1184,7 +1200,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -1184,7 +1200,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
/* its one of ours */ /* its one of ours */
goto emul; goto emul;
return SIGILL; goto bc_sigill;
case spec_op: case spec_op:
switch (MIPSInst_FUNC(ir)) { switch (MIPSInst_FUNC(ir)) {
...@@ -1192,16 +1208,24 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -1192,16 +1208,24 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (cpu_has_mips_4_5_r) if (cpu_has_mips_4_5_r)
goto emul; goto emul;
return SIGILL; goto bc_sigill;
} }
break; break;
bc_sigill:
xcp->cp0_epc = bcpc;
return SIGILL;
} }
/* /*
* Single step the non-cp1 * Single step the non-cp1
* instruction in the dslot * 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 */ } else if (likely) { /* branch not taken */
/* /*
* branch likely nullifies * branch likely nullifies
......
...@@ -96,7 +96,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) ...@@ -96,7 +96,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
flush_cache_sigtramp((unsigned long)&fr->emul); flush_cache_sigtramp((unsigned long)&fr->emul);
return SIGILL; /* force out of emulation loop */ return 0;
} }
int do_dsemulret(struct pt_regs *xcp) int do_dsemulret(struct pt_regs *xcp)
......
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