diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/include/uapi/asm/inst.h | 8 | ||||
-rw-r--r-- | arch/mips/math-emu/dsemul.c | 24 |
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); /* |