The MIPS R6 JR instruction is an alias to the JALR one, so it may need emulation for non-R6 userlands. Signed-off-by: Markos Chandras <markos.chandras@xxxxxxxxxx> --- arch/mips/include/asm/branch.h | 3 +++ arch/mips/kernel/branch.c | 5 +++++ arch/mips/math-emu/cp1emu.c | 3 +++ 3 files changed, 11 insertions(+) diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h index de781cf54bc7..2894ea58454d 100644 --- a/arch/mips/include/asm/branch.h +++ b/arch/mips/include/asm/branch.h @@ -13,6 +13,9 @@ #include <asm/ptrace.h> #include <asm/inst.h> +static int mipsr2_emulation = 0; +#define NO_R6EMU (cpu_has_mips_r6 && !mipsr2_emulation) + extern int __isa_exception_epc(struct pt_regs *regs); extern int __compute_return_epc(struct pt_regs *regs); extern int __compute_return_epc_for_insn(struct pt_regs *regs, diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 4d7d99d601cc..9b622ca391d8 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -417,6 +417,11 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, regs->regs[insn.r_format.rd] = epc + 8; /* Fall through */ case jr_op: + if (NO_R6EMU && (insn.r_format.func == jr_op)) { + ret = -SIGILL; + /* For R6, JR already emulated in jalr_op */ + break; + } regs->cp0_epc = regs->regs[insn.r_format.rs]; break; } diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 9dfcd7fc1bc3..9707af43913f 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -448,6 +448,9 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, dec_insn.next_pc_inc; /* Fall through */ case jr_op: + /* For R6, JR already emulated in jalr_op */ + if (NO_R6EMU && (insn.r_format.opcode == jr_op)) + break; *contpc = regs->regs[insn.r_format.rs]; return 1; } -- 2.2.1