Commit 319824ea authored by Markos Chandras's avatar Markos Chandras

MIPS: kernel: branch: Do not emulate the branch likelies on MIPS R6

MIPS R6 removed the BLTZL, BGEZL, BLTZAL, BGEZAL, BEQL, BNEL, BLEZL,
BGTZL branch likely instructions so we must not try to emulate them on
MIPS R6 if the R2-to-R6 emulator is not present.
Signed-off-by: default avatarMarkos Chandras <markos.chandras@imgtec.com>
parent 5f9f41c4
...@@ -431,8 +431,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -431,8 +431,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
*/ */
case bcond_op: case bcond_op:
switch (insn.i_format.rt) { switch (insn.i_format.rt) {
case bltz_op:
case bltzl_op: case bltzl_op:
if (NO_R6EMU)
goto sigill_r6;
case bltz_op:
if ((long)regs->regs[insn.i_format.rs] < 0) { if ((long)regs->regs[insn.i_format.rs] < 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2); epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bltzl_op) if (insn.i_format.rt == bltzl_op)
...@@ -442,8 +444,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -442,8 +444,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->cp0_epc = epc; regs->cp0_epc = epc;
break; break;
case bgez_op:
case bgezl_op: case bgezl_op:
if (NO_R6EMU)
goto sigill_r6;
case bgez_op:
if ((long)regs->regs[insn.i_format.rs] >= 0) { if ((long)regs->regs[insn.i_format.rs] >= 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2); epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bgezl_op) if (insn.i_format.rt == bgezl_op)
...@@ -455,7 +459,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -455,7 +459,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
case bltzal_op: case bltzal_op:
case bltzall_op: case bltzall_op:
if (NO_R6EMU && (insn.i_format.rs ||
insn.i_format.rt == bltzall_op)) {
ret = -SIGILL;
break;
}
regs->regs[31] = epc + 8; regs->regs[31] = epc + 8;
/*
* OK we are here either because we hit a NAL
* instruction or because we are emulating an
* old bltzal{,l} one. Lets figure out what the
* case really is.
*/
if (!insn.i_format.rs) {
/*
* NAL or BLTZAL with rs == 0
* Doesn't matter if we are R6 or not. The
* result is the same
*/
regs->cp0_epc += 4 +
(insn.i_format.simmediate << 2);
break;
}
/* Now do the real thing for non-R6 BLTZAL{,L} */
if ((long)regs->regs[insn.i_format.rs] < 0) { if ((long)regs->regs[insn.i_format.rs] < 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2); epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bltzall_op) if (insn.i_format.rt == bltzall_op)
...@@ -467,7 +493,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -467,7 +493,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
case bgezal_op: case bgezal_op:
case bgezall_op: case bgezall_op:
if (NO_R6EMU && (insn.i_format.rs ||
insn.i_format.rt == bgezall_op)) {
ret = -SIGILL;
break;
}
regs->regs[31] = epc + 8; regs->regs[31] = epc + 8;
/*
* OK we are here either because we hit a BAL
* instruction or because we are emulating an
* old bgezal{,l} one. Lets figure out what the
* case really is.
*/
if (!insn.i_format.rs) {
/*
* BAL or BGEZAL with rs == 0
* Doesn't matter if we are R6 or not. The
* result is the same
*/
regs->cp0_epc += 4 +
(insn.i_format.simmediate << 2);
break;
}
/* Now do the real thing for non-R6 BGEZAL{,L} */
if ((long)regs->regs[insn.i_format.rs] >= 0) { if ((long)regs->regs[insn.i_format.rs] >= 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2); epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bgezall_op) if (insn.i_format.rt == bgezall_op)
...@@ -510,8 +558,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -510,8 +558,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
/* /*
* These are conditional and in i_format. * These are conditional and in i_format.
*/ */
case beq_op:
case beql_op: case beql_op:
if (NO_R6EMU)
goto sigill_r6;
case beq_op:
if (regs->regs[insn.i_format.rs] == if (regs->regs[insn.i_format.rs] ==
regs->regs[insn.i_format.rt]) { regs->regs[insn.i_format.rt]) {
epc = epc + 4 + (insn.i_format.simmediate << 2); epc = epc + 4 + (insn.i_format.simmediate << 2);
...@@ -522,8 +572,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -522,8 +572,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->cp0_epc = epc; regs->cp0_epc = epc;
break; break;
case bne_op:
case bnel_op: case bnel_op:
if (NO_R6EMU)
goto sigill_r6;
case bne_op:
if (regs->regs[insn.i_format.rs] != if (regs->regs[insn.i_format.rs] !=
regs->regs[insn.i_format.rt]) { regs->regs[insn.i_format.rt]) {
epc = epc + 4 + (insn.i_format.simmediate << 2); epc = epc + 4 + (insn.i_format.simmediate << 2);
...@@ -534,8 +586,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -534,8 +586,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->cp0_epc = epc; regs->cp0_epc = epc;
break; break;
case blez_op: /* not really i_format */ case blezl_op: /* not really i_format */
case blezl_op: if (NO_R6EMU)
goto sigill_r6;
case blez_op:
/* rt field assumed to be zero */ /* rt field assumed to be zero */
if ((long)regs->regs[insn.i_format.rs] <= 0) { if ((long)regs->regs[insn.i_format.rs] <= 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2); epc = epc + 4 + (insn.i_format.simmediate << 2);
...@@ -546,8 +600,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -546,8 +600,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->cp0_epc = epc; regs->cp0_epc = epc;
break; break;
case bgtz_op:
case bgtzl_op: case bgtzl_op:
if (NO_R6EMU)
goto sigill_r6;
case bgtz_op:
/* rt field assumed to be zero */ /* rt field assumed to be zero */
if ((long)regs->regs[insn.i_format.rs] > 0) { if ((long)regs->regs[insn.i_format.rs] > 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2); epc = epc + 4 + (insn.i_format.simmediate << 2);
......
...@@ -459,12 +459,18 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, ...@@ -459,12 +459,18 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
switch (insn.i_format.rt) { switch (insn.i_format.rt) {
case bltzal_op: case bltzal_op:
case bltzall_op: case bltzall_op:
if (NO_R6EMU && (insn.i_format.rs ||
insn.i_format.rt == bltzall_op))
break;
regs->regs[31] = regs->cp0_epc + regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.pc_inc +
dec_insn.next_pc_inc; dec_insn.next_pc_inc;
/* Fall through */ /* Fall through */
case bltz_op:
case bltzl_op: case bltzl_op:
if (NO_R6EMU)
break;
case bltz_op:
if ((long)regs->regs[insn.i_format.rs] < 0) if ((long)regs->regs[insn.i_format.rs] < 0)
*contpc = regs->cp0_epc + *contpc = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.pc_inc +
...@@ -476,12 +482,18 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, ...@@ -476,12 +482,18 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
return 1; return 1;
case bgezal_op: case bgezal_op:
case bgezall_op: case bgezall_op:
if (NO_R6EMU && (insn.i_format.rs ||
insn.i_format.rt == bgezall_op))
break;
regs->regs[31] = regs->cp0_epc + regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.pc_inc +
dec_insn.next_pc_inc; dec_insn.next_pc_inc;
/* Fall through */ /* Fall through */
case bgez_op:
case bgezl_op: case bgezl_op:
if (NO_R6EMU)
break;
case bgez_op:
if ((long)regs->regs[insn.i_format.rs] >= 0) if ((long)regs->regs[insn.i_format.rs] >= 0)
*contpc = regs->cp0_epc + *contpc = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.pc_inc +
...@@ -508,8 +520,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, ...@@ -508,8 +520,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
/* Set microMIPS mode bit: XOR for jalx. */ /* Set microMIPS mode bit: XOR for jalx. */
*contpc ^= bit; *contpc ^= bit;
return 1; return 1;
case beq_op:
case beql_op: case beql_op:
if (NO_R6EMU)
break;
case beq_op:
if (regs->regs[insn.i_format.rs] == if (regs->regs[insn.i_format.rs] ==
regs->regs[insn.i_format.rt]) regs->regs[insn.i_format.rt])
*contpc = regs->cp0_epc + *contpc = regs->cp0_epc +
...@@ -520,8 +534,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, ...@@ -520,8 +534,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.pc_inc + dec_insn.pc_inc +
dec_insn.next_pc_inc; dec_insn.next_pc_inc;
return 1; return 1;
case bne_op:
case bnel_op: case bnel_op:
if (NO_R6EMU)
break;
case bne_op:
if (regs->regs[insn.i_format.rs] != if (regs->regs[insn.i_format.rs] !=
regs->regs[insn.i_format.rt]) regs->regs[insn.i_format.rt])
*contpc = regs->cp0_epc + *contpc = regs->cp0_epc +
...@@ -532,8 +548,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, ...@@ -532,8 +548,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.pc_inc + dec_insn.pc_inc +
dec_insn.next_pc_inc; dec_insn.next_pc_inc;
return 1; return 1;
case blez_op:
case blezl_op: case blezl_op:
if (NO_R6EMU)
break;
case blez_op:
if ((long)regs->regs[insn.i_format.rs] <= 0) if ((long)regs->regs[insn.i_format.rs] <= 0)
*contpc = regs->cp0_epc + *contpc = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.pc_inc +
...@@ -543,8 +561,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, ...@@ -543,8 +561,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.pc_inc + dec_insn.pc_inc +
dec_insn.next_pc_inc; dec_insn.next_pc_inc;
return 1; return 1;
case bgtz_op:
case bgtzl_op: case bgtzl_op:
if (NO_R6EMU)
break;
case bgtz_op:
if ((long)regs->regs[insn.i_format.rs] > 0) if ((long)regs->regs[insn.i_format.rs] > 0)
*contpc = regs->cp0_epc + *contpc = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.pc_inc +
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment