Skip to content

Commit

Permalink
MIPS: math-emu: Correct the emulation of microMIPS ADDIUPC instruction
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Maciej W. Rozycki authored and Ralf Baechle committed Jan 24, 2016
1 parent 733b8bc commit 69a1e6c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
8 changes: 8 additions & 0 deletions arch/mips/include/uapi/asm/inst.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
*/
Expand Down Expand Up @@ -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 ;
Expand Down
24 changes: 22 additions & 2 deletions arch/mips/math-emu/dsemul.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/*
Expand Down

0 comments on commit 69a1e6c

Please sign in to comment.