diff options
Diffstat (limited to 'arch/mips/kernel/branch.c')
-rw-r--r-- | arch/mips/kernel/branch.c | 288 |
1 files changed, 250 insertions, 38 deletions
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 4d7d99d601cc..c2e0f45ddf6c 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/fpu.h> | 16 | #include <asm/fpu.h> |
17 | #include <asm/fpu_emulator.h> | 17 | #include <asm/fpu_emulator.h> |
18 | #include <asm/inst.h> | 18 | #include <asm/inst.h> |
19 | #include <asm/mips-r2-to-r6-emul.h> | ||
19 | #include <asm/ptrace.h> | 20 | #include <asm/ptrace.h> |
20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
21 | 22 | ||
@@ -399,11 +400,21 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs) | |||
399 | * @returns: -EFAULT on error and forces SIGBUS, and on success | 400 | * @returns: -EFAULT on error and forces SIGBUS, and on success |
400 | * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after | 401 | * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after |
401 | * evaluating the branch. | 402 | * evaluating the branch. |
403 | * | ||
404 | * MIPS R6 Compact branches and forbidden slots: | ||
405 | * Compact branches do not throw exceptions because they do | ||
406 | * not have delay slots. The forbidden slot instruction ($PC+4) | ||
407 | * is only executed if the branch was not taken. Otherwise the | ||
408 | * forbidden slot is skipped entirely. This means that the | ||
409 | * only possible reason to be here because of a MIPS R6 compact | ||
410 | * branch instruction is that the forbidden slot has thrown one. | ||
411 | * In that case the branch was not taken, so the EPC can be safely | ||
412 | * set to EPC + 8. | ||
402 | */ | 413 | */ |
403 | int __compute_return_epc_for_insn(struct pt_regs *regs, | 414 | int __compute_return_epc_for_insn(struct pt_regs *regs, |
404 | union mips_instruction insn) | 415 | union mips_instruction insn) |
405 | { | 416 | { |
406 | unsigned int bit, fcr31, dspcontrol; | 417 | unsigned int bit, fcr31, dspcontrol, reg; |
407 | long epc = regs->cp0_epc; | 418 | long epc = regs->cp0_epc; |
408 | int ret = 0; | 419 | int ret = 0; |
409 | 420 | ||
@@ -417,6 +428,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
417 | regs->regs[insn.r_format.rd] = epc + 8; | 428 | regs->regs[insn.r_format.rd] = epc + 8; |
418 | /* Fall through */ | 429 | /* Fall through */ |
419 | case jr_op: | 430 | case jr_op: |
431 | if (NO_R6EMU && insn.r_format.func == jr_op) | ||
432 | goto sigill_r6; | ||
420 | regs->cp0_epc = regs->regs[insn.r_format.rs]; | 433 | regs->cp0_epc = regs->regs[insn.r_format.rs]; |
421 | break; | 434 | break; |
422 | } | 435 | } |
@@ -429,8 +442,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
429 | */ | 442 | */ |
430 | case bcond_op: | 443 | case bcond_op: |
431 | switch (insn.i_format.rt) { | 444 | switch (insn.i_format.rt) { |
432 | case bltz_op: | ||
433 | case bltzl_op: | 445 | case bltzl_op: |
446 | if (NO_R6EMU) | ||
447 | goto sigill_r6; | ||
448 | case bltz_op: | ||
434 | if ((long)regs->regs[insn.i_format.rs] < 0) { | 449 | if ((long)regs->regs[insn.i_format.rs] < 0) { |
435 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 450 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
436 | if (insn.i_format.rt == bltzl_op) | 451 | if (insn.i_format.rt == bltzl_op) |
@@ -440,8 +455,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
440 | regs->cp0_epc = epc; | 455 | regs->cp0_epc = epc; |
441 | break; | 456 | break; |
442 | 457 | ||
443 | case bgez_op: | ||
444 | case bgezl_op: | 458 | case bgezl_op: |
459 | if (NO_R6EMU) | ||
460 | goto sigill_r6; | ||
461 | case bgez_op: | ||
445 | if ((long)regs->regs[insn.i_format.rs] >= 0) { | 462 | if ((long)regs->regs[insn.i_format.rs] >= 0) { |
446 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 463 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
447 | if (insn.i_format.rt == bgezl_op) | 464 | if (insn.i_format.rt == bgezl_op) |
@@ -453,7 +470,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
453 | 470 | ||
454 | case bltzal_op: | 471 | case bltzal_op: |
455 | case bltzall_op: | 472 | case bltzall_op: |
473 | if (NO_R6EMU && (insn.i_format.rs || | ||
474 | insn.i_format.rt == bltzall_op)) { | ||
475 | ret = -SIGILL; | ||
476 | break; | ||
477 | } | ||
456 | regs->regs[31] = epc + 8; | 478 | regs->regs[31] = epc + 8; |
479 | /* | ||
480 | * OK we are here either because we hit a NAL | ||
481 | * instruction or because we are emulating an | ||
482 | * old bltzal{,l} one. Lets figure out what the | ||
483 | * case really is. | ||
484 | */ | ||
485 | if (!insn.i_format.rs) { | ||
486 | /* | ||
487 | * NAL or BLTZAL with rs == 0 | ||
488 | * Doesn't matter if we are R6 or not. The | ||
489 | * result is the same | ||
490 | */ | ||
491 | regs->cp0_epc += 4 + | ||
492 | (insn.i_format.simmediate << 2); | ||
493 | break; | ||
494 | } | ||
495 | /* Now do the real thing for non-R6 BLTZAL{,L} */ | ||
457 | if ((long)regs->regs[insn.i_format.rs] < 0) { | 496 | if ((long)regs->regs[insn.i_format.rs] < 0) { |
458 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 497 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
459 | if (insn.i_format.rt == bltzall_op) | 498 | if (insn.i_format.rt == bltzall_op) |
@@ -465,7 +504,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
465 | 504 | ||
466 | case bgezal_op: | 505 | case bgezal_op: |
467 | case bgezall_op: | 506 | case bgezall_op: |
507 | if (NO_R6EMU && (insn.i_format.rs || | ||
508 | insn.i_format.rt == bgezall_op)) { | ||
509 | ret = -SIGILL; | ||
510 | break; | ||
511 | } | ||
468 | regs->regs[31] = epc + 8; | 512 | regs->regs[31] = epc + 8; |
513 | /* | ||
514 | * OK we are here either because we hit a BAL | ||
515 | * instruction or because we are emulating an | ||
516 | * old bgezal{,l} one. Lets figure out what the | ||
517 | * case really is. | ||
518 | */ | ||
519 | if (!insn.i_format.rs) { | ||
520 | /* | ||
521 | * BAL or BGEZAL with rs == 0 | ||
522 | * Doesn't matter if we are R6 or not. The | ||
523 | * result is the same | ||
524 | */ | ||
525 | regs->cp0_epc += 4 + | ||
526 | (insn.i_format.simmediate << 2); | ||
527 | break; | ||
528 | } | ||
529 | /* Now do the real thing for non-R6 BGEZAL{,L} */ | ||
469 | if ((long)regs->regs[insn.i_format.rs] >= 0) { | 530 | if ((long)regs->regs[insn.i_format.rs] >= 0) { |
470 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 531 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
471 | if (insn.i_format.rt == bgezall_op) | 532 | if (insn.i_format.rt == bgezall_op) |
@@ -477,7 +538,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
477 | 538 | ||
478 | case bposge32_op: | 539 | case bposge32_op: |
479 | if (!cpu_has_dsp) | 540 | if (!cpu_has_dsp) |
480 | goto sigill; | 541 | goto sigill_dsp; |
481 | 542 | ||
482 | dspcontrol = rddsp(0x01); | 543 | dspcontrol = rddsp(0x01); |
483 | 544 | ||
@@ -508,8 +569,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
508 | /* | 569 | /* |
509 | * These are conditional and in i_format. | 570 | * These are conditional and in i_format. |
510 | */ | 571 | */ |
511 | case beq_op: | ||
512 | case beql_op: | 572 | case beql_op: |
573 | if (NO_R6EMU) | ||
574 | goto sigill_r6; | ||
575 | case beq_op: | ||
513 | if (regs->regs[insn.i_format.rs] == | 576 | if (regs->regs[insn.i_format.rs] == |
514 | regs->regs[insn.i_format.rt]) { | 577 | regs->regs[insn.i_format.rt]) { |
515 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 578 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
@@ -520,8 +583,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
520 | regs->cp0_epc = epc; | 583 | regs->cp0_epc = epc; |
521 | break; | 584 | break; |
522 | 585 | ||
523 | case bne_op: | ||
524 | case bnel_op: | 586 | case bnel_op: |
587 | if (NO_R6EMU) | ||
588 | goto sigill_r6; | ||
589 | case bne_op: | ||
525 | if (regs->regs[insn.i_format.rs] != | 590 | if (regs->regs[insn.i_format.rs] != |
526 | regs->regs[insn.i_format.rt]) { | 591 | regs->regs[insn.i_format.rt]) { |
527 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 592 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
@@ -532,8 +597,31 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
532 | regs->cp0_epc = epc; | 597 | regs->cp0_epc = epc; |
533 | break; | 598 | break; |
534 | 599 | ||
535 | case blez_op: /* not really i_format */ | 600 | case blezl_op: /* not really i_format */ |
536 | case blezl_op: | 601 | if (NO_R6EMU) |
602 | goto sigill_r6; | ||
603 | case blez_op: | ||
604 | /* | ||
605 | * Compact branches for R6 for the | ||
606 | * blez and blezl opcodes. | ||
607 | * BLEZ | rs = 0 | rt != 0 == BLEZALC | ||
608 | * BLEZ | rs = rt != 0 == BGEZALC | ||
609 | * BLEZ | rs != 0 | rt != 0 == BGEUC | ||
610 | * BLEZL | rs = 0 | rt != 0 == BLEZC | ||
611 | * BLEZL | rs = rt != 0 == BGEZC | ||
612 | * BLEZL | rs != 0 | rt != 0 == BGEC | ||
613 | * | ||
614 | * For real BLEZ{,L}, rt is always 0. | ||
615 | */ | ||
616 | |||
617 | if (cpu_has_mips_r6 && insn.i_format.rt) { | ||
618 | if ((insn.i_format.opcode == blez_op) && | ||
619 | ((!insn.i_format.rs && insn.i_format.rt) || | ||
620 | (insn.i_format.rs == insn.i_format.rt))) | ||
621 | regs->regs[31] = epc + 4; | ||
622 | regs->cp0_epc += 8; | ||
623 | break; | ||
624 | } | ||
537 | /* rt field assumed to be zero */ | 625 | /* rt field assumed to be zero */ |
538 | if ((long)regs->regs[insn.i_format.rs] <= 0) { | 626 | if ((long)regs->regs[insn.i_format.rs] <= 0) { |
539 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 627 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
@@ -544,8 +632,32 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
544 | regs->cp0_epc = epc; | 632 | regs->cp0_epc = epc; |
545 | break; | 633 | break; |
546 | 634 | ||
547 | case bgtz_op: | ||
548 | case bgtzl_op: | 635 | case bgtzl_op: |
636 | if (NO_R6EMU) | ||
637 | goto sigill_r6; | ||
638 | case bgtz_op: | ||
639 | /* | ||
640 | * Compact branches for R6 for the | ||
641 | * bgtz and bgtzl opcodes. | ||
642 | * BGTZ | rs = 0 | rt != 0 == BGTZALC | ||
643 | * BGTZ | rs = rt != 0 == BLTZALC | ||
644 | * BGTZ | rs != 0 | rt != 0 == BLTUC | ||
645 | * BGTZL | rs = 0 | rt != 0 == BGTZC | ||
646 | * BGTZL | rs = rt != 0 == BLTZC | ||
647 | * BGTZL | rs != 0 | rt != 0 == BLTC | ||
648 | * | ||
649 | * *ZALC varint for BGTZ &&& rt != 0 | ||
650 | * For real GTZ{,L}, rt is always 0. | ||
651 | */ | ||
652 | if (cpu_has_mips_r6 && insn.i_format.rt) { | ||
653 | if ((insn.i_format.opcode == blez_op) && | ||
654 | ((!insn.i_format.rs && insn.i_format.rt) || | ||
655 | (insn.i_format.rs == insn.i_format.rt))) | ||
656 | regs->regs[31] = epc + 4; | ||
657 | regs->cp0_epc += 8; | ||
658 | break; | ||
659 | } | ||
660 | |||
549 | /* rt field assumed to be zero */ | 661 | /* rt field assumed to be zero */ |
550 | if ((long)regs->regs[insn.i_format.rs] > 0) { | 662 | if ((long)regs->regs[insn.i_format.rs] > 0) { |
551 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 663 | epc = epc + 4 + (insn.i_format.simmediate << 2); |
@@ -560,40 +672,83 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
560 | * And now the FPA/cp1 branch instructions. | 672 | * And now the FPA/cp1 branch instructions. |
561 | */ | 673 | */ |
562 | case cop1_op: | 674 | case cop1_op: |
563 | preempt_disable(); | 675 | if (cpu_has_mips_r6 && |
564 | if (is_fpu_owner()) | 676 | ((insn.i_format.rs == bc1eqz_op) || |
565 | fcr31 = read_32bit_cp1_register(CP1_STATUS); | 677 | (insn.i_format.rs == bc1nez_op))) { |
566 | else | 678 | if (!used_math()) { /* First time FPU user */ |
567 | fcr31 = current->thread.fpu.fcr31; | 679 | ret = init_fpu(); |
568 | preempt_enable(); | 680 | if (ret && NO_R6EMU) { |
569 | 681 | ret = -ret; | |
570 | bit = (insn.i_format.rt >> 2); | 682 | break; |
571 | bit += (bit != 0); | 683 | } |
572 | bit += 23; | 684 | ret = 0; |
573 | switch (insn.i_format.rt & 3) { | 685 | set_used_math(); |
574 | case 0: /* bc1f */ | 686 | } |
575 | case 2: /* bc1fl */ | 687 | lose_fpu(1); /* Save FPU state for the emulator. */ |
576 | if (~fcr31 & (1 << bit)) { | 688 | reg = insn.i_format.rt; |
577 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 689 | bit = 0; |
578 | if (insn.i_format.rt == 2) | 690 | switch (insn.i_format.rs) { |
579 | ret = BRANCH_LIKELY_TAKEN; | 691 | case bc1eqz_op: |
580 | } else | 692 | /* Test bit 0 */ |
693 | if (get_fpr32(¤t->thread.fpu.fpr[reg], 0) | ||
694 | & 0x1) | ||
695 | bit = 1; | ||
696 | break; | ||
697 | case bc1nez_op: | ||
698 | /* Test bit 0 */ | ||
699 | if (!(get_fpr32(¤t->thread.fpu.fpr[reg], 0) | ||
700 | & 0x1)) | ||
701 | bit = 1; | ||
702 | break; | ||
703 | } | ||
704 | own_fpu(1); | ||
705 | if (bit) | ||
706 | epc = epc + 4 + | ||
707 | (insn.i_format.simmediate << 2); | ||
708 | else | ||
581 | epc += 8; | 709 | epc += 8; |
582 | regs->cp0_epc = epc; | 710 | regs->cp0_epc = epc; |
711 | |||
583 | break; | 712 | break; |
713 | } else { | ||
584 | 714 | ||
585 | case 1: /* bc1t */ | 715 | preempt_disable(); |
586 | case 3: /* bc1tl */ | 716 | if (is_fpu_owner()) |
587 | if (fcr31 & (1 << bit)) { | 717 | fcr31 = read_32bit_cp1_register(CP1_STATUS); |
588 | epc = epc + 4 + (insn.i_format.simmediate << 2); | 718 | else |
589 | if (insn.i_format.rt == 3) | 719 | fcr31 = current->thread.fpu.fcr31; |
590 | ret = BRANCH_LIKELY_TAKEN; | 720 | preempt_enable(); |
591 | } else | 721 | |
592 | epc += 8; | 722 | bit = (insn.i_format.rt >> 2); |
593 | regs->cp0_epc = epc; | 723 | bit += (bit != 0); |
724 | bit += 23; | ||
725 | switch (insn.i_format.rt & 3) { | ||
726 | case 0: /* bc1f */ | ||
727 | case 2: /* bc1fl */ | ||
728 | if (~fcr31 & (1 << bit)) { | ||
729 | epc = epc + 4 + | ||
730 | (insn.i_format.simmediate << 2); | ||
731 | if (insn.i_format.rt == 2) | ||
732 | ret = BRANCH_LIKELY_TAKEN; | ||
733 | } else | ||
734 | epc += 8; | ||
735 | regs->cp0_epc = epc; | ||
736 | break; | ||
737 | |||
738 | case 1: /* bc1t */ | ||
739 | case 3: /* bc1tl */ | ||
740 | if (fcr31 & (1 << bit)) { | ||
741 | epc = epc + 4 + | ||
742 | (insn.i_format.simmediate << 2); | ||
743 | if (insn.i_format.rt == 3) | ||
744 | ret = BRANCH_LIKELY_TAKEN; | ||
745 | } else | ||
746 | epc += 8; | ||
747 | regs->cp0_epc = epc; | ||
748 | break; | ||
749 | } | ||
594 | break; | 750 | break; |
595 | } | 751 | } |
596 | break; | ||
597 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 752 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
598 | case lwc2_op: /* This is bbit0 on Octeon */ | 753 | case lwc2_op: /* This is bbit0 on Octeon */ |
599 | if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) | 754 | if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) |
@@ -626,15 +781,72 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | |||
626 | epc += 8; | 781 | epc += 8; |
627 | regs->cp0_epc = epc; | 782 | regs->cp0_epc = epc; |
628 | break; | 783 | break; |
784 | #else | ||
785 | case bc6_op: | ||
786 | /* Only valid for MIPS R6 */ | ||
787 | if (!cpu_has_mips_r6) { | ||
788 | ret = -SIGILL; | ||
789 | break; | ||
790 | } | ||
791 | regs->cp0_epc += 8; | ||
792 | break; | ||
793 | case balc6_op: | ||
794 | if (!cpu_has_mips_r6) { | ||
795 | ret = -SIGILL; | ||
796 | break; | ||
797 | } | ||
798 | /* Compact branch: BALC */ | ||
799 | regs->regs[31] = epc + 4; | ||
800 | epc += 4 + (insn.i_format.simmediate << 2); | ||
801 | regs->cp0_epc = epc; | ||
802 | break; | ||
803 | case beqzcjic_op: | ||
804 | if (!cpu_has_mips_r6) { | ||
805 | ret = -SIGILL; | ||
806 | break; | ||
807 | } | ||
808 | /* Compact branch: BEQZC || JIC */ | ||
809 | regs->cp0_epc += 8; | ||
810 | break; | ||
811 | case bnezcjialc_op: | ||
812 | if (!cpu_has_mips_r6) { | ||
813 | ret = -SIGILL; | ||
814 | break; | ||
815 | } | ||
816 | /* Compact branch: BNEZC || JIALC */ | ||
817 | if (insn.i_format.rs) | ||
818 | regs->regs[31] = epc + 4; | ||
819 | regs->cp0_epc += 8; | ||
820 | break; | ||
629 | #endif | 821 | #endif |
822 | case cbcond0_op: | ||
823 | case cbcond1_op: | ||
824 | /* Only valid for MIPS R6 */ | ||
825 | if (!cpu_has_mips_r6) { | ||
826 | ret = -SIGILL; | ||
827 | break; | ||
828 | } | ||
829 | /* | ||
830 | * Compact branches: | ||
831 | * bovc, beqc, beqzalc, bnvc, bnec, bnezlac | ||
832 | */ | ||
833 | if (insn.i_format.rt && !insn.i_format.rs) | ||
834 | regs->regs[31] = epc + 4; | ||
835 | regs->cp0_epc += 8; | ||
836 | break; | ||
630 | } | 837 | } |
631 | 838 | ||
632 | return ret; | 839 | return ret; |
633 | 840 | ||
634 | sigill: | 841 | sigill_dsp: |
635 | printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); | 842 | printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); |
636 | force_sig(SIGBUS, current); | 843 | force_sig(SIGBUS, current); |
637 | return -EFAULT; | 844 | return -EFAULT; |
845 | sigill_r6: | ||
846 | pr_info("%s: R2 branch but r2-to-r6 emulator is not preset - sending SIGILL.\n", | ||
847 | current->comm); | ||
848 | force_sig(SIGILL, current); | ||
849 | return -EFAULT; | ||
638 | } | 850 | } |
639 | EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn); | 851 | EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn); |
640 | 852 | ||