From 69a1e6cbdf1f40d5dcae84c5a538d390b6d2c307 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 22 Jan 2016 05:21:00 +0000 Subject: MIPS: math-emu: Correct the emulation of microMIPS ADDIUPC instruction Emulate the microMIPS ADDIUPC instruction directly in `mips_dsemul'. If executed in the emulation frame, this instruction produces an incorrect result, because the value of the PC there is not the same as where the instruction originated. Reshape code so as to handle all microMIPS cases together. Signed-off-by: Maciej W. Rozycki Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12175/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/dsemul.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'arch/mips/math-emu/dsemul.c') diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 32ec5d7e1728..77a623db3b38 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -43,10 +43,30 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) int err; /* NOP is easy */ - if ((get_isa16_mode(regs->cp0_epc) && ((ir >> 16) == MM_NOP16)) || - (ir == 0)) + if (ir == 0) return -1; + /* microMIPS instructions */ + if (get_isa16_mode(regs->cp0_epc)) { + union mips_instruction insn = { .word = ir }; + + /* NOP16 aka MOVE16 $0, $0 */ + if ((ir >> 16) == MM_NOP16) + return -1; + + /* ADDIUPC */ + if (insn.mm_a_format.opcode == mm_addiupc_op) { + unsigned int rs; + s32 v; + + rs = (((insn.mm_a_format.rs + 0x1e) & 0xf) + 2); + v = regs->cp0_epc & ~3; + v += insn.mm_a_format.simmediate << 2; + regs->regs[rs] = (long)v; + return -1; + } + } + pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc); /* -- cgit