| Message ID | - |
|---|---|
| State | Accepted |
| Delegated to: | Ralf Baechle |
| Headers | show |
| Series |
|
| Related | show |
On Mon, Mar 13, 2017 at 04:36:35PM +0100, Aleksandar Markovic wrote: > From: Leonid Yegoshin <> > > Fix the problem of inaccurate identification of instructions BLEZL and > BGTZL in R2 emulation code by making sure all necessary encoding > specifications are met. > > Previously, certain R6 instructions could be identified as BLEZL or > BGTZL. R2 emulation routine didn't take into account that both BLEZL > and BGTZL instructions require their rt field (bits 20 to 16 of > instruction encoding) to be 0, and that, at same time, if the value in > that field is not 0, the encoding may represent a legitimate MIPS R6 > instruction. > > This means that a problem could occur after emulation optimization, > when emulation routine tried to pipeline emulation, picked up a next > candidate, and subsequently misrecognized an R6 instruction as BLEZL > or BGTZL. > > It should be said that for single pass strategy, the problem does not > happen because CPU doesn't trap on branch-compacts which share opcode > space with BLEZL/BGTZL (but have rt field != 0, of course). > > Signed-off-by: Leonid Yegoshin <> > Signed-off-by: Miodrag Dinic <> > Signed-off-by: Aleksandar Markovic <> > Reported-by: Douglas Leung <> > Reviewed-by: Paul Burton <> Thanks for sorting out the review comments on v1. Applied, Ralf
diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index ef2ca28..8fb4eac 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -1096,10 +1096,20 @@ int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31) } break; - case beql_op: - case bnel_op: case blezl_op: case bgtzl_op: + /* + * For BLEZL and BGTZL, rt field must be set to 0. If this + * is not the case, this may be an encoding of a MIPS R6 + * instruction, so return to CPU execution if this occurs + */ + if (MIPSInst_RT(inst)) { + err = SIGILL; + break; + } + /* fall through */ + case beql_op: + case bnel_op: if (delay_slot(regs)) { err = SIGILL; break;