diff options
-rw-r--r-- | arch/mips/kernel/branch.c | 31 | ||||
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 24 |
2 files changed, 55 insertions, 0 deletions
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index f9cb13c56595..a1fd8786d716 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c | |||
@@ -399,6 +399,16 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs) | |||
399 | * @returns: -EFAULT on error and forces SIGBUS, and on success | 399 | * @returns: -EFAULT on error and forces SIGBUS, and on success |
400 | * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after | 400 | * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after |
401 | * evaluating the branch. | 401 | * evaluating the branch. |
402 | * | ||
403 | * MIPS R6 Compact branches and forbidden slots: | ||
404 | * Compact branches do not throw exceptions because they do | ||
405 | * not have delay slots. The forbidden slot instruction ($PC+4) | ||
406 | * is only executed if the branch was not taken. Otherwise the | ||
407 | * forbidden slot is skipped entirely. This means that the | ||
408 | * only possible reason to be here because of a MIPS R6 compact | ||
409 | * branch instruction is that the forbidden slot has thrown one. | ||
410 | * In that case the branch was not taken, so the EPC can be safely | ||
411 | * set to EPC + 8. | ||
402 | */ | 412 | */ |
403 | int __compute_return_epc_for_insn(struct pt_regs *regs, | 413 | int __compute_return_epc_for_insn(struct pt_regs *regs, |
404 | union mips_instruction insn) | 414 | union mips_instruction insn) |
@@ -590,6 +600,27 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
590 | if (NO_R6EMU) | 600 | if (NO_R6EMU) |
591 | goto sigill_r6; | 601 | goto sigill_r6; |
592 | case blez_op: | 602 | case blez_op: |
603 | /* | ||
604 | * Compact branches for R6 for the | ||
605 | * blez and blezl opcodes. | ||
606 | * BLEZ | rs = 0 | rt != 0 == BLEZALC | ||
607 | * BLEZ | rs = rt != 0 == BGEZALC | ||
608 | * BLEZ | rs != 0 | rt != 0 == BGEUC | ||
609 | * BLEZL | rs = 0 | rt != 0 == BLEZC | ||
610 | * BLEZL | rs = rt != 0 == BGEZC | ||
611 | * BLEZL | rs != 0 | rt != 0 == BGEC | ||
612 | * | ||
613 | * For real BLEZ{,L}, rt is always 0. | ||
614 | */ | ||
615 | |||
616 | if (cpu_has_mips_r6 && insn.i_format.rt) { | ||
617 | if ((insn.i_format.opcode == blez_op) && | ||
618 | ((!insn.i_format.rs && insn.i_format.rt) || | ||
619 | (insn.i_format.rs == insn.i_format.rt))) | ||
620 | regs->regs[31] = epc + 4; | ||
621 | regs->cp0_epc += 8; | ||
622 | break; | ||
623 | } | ||
593 | /* rt field assumed to be zero */ | 624 | /* rt field assumed to be zero */ |
594 | if ((long)regs->regs[insn.i_format.rs] <= 0) { | 625 | if ((long)regs->regs[insn.i_format.rs] <= 0) { |
595 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 626 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 798204e492fc..c770617dc340 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c | |||
@@ -552,6 +552,30 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
552 | if (NO_R6EMU) | 552 | if (NO_R6EMU) |
553 | break; | 553 | break; |
554 | case blez_op: | 554 | case blez_op: |
555 | |||
556 | /* | ||
557 | * Compact branches for R6 for the | ||
558 | * blez and blezl opcodes. | ||
559 | * BLEZ | rs = 0 | rt != 0 == BLEZALC | ||
560 | * BLEZ | rs = rt != 0 == BGEZALC | ||
561 | * BLEZ | rs != 0 | rt != 0 == BGEUC | ||
562 | * BLEZL | rs = 0 | rt != 0 == BLEZC | ||
563 | * BLEZL | rs = rt != 0 == BGEZC | ||
564 | * BLEZL | rs != 0 | rt != 0 == BGEC | ||
565 | * | ||
566 | * For real BLEZ{,L}, rt is always 0. | ||
567 | */ | ||
568 | if (cpu_has_mips_r6 && insn.i_format.rt) { | ||
569 | if ((insn.i_format.opcode == blez_op) && | ||
570 | ((!insn.i_format.rs && insn.i_format.rt) || | ||
571 | (insn.i_format.rs == insn.i_format.rt))) | ||
572 | regs->regs[31] = regs->cp0_epc + | ||
573 | dec_insn.pc_inc; | ||
574 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
575 | dec_insn.next_pc_inc; | ||
576 | |||
577 | return 1; | ||
578 | } | ||
555 | if ((long)regs->regs[insn.i_format.rs] <= 0) | 579 | if ((long)regs->regs[insn.i_format.rs] <= 0) |
556 | *contpc = regs->cp0_epc + | 580 | *contpc = regs->cp0_epc + |
557 | dec_insn.pc_inc + | 581 | dec_insn.pc_inc + |