MIPS R6 added the following four instructions which share the BLEZ and BLEZL opcodes: BLEZALC: Compact branch-and-link if GPR rt is <= to zero BGEZALC: Compact branch-and-link if GPR rt is >= to zero BLEZC: Compact branch if GPR rt is < to zero BGEZC: Compact branch if GPR rt is > to zero Signed-off-by: Markos Chandras <markos.chandras@xxxxxxxxxx> --- arch/mips/kernel/branch.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index e6d78ab52aa7..7bc2df026b51 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -402,6 +402,16 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs) * @returns: -EFAULT on error and forces SIGBUS, and on success * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after * evaluating the branch. + * + * MIPS R6 Compact branches and forbidden slots: + * Compact branches do not throw exceptions because they do + * not have delay slots. The forbidden slot instruction ($PC+4) + * is only executed if the branch was not taken. Otherwise the + * forbidden slot is skipped entirely. This means that they + * only possible reason to be here because of a MIPS R6 compact + * branch instruction is that the forbidden slot has thrown one. + * In that case the branch was not taken, so the EPC can be safely + * set to EPC + 8. */ int __compute_return_epc_for_insn(struct pt_regs *regs, union mips_instruction insn) @@ -609,6 +619,18 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ret = -SIGILL; break; } + /* blezalc, bgezalc, blezc, bgezc */ + if (cpu_has_mips_r6) { + if (insn.i_format.rt) { + if (insn.i_format.opcode == blez_op) + if ((insn.i_format.rs == + insn.i_format.rt) || + !insn.i_format.rs) + regs->regs[31] = epc + 4; + regs->cp0_epc += 8; + break; + } + } /* rt field assumed to be zero */ if ((long)regs->regs[insn.i_format.rs] <= 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); -- 2.2.0