diff options
Diffstat (limited to 'arch/mips/kernel/branch.c')
-rw-r--r-- | arch/mips/kernel/branch.c | 70 |
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); |