Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/47x: Kernel support for KEXEC

This patch adds support for creating 1:1 mapping for the PPC_47x during
a KEXEC. The implementation is similar to that of the PPC440x which is
described here :

http://patchwork.ozlabs.org/patch/104323/

PPC_47x MMU :

The 47x uses Unified TLB 1024 entries, with 4-way associative mapping
(4 x 256 entries). The index to be used is calculated by the MMU by
hashing the PID, EPN and TS. The software can choose to specify the way
by setting bit 0(enable way select) and the way in bits 1-2 in the TLB
Word 0.

Implementation:

The patch erases all the UTLB entries which includes the tlb covering
the mapping for our code. The shadow TLB caches the mapping for the
running code which helps us to continue the execution until we do
isync/rfi. We then create a tmp mapping for the current code in the
other address space (TS) and switch to it.

Then we create a 1:1 mapping(EPN=RPN) for 0-2GiB in the original
address space and switch to the new mapping.

TODO: Add SMP support.

Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Signed-off-by: Josh Boyer <jwboyer@gmail.com>

authored by

Suzuki Poulose and committed by
Josh Boyer
68343020 f13bfcc6

+190 -7
+1 -1
arch/powerpc/Kconfig
··· 353 353 354 354 config KEXEC 355 355 bool "kexec system call (EXPERIMENTAL)" 356 - depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !PPC_47x)) && EXPERIMENTAL 356 + depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) && EXPERIMENTAL 357 357 help 358 358 kexec is a system call that implements the ability to shutdown your 359 359 current kernel, and to start another kernel. It is like a reboot
+189 -6
arch/powerpc/kernel/misc_32.S
··· 738 738 mr r5, r31 739 739 740 740 li r0, 0 741 - #elif defined(CONFIG_44x) && !defined(CONFIG_PPC_47x) 741 + #elif defined(CONFIG_44x) 742 742 743 + /* Save our parameters */ 744 + mr r29, r3 745 + mr r30, r4 746 + mr r31, r5 747 + 748 + #ifdef CONFIG_PPC_47x 749 + /* Check for 47x cores */ 750 + mfspr r3,SPRN_PVR 751 + srwi r3,r3,16 752 + cmplwi cr0,r3,PVR_476@h 753 + beq setup_map_47x 754 + cmplwi cr0,r3,PVR_476_ISS@h 755 + beq setup_map_47x 756 + #endif /* CONFIG_PPC_47x */ 757 + 743 758 /* 744 759 * Code for setting up 1:1 mapping for PPC440x for KEXEC 745 760 * ··· 768 753 * 5) Invalidate the tmp mapping. 769 754 * 770 755 * - Based on the kexec support code for FSL BookE 771 - * - Doesn't support 47x yet. 772 756 * 773 757 */ 774 - /* Save our parameters */ 775 - mr r29, r3 776 - mr r30, r4 777 - mr r31, r5 778 758 779 759 /* 780 760 * Load the PID with kernel PID (0). ··· 914 904 li r3, 0 915 905 tlbwe r3, r24, PPC44x_TLB_PAGEID 916 906 sync 907 + b ppc44x_map_done 908 + 909 + #ifdef CONFIG_PPC_47x 910 + 911 + /* 1:1 mapping for 47x */ 912 + 913 + setup_map_47x: 914 + 915 + /* 916 + * Load the kernel pid (0) to PID and also to MMUCR[TID]. 917 + * Also set the MSR IS->MMUCR STS 918 + */ 919 + li r3, 0 920 + mtspr SPRN_PID, r3 /* Set PID */ 921 + mfmsr r4 /* Get MSR */ 922 + andi. r4, r4, MSR_IS@l /* TS=1? */ 923 + beq 1f /* If not, leave STS=0 */ 924 + oris r3, r3, PPC47x_MMUCR_STS@h /* Set STS=1 */ 925 + 1: mtspr SPRN_MMUCR, r3 /* Put MMUCR */ 926 + sync 927 + 928 + /* Find the entry we are running from */ 929 + bl 2f 930 + 2: mflr r23 931 + tlbsx r23, 0, r23 932 + tlbre r24, r23, 0 /* TLB Word 0 */ 933 + tlbre r25, r23, 1 /* TLB Word 1 */ 934 + tlbre r26, r23, 2 /* TLB Word 2 */ 935 + 936 + 937 + /* 938 + * Invalidates all the tlb entries by writing to 256 RPNs(r4) 939 + * of 4k page size in all 4 ways (0-3 in r3). 940 + * This would invalidate the entire UTLB including the one we are 941 + * running from. However the shadow TLB entries would help us 942 + * to continue the execution, until we flush them (rfi/isync). 943 + */ 944 + addis r3, 0, 0x8000 /* specify the way */ 945 + addi r4, 0, 0 /* TLB Word0 = (EPN=0, VALID = 0) */ 946 + addi r5, 0, 0 947 + b clear_utlb_entry 948 + 949 + /* Align the loop to speed things up. from head_44x.S */ 950 + .align 6 951 + 952 + clear_utlb_entry: 953 + 954 + tlbwe r4, r3, 0 955 + tlbwe r5, r3, 1 956 + tlbwe r5, r3, 2 957 + addis r3, r3, 0x2000 /* Increment the way */ 958 + cmpwi r3, 0 959 + bne clear_utlb_entry 960 + addis r3, 0, 0x8000 961 + addis r4, r4, 0x100 /* Increment the EPN */ 962 + cmpwi r4, 0 963 + bne clear_utlb_entry 964 + 965 + /* Create the entries in the other address space */ 966 + mfmsr r5 967 + rlwinm r7, r5, 27, 31, 31 /* Get the TS (Bit 26) from MSR */ 968 + xori r7, r7, 1 /* r7 = !TS */ 969 + 970 + insrwi r24, r7, 1, 21 /* Change the TS in the saved TLB word 0 */ 971 + 972 + /* 973 + * write out the TLB entries for the tmp mapping 974 + * Use way '0' so that we could easily invalidate it later. 975 + */ 976 + lis r3, 0x8000 /* Way '0' */ 977 + 978 + tlbwe r24, r3, 0 979 + tlbwe r25, r3, 1 980 + tlbwe r26, r3, 2 981 + 982 + /* Update the msr to the new TS */ 983 + insrwi r5, r7, 1, 26 984 + 985 + bl 1f 986 + 1: mflr r6 987 + addi r6, r6, (2f-1b) 988 + 989 + mtspr SPRN_SRR0, r6 990 + mtspr SPRN_SRR1, r5 991 + rfi 992 + 993 + /* 994 + * Now we are in the tmp address space. 995 + * Create a 1:1 mapping for 0-2GiB in the original TS. 996 + */ 997 + 2: 998 + li r3, 0 999 + li r4, 0 /* TLB Word 0 */ 1000 + li r5, 0 /* TLB Word 1 */ 1001 + li r6, 0 1002 + ori r6, r6, PPC47x_TLB2_S_RWX /* TLB word 2 */ 1003 + 1004 + li r8, 0 /* PageIndex */ 1005 + 1006 + xori r7, r7, 1 /* revert back to original TS */ 1007 + 1008 + write_utlb: 1009 + rotlwi r5, r8, 28 /* RPN = PageIndex * 256M */ 1010 + /* ERPN = 0 as we don't use memory above 2G */ 1011 + 1012 + mr r4, r5 /* EPN = RPN */ 1013 + ori r4, r4, (PPC47x_TLB0_VALID | PPC47x_TLB0_256M) 1014 + insrwi r4, r7, 1, 21 /* Insert the TS to Word 0 */ 1015 + 1016 + tlbwe r4, r3, 0 /* Write out the entries */ 1017 + tlbwe r5, r3, 1 1018 + tlbwe r6, r3, 2 1019 + addi r8, r8, 1 1020 + cmpwi r8, 8 /* Have we completed ? */ 1021 + bne write_utlb 1022 + 1023 + /* make sure we complete the TLB write up */ 1024 + isync 1025 + 1026 + /* 1027 + * Prepare to jump to the 1:1 mapping. 1028 + * 1) Extract page size of the tmp mapping 1029 + * DSIZ = TLB_Word0[22:27] 1030 + * 2) Calculate the physical address of the address 1031 + * to jump to. 1032 + */ 1033 + rlwinm r10, r24, 0, 22, 27 1034 + 1035 + cmpwi r10, PPC47x_TLB0_4K 1036 + bne 0f 1037 + li r10, 0x1000 /* r10 = 4k */ 1038 + bl 1f 1039 + 1040 + 0: 1041 + /* Defaults to 256M */ 1042 + lis r10, 0x1000 1043 + 1044 + bl 1f 1045 + 1: mflr r4 1046 + addi r4, r4, (2f-1b) /* virtual address of 2f */ 1047 + 1048 + subi r11, r10, 1 /* offsetmask = Pagesize - 1 */ 1049 + not r10, r11 /* Pagemask = ~(offsetmask) */ 1050 + 1051 + and r5, r25, r10 /* Physical page */ 1052 + and r6, r4, r11 /* offset within the current page */ 1053 + 1054 + or r5, r5, r6 /* Physical address for 2f */ 1055 + 1056 + /* Switch the TS in MSR to the original one */ 1057 + mfmsr r8 1058 + insrwi r8, r7, 1, 26 1059 + 1060 + mtspr SPRN_SRR1, r8 1061 + mtspr SPRN_SRR0, r5 1062 + rfi 1063 + 1064 + 2: 1065 + /* Invalidate the tmp mapping */ 1066 + lis r3, 0x8000 /* Way '0' */ 1067 + 1068 + clrrwi r24, r24, 12 /* Clear the valid bit */ 1069 + tlbwe r24, r3, 0 1070 + tlbwe r25, r3, 1 1071 + tlbwe r26, r3, 2 1072 + 1073 + /* Make sure we complete the TLB write and flush the shadow TLB */ 1074 + isync 1075 + 1076 + #endif 1077 + 1078 + ppc44x_map_done: 1079 + 917 1080 918 1081 /* Restore the parameters */ 919 1082 mr r3, r29