summaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@imgtec.com>2016-01-22 05:21:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2016-01-24 01:36:10 +0100
commit69a1e6cbdf1f40d5dcae84c5a538d390b6d2c307 (patch)
tree5cfd41a53625d104620bb267345d0ecac2798f8a /arch/mips
parent733b8bc183f491e8263009edf8ef184fb44a6882 (diff)
downloadlinux-69a1e6cbdf1f40d5dcae84c5a538d390b6d2c307.tar.bz2
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 <macro@imgtec.com> Cc: Aurelien Jarno <aurelien@aurel32.net> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12175/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/include/uapi/asm/inst.h8
-rw-r--r--arch/mips/math-emu/dsemul.c24
2 files changed, 30 insertions, 2 deletions
diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
index 9b44d5a816fa..b145749c743f 100644
--- a/arch/mips/include/uapi/asm/inst.h
+++ b/arch/mips/include/uapi/asm/inst.h
@@ -799,6 +799,13 @@ struct mm_x_format { /* Scaled indexed load format (microMIPS) */
;)))))
};
+struct mm_a_format { /* ADDIUPC format (microMIPS) */
+ __BITFIELD_FIELD(unsigned int opcode : 6,
+ __BITFIELD_FIELD(unsigned int rs : 3,
+ __BITFIELD_FIELD(signed int simmediate : 23,
+ ;)))
+};
+
/*
* microMIPS instruction formats (16-bit length)
*/
@@ -940,6 +947,7 @@ union mips_instruction {
struct mm_i_format mm_i_format;
struct mm_m_format mm_m_format;
struct mm_x_format mm_x_format;
+ struct mm_a_format mm_a_format;
struct mm_b0_format mm_b0_format;
struct mm_b1_format mm_b1_format;
struct mm16_m_format mm16_m_format ;
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);
/*