diff options
Diffstat (limited to 'arch/powerpc/kernel/exceptions-64e.S')
-rw-r--r-- | arch/powerpc/kernel/exceptions-64e.S | 204 |
1 files changed, 200 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 662236c72244..9048f96237f6 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S | |||
@@ -616,18 +616,214 @@ bad_stack_book3e: | |||
616 | * Setup the initial TLB for a core. This current implementation | 616 | * Setup the initial TLB for a core. This current implementation |
617 | * assume that whatever we are running off will not conflict with | 617 | * assume that whatever we are running off will not conflict with |
618 | * the new mapping at PAGE_OFFSET. | 618 | * the new mapping at PAGE_OFFSET. |
619 | * We also make various assumptions about the processor we run on, | ||
620 | * this might have to be made more flexible based on the content | ||
621 | * of MMUCFG and friends. | ||
622 | */ | 619 | */ |
623 | _GLOBAL(initial_tlb_book3e) | 620 | _GLOBAL(initial_tlb_book3e) |
624 | 621 | ||
622 | /* Look for the first TLB with IPROT set */ | ||
623 | mfspr r4,SPRN_TLB0CFG | ||
624 | andi. r3,r4,TLBnCFG_IPROT | ||
625 | lis r3,MAS0_TLBSEL(0)@h | ||
626 | bne found_iprot | ||
627 | |||
628 | mfspr r4,SPRN_TLB1CFG | ||
629 | andi. r3,r4,TLBnCFG_IPROT | ||
630 | lis r3,MAS0_TLBSEL(1)@h | ||
631 | bne found_iprot | ||
632 | |||
633 | mfspr r4,SPRN_TLB2CFG | ||
634 | andi. r3,r4,TLBnCFG_IPROT | ||
635 | lis r3,MAS0_TLBSEL(2)@h | ||
636 | bne found_iprot | ||
637 | |||
638 | lis r3,MAS0_TLBSEL(3)@h | ||
639 | mfspr r4,SPRN_TLB3CFG | ||
640 | /* fall through */ | ||
641 | |||
642 | found_iprot: | ||
643 | andi. r5,r4,TLBnCFG_HES | ||
644 | bne have_hes | ||
645 | |||
646 | mflr r8 /* save LR */ | ||
647 | /* 1. Find the index of the entry we're executing in | ||
648 | * | ||
649 | * r3 = MAS0_TLBSEL (for the iprot array) | ||
650 | * r4 = SPRN_TLBnCFG | ||
651 | */ | ||
652 | bl invstr /* Find our address */ | ||
653 | invstr: mflr r6 /* Make it accessible */ | ||
654 | mfmsr r7 | ||
655 | rlwinm r5,r7,27,31,31 /* extract MSR[IS] */ | ||
656 | mfspr r7,SPRN_PID | ||
657 | slwi r7,r7,16 | ||
658 | or r7,r7,r5 | ||
659 | mtspr SPRN_MAS6,r7 | ||
660 | tlbsx 0,r6 /* search MSR[IS], SPID=PID */ | ||
661 | |||
662 | mfspr r3,SPRN_MAS0 | ||
663 | rlwinm r5,r3,16,20,31 /* Extract MAS0(Entry) */ | ||
664 | |||
665 | mfspr r7,SPRN_MAS1 /* Insure IPROT set */ | ||
666 | oris r7,r7,MAS1_IPROT@h | ||
667 | mtspr SPRN_MAS1,r7 | ||
668 | tlbwe | ||
669 | |||
670 | /* 2. Invalidate all entries except the entry we're executing in | ||
671 | * | ||
672 | * r3 = MAS0 w/TLBSEL & ESEL for the entry we are running in | ||
673 | * r4 = SPRN_TLBnCFG | ||
674 | * r5 = ESEL of entry we are running in | ||
675 | */ | ||
676 | andi. r4,r4,TLBnCFG_N_ENTRY /* Extract # entries */ | ||
677 | li r6,0 /* Set Entry counter to 0 */ | ||
678 | 1: mr r7,r3 /* Set MAS0(TLBSEL) */ | ||
679 | rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */ | ||
680 | mtspr SPRN_MAS0,r7 | ||
681 | tlbre | ||
682 | mfspr r7,SPRN_MAS1 | ||
683 | rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */ | ||
684 | cmpw r5,r6 | ||
685 | beq skpinv /* Dont update the current execution TLB */ | ||
686 | mtspr SPRN_MAS1,r7 | ||
687 | tlbwe | ||
688 | isync | ||
689 | skpinv: addi r6,r6,1 /* Increment */ | ||
690 | cmpw r6,r4 /* Are we done? */ | ||
691 | bne 1b /* If not, repeat */ | ||
692 | |||
693 | /* Invalidate all TLBs */ | ||
694 | PPC_TLBILX_ALL(0,0) | ||
695 | sync | ||
696 | isync | ||
697 | |||
698 | /* 3. Setup a temp mapping and jump to it | ||
699 | * | ||
700 | * r3 = MAS0 w/TLBSEL & ESEL for the entry we are running in | ||
701 | * r5 = ESEL of entry we are running in | ||
702 | */ | ||
703 | andi. r7,r5,0x1 /* Find an entry not used and is non-zero */ | ||
704 | addi r7,r7,0x1 | ||
705 | mr r4,r3 /* Set MAS0(TLBSEL) = 1 */ | ||
706 | mtspr SPRN_MAS0,r4 | ||
707 | tlbre | ||
708 | |||
709 | rlwimi r4,r7,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r7) */ | ||
710 | mtspr SPRN_MAS0,r4 | ||
711 | |||
712 | mfspr r7,SPRN_MAS1 | ||
713 | xori r6,r7,MAS1_TS /* Setup TMP mapping in the other Address space */ | ||
714 | mtspr SPRN_MAS1,r6 | ||
715 | |||
716 | tlbwe | ||
717 | |||
718 | mfmsr r6 | ||
719 | xori r6,r6,MSR_IS | ||
720 | mtspr SPRN_SRR1,r6 | ||
721 | bl 1f /* Find our address */ | ||
722 | 1: mflr r6 | ||
723 | addi r6,r6,(2f - 1b) | ||
724 | mtspr SPRN_SRR0,r6 | ||
725 | rfi | ||
726 | 2: | ||
727 | |||
728 | /* 4. Clear out PIDs & Search info | ||
729 | * | ||
730 | * r3 = MAS0 w/TLBSEL & ESEL for the entry we started in | ||
731 | * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping | ||
732 | * r5 = MAS3 | ||
733 | */ | ||
734 | li r6,0 | ||
735 | mtspr SPRN_MAS6,r6 | ||
736 | mtspr SPRN_PID,r6 | ||
737 | |||
738 | /* 5. Invalidate mapping we started in | ||
739 | * | ||
740 | * r3 = MAS0 w/TLBSEL & ESEL for the entry we started in | ||
741 | * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping | ||
742 | * r5 = MAS3 | ||
743 | */ | ||
744 | mtspr SPRN_MAS0,r3 | ||
745 | tlbre | ||
746 | mfspr r6,SPRN_MAS1 | ||
747 | rlwinm r6,r6,0,2,0 /* clear IPROT */ | ||
748 | mtspr SPRN_MAS1,r6 | ||
749 | tlbwe | ||
750 | |||
751 | /* Invalidate TLB1 */ | ||
752 | PPC_TLBILX_ALL(0,0) | ||
753 | sync | ||
754 | isync | ||
755 | |||
756 | /* The mapping only needs to be cache-coherent on SMP */ | ||
757 | #ifdef CONFIG_SMP | ||
758 | #define M_IF_SMP MAS2_M | ||
759 | #else | ||
760 | #define M_IF_SMP 0 | ||
761 | #endif | ||
762 | |||
763 | /* 6. Setup KERNELBASE mapping in TLB[0] | ||
764 | * | ||
765 | * r3 = MAS0 w/TLBSEL & ESEL for the entry we started in | ||
766 | * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping | ||
767 | * r5 = MAS3 | ||
768 | */ | ||
769 | rlwinm r3,r3,0,16,3 /* clear ESEL */ | ||
770 | mtspr SPRN_MAS0,r3 | ||
771 | lis r6,(MAS1_VALID|MAS1_IPROT)@h | ||
772 | ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_1GB))@l | ||
773 | mtspr SPRN_MAS1,r6 | ||
774 | |||
775 | LOAD_REG_IMMEDIATE(r6, PAGE_OFFSET | M_IF_SMP) | ||
776 | mtspr SPRN_MAS2,r6 | ||
777 | |||
778 | rlwinm r5,r5,0,0,25 | ||
779 | ori r5,r5,MAS3_SR | MAS3_SW | MAS3_SX | ||
780 | mtspr SPRN_MAS3,r5 | ||
781 | li r5,-1 | ||
782 | rlwinm r5,r5,0,0,25 | ||
783 | |||
784 | tlbwe | ||
785 | |||
786 | /* 7. Jump to KERNELBASE mapping | ||
787 | * | ||
788 | * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping | ||
789 | */ | ||
790 | /* Now we branch the new virtual address mapped by this entry */ | ||
791 | LOAD_REG_IMMEDIATE(r6,2f) | ||
792 | lis r7,MSR_KERNEL@h | ||
793 | ori r7,r7,MSR_KERNEL@l | ||
794 | mtspr SPRN_SRR0,r6 | ||
795 | mtspr SPRN_SRR1,r7 | ||
796 | rfi /* start execution out of TLB1[0] entry */ | ||
797 | 2: | ||
798 | |||
799 | /* 8. Clear out the temp mapping | ||
800 | * | ||
801 | * r4 = MAS0 w/TLBSEL & ESEL for the entry we are running in | ||
802 | */ | ||
803 | mtspr SPRN_MAS0,r4 | ||
804 | tlbre | ||
805 | mfspr r5,SPRN_MAS1 | ||
806 | rlwinm r5,r5,0,2,0 /* clear IPROT */ | ||
807 | mtspr SPRN_MAS1,r5 | ||
808 | tlbwe | ||
809 | |||
810 | /* Invalidate TLB1 */ | ||
811 | PPC_TLBILX_ALL(0,0) | ||
812 | sync | ||
813 | isync | ||
814 | |||
815 | /* We translate LR and return */ | ||
816 | tovirt(r8,r8) | ||
817 | mtlr r8 | ||
818 | blr | ||
819 | |||
820 | have_hes: | ||
625 | /* Setup MAS 0,1,2,3 and 7 for tlbwe of a 1G entry that maps the | 821 | /* Setup MAS 0,1,2,3 and 7 for tlbwe of a 1G entry that maps the |
626 | * kernel linear mapping. We also set MAS8 once for all here though | 822 | * kernel linear mapping. We also set MAS8 once for all here though |
627 | * that will have to be made dependent on whether we are running under | 823 | * that will have to be made dependent on whether we are running under |
628 | * a hypervisor I suppose. | 824 | * a hypervisor I suppose. |
629 | */ | 825 | */ |
630 | li r3,MAS0_HES | MAS0_WQ_ALLWAYS | 826 | ori r3,r3,MAS0_HES | MAS0_WQ_ALLWAYS |
631 | mtspr SPRN_MAS0,r3 | 827 | mtspr SPRN_MAS0,r3 |
632 | lis r3,(MAS1_VALID | MAS1_IPROT)@h | 828 | lis r3,(MAS1_VALID | MAS1_IPROT)@h |
633 | ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT | 829 | ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT |