aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/branch.c
diff options
context:
space:
mode:
authorMarkos Chandras <markos.chandras@imgtec.com>2014-11-25 11:02:23 -0500
committerMarkos Chandras <markos.chandras@imgtec.com>2015-02-17 10:37:32 -0500
commit319824eabc3f1c1aab67f408d66f384fbb996ee2 (patch)
tree260bbaa71db86705f735b6c9e45bf32aad95c420 /arch/mips/kernel/branch.c
parent5f9f41c474befb4ebbc40b27f65bb7d649241581 (diff)
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: Markos Chandras <markos.chandras@imgtec.com>
Diffstat (limited to 'arch/mips/kernel/branch.c')
-rw-r--r--arch/mips/kernel/branch.c70
1 files changed, 63 insertions, 7 deletions
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index 5736949896d1..5121adaa34bd 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -431,8 +431,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
431 */ 431 */
432 case bcond_op: 432 case bcond_op:
433 switch (insn.i_format.rt) { 433 switch (insn.i_format.rt) {
434 case bltz_op:
435 case bltzl_op: 434 case bltzl_op:
435 if (NO_R6EMU)
436 goto sigill_r6;
437 case bltz_op:
436 if ((long)regs->regs[insn.i_format.rs] < 0) { 438 if ((long)regs->regs[insn.i_format.rs] < 0) {
437 epc = epc + 4 + (insn.i_format.simmediate << 2); 439 epc = epc + 4 + (insn.i_format.simmediate << 2);
438 if (insn.i_format.rt == bltzl_op) 440 if (insn.i_format.rt == bltzl_op)
@@ -442,8 +444,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
442 regs->cp0_epc = epc; 444 regs->cp0_epc = epc;
443 break; 445 break;
444 446
445 case bgez_op:
446 case bgezl_op: 447 case bgezl_op:
448 if (NO_R6EMU)
449 goto sigill_r6;
450 case bgez_op:
447 if ((long)regs->regs[insn.i_format.rs] >= 0) { 451 if ((long)regs->regs[insn.i_format.rs] >= 0) {
448 epc = epc + 4 + (insn.i_format.simmediate << 2); 452 epc = epc + 4 + (insn.i_format.simmediate << 2);
449 if (insn.i_format.rt == bgezl_op) 453 if (insn.i_format.rt == bgezl_op)
@@ -455,7 +459,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
455 459
456 case bltzal_op: 460 case bltzal_op:
457 case bltzall_op: 461 case bltzall_op:
462 if (NO_R6EMU && (insn.i_format.rs ||
463 insn.i_format.rt == bltzall_op)) {
464 ret = -SIGILL;
465 break;
466 }
458 regs->regs[31] = epc + 8; 467 regs->regs[31] = epc + 8;
468 /*
469 * OK we are here either because we hit a NAL
470 * instruction or because we are emulating an
471 * old bltzal{,l} one. Lets figure out what the
472 * case really is.
473 */
474 if (!insn.i_format.rs) {
475 /*
476 * NAL or BLTZAL with rs == 0
477 * Doesn't matter if we are R6 or not. The
478 * result is the same
479 */
480 regs->cp0_epc += 4 +
481 (insn.i_format.simmediate << 2);
482 break;
483 }
484 /* Now do the real thing for non-R6 BLTZAL{,L} */
459 if ((long)regs->regs[insn.i_format.rs] < 0) { 485 if ((long)regs->regs[insn.i_format.rs] < 0) {
460 epc = epc + 4 + (insn.i_format.simmediate << 2); 486 epc = epc + 4 + (insn.i_format.simmediate << 2);
461 if (insn.i_format.rt == bltzall_op) 487 if (insn.i_format.rt == bltzall_op)
@@ -467,7 +493,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
467 493
468 case bgezal_op: 494 case bgezal_op:
469 case bgezall_op: 495 case bgezall_op:
496 if (NO_R6EMU && (insn.i_format.rs ||
497 insn.i_format.rt == bgezall_op)) {
498 ret = -SIGILL;
499 break;
500 }
470 regs->regs[31] = epc + 8; 501 regs->regs[31] = epc + 8;
502 /*
503 * OK we are here either because we hit a BAL
504 * instruction or because we are emulating an
505 * old bgezal{,l} one. Lets figure out what the
506 * case really is.
507 */
508 if (!insn.i_format.rs) {
509 /*
510 * BAL or BGEZAL with rs == 0
511 * Doesn't matter if we are R6 or not. The
512 * result is the same
513 */
514 regs->cp0_epc += 4 +
515 (insn.i_format.simmediate << 2);
516 break;
517 }
518 /* Now do the real thing for non-R6 BGEZAL{,L} */
471 if ((long)regs->regs[insn.i_format.rs] >= 0) { 519 if ((long)regs->regs[insn.i_format.rs] >= 0) {
472 epc = epc + 4 + (insn.i_format.simmediate << 2); 520 epc = epc + 4 + (insn.i_format.simmediate << 2);
473 if (insn.i_format.rt == bgezall_op) 521 if (insn.i_format.rt == bgezall_op)
@@ -510,8 +558,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
510 /* 558 /*
511 * These are conditional and in i_format. 559 * These are conditional and in i_format.
512 */ 560 */
513 case beq_op:
514 case beql_op: 561 case beql_op:
562 if (NO_R6EMU)
563 goto sigill_r6;
564 case beq_op:
515 if (regs->regs[insn.i_format.rs] == 565 if (regs->regs[insn.i_format.rs] ==
516 regs->regs[insn.i_format.rt]) { 566 regs->regs[insn.i_format.rt]) {
517 epc = epc + 4 + (insn.i_format.simmediate << 2); 567 epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -522,8 +572,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
522 regs->cp0_epc = epc; 572 regs->cp0_epc = epc;
523 break; 573 break;
524 574
525 case bne_op:
526 case bnel_op: 575 case bnel_op:
576 if (NO_R6EMU)
577 goto sigill_r6;
578 case bne_op:
527 if (regs->regs[insn.i_format.rs] != 579 if (regs->regs[insn.i_format.rs] !=
528 regs->regs[insn.i_format.rt]) { 580 regs->regs[insn.i_format.rt]) {
529 epc = epc + 4 + (insn.i_format.simmediate << 2); 581 epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -534,8 +586,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
534 regs->cp0_epc = epc; 586 regs->cp0_epc = epc;
535 break; 587 break;
536 588
537 case blez_op: /* not really i_format */ 589 case blezl_op: /* not really i_format */
538 case blezl_op: 590 if (NO_R6EMU)
591 goto sigill_r6;
592 case blez_op:
539 /* rt field assumed to be zero */ 593 /* rt field assumed to be zero */
540 if ((long)regs->regs[insn.i_format.rs] <= 0) { 594 if ((long)regs->regs[insn.i_format.rs] <= 0) {
541 epc = epc + 4 + (insn.i_format.simmediate << 2); 595 epc = epc + 4 + (insn.i_format.simmediate << 2);
@@ -546,8 +600,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
546 regs->cp0_epc = epc; 600 regs->cp0_epc = epc;
547 break; 601 break;
548 602
549 case bgtz_op:
550 case bgtzl_op: 603 case bgtzl_op:
604 if (NO_R6EMU)
605 goto sigill_r6;
606 case bgtz_op:
551 /* rt field assumed to be zero */ 607 /* rt field assumed to be zero */
552 if ((long)regs->regs[insn.i_format.rs] > 0) { 608 if ((long)regs->regs[insn.i_format.rs] > 0) {
553 epc = epc + 4 + (insn.i_format.simmediate << 2); 609 epc = epc + 4 + (insn.i_format.simmediate << 2);