diff options
Diffstat (limited to 'arch/powerpc/kernel/head_fsl_booke.S')
-rw-r--r-- | arch/powerpc/kernel/head_fsl_booke.S | 266 |
1 files changed, 236 insertions, 30 deletions
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index f45726a1d963..b497188a94a1 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S | |||
@@ -65,29 +65,78 @@ _ENTRY(_start); | |||
65 | nop | 65 | nop |
66 | 66 | ||
67 | /* Translate device tree address to physical, save in r30/r31 */ | 67 | /* Translate device tree address to physical, save in r30/r31 */ |
68 | mfmsr r16 | 68 | bl get_phys_addr |
69 | mfspr r17,SPRN_PID | 69 | mr r30,r3 |
70 | rlwinm r17,r17,16,0x3fff0000 /* turn PID into MAS6[SPID] */ | 70 | mr r31,r4 |
71 | rlwimi r17,r16,28,0x00000001 /* turn MSR[DS] into MAS6[SAS] */ | ||
72 | mtspr SPRN_MAS6,r17 | ||
73 | |||
74 | tlbsx 0,r3 /* must succeed */ | ||
75 | |||
76 | mfspr r16,SPRN_MAS1 | ||
77 | mfspr r20,SPRN_MAS3 | ||
78 | rlwinm r17,r16,25,0x1f /* r17 = log2(page size) */ | ||
79 | li r18,1024 | ||
80 | slw r18,r18,r17 /* r18 = page size */ | ||
81 | addi r18,r18,-1 | ||
82 | and r19,r3,r18 /* r19 = page offset */ | ||
83 | andc r31,r20,r18 /* r31 = page base */ | ||
84 | or r31,r31,r19 /* r31 = devtree phys addr */ | ||
85 | mfspr r30,SPRN_MAS7 | ||
86 | 71 | ||
87 | li r25,0 /* phys kernel start (low) */ | 72 | li r25,0 /* phys kernel start (low) */ |
88 | li r24,0 /* CPU number */ | 73 | li r24,0 /* CPU number */ |
89 | li r23,0 /* phys kernel start (high) */ | 74 | li r23,0 /* phys kernel start (high) */ |
90 | 75 | ||
76 | #ifdef CONFIG_RELOCATABLE | ||
77 | LOAD_REG_ADDR_PIC(r3, _stext) /* Get our current runtime base */ | ||
78 | |||
79 | /* Translate _stext address to physical, save in r23/r25 */ | ||
80 | bl get_phys_addr | ||
81 | mr r23,r3 | ||
82 | mr r25,r4 | ||
83 | |||
84 | bl 0f | ||
85 | 0: mflr r8 | ||
86 | addis r3,r8,(is_second_reloc - 0b)@ha | ||
87 | lwz r19,(is_second_reloc - 0b)@l(r3) | ||
88 | |||
89 | /* Check if this is the second relocation. */ | ||
90 | cmpwi r19,1 | ||
91 | bne 1f | ||
92 | |||
93 | /* | ||
94 | * For the second relocation, we already get the real memstart_addr | ||
95 | * from device tree. So we will map PAGE_OFFSET to memstart_addr, | ||
96 | * then the virtual address of start kernel should be: | ||
97 | * PAGE_OFFSET + (kernstart_addr - memstart_addr) | ||
98 | * Since the offset between kernstart_addr and memstart_addr should | ||
99 | * never be beyond 1G, so we can just use the lower 32bit of them | ||
100 | * for the calculation. | ||
101 | */ | ||
102 | lis r3,PAGE_OFFSET@h | ||
103 | |||
104 | addis r4,r8,(kernstart_addr - 0b)@ha | ||
105 | addi r4,r4,(kernstart_addr - 0b)@l | ||
106 | lwz r5,4(r4) | ||
107 | |||
108 | addis r6,r8,(memstart_addr - 0b)@ha | ||
109 | addi r6,r6,(memstart_addr - 0b)@l | ||
110 | lwz r7,4(r6) | ||
111 | |||
112 | subf r5,r7,r5 | ||
113 | add r3,r3,r5 | ||
114 | b 2f | ||
115 | |||
116 | 1: | ||
117 | /* | ||
118 | * We have the runtime (virutal) address of our base. | ||
119 | * We calculate our shift of offset from a 64M page. | ||
120 | * We could map the 64M page we belong to at PAGE_OFFSET and | ||
121 | * get going from there. | ||
122 | */ | ||
123 | lis r4,KERNELBASE@h | ||
124 | ori r4,r4,KERNELBASE@l | ||
125 | rlwinm r6,r25,0,0x3ffffff /* r6 = PHYS_START % 64M */ | ||
126 | rlwinm r5,r4,0,0x3ffffff /* r5 = KERNELBASE % 64M */ | ||
127 | subf r3,r5,r6 /* r3 = r6 - r5 */ | ||
128 | add r3,r4,r3 /* Required Virtual Address */ | ||
129 | |||
130 | 2: bl relocate | ||
131 | |||
132 | /* | ||
133 | * For the second relocation, we already set the right tlb entries | ||
134 | * for the kernel space, so skip the code in fsl_booke_entry_mapping.S | ||
135 | */ | ||
136 | cmpwi r19,1 | ||
137 | beq set_ivor | ||
138 | #endif | ||
139 | |||
91 | /* We try to not make any assumptions about how the boot loader | 140 | /* We try to not make any assumptions about how the boot loader |
92 | * setup or used the TLBs. We invalidate all mappings from the | 141 | * setup or used the TLBs. We invalidate all mappings from the |
93 | * boot loader and load a single entry in TLB1[0] to map the | 142 | * boot loader and load a single entry in TLB1[0] to map the |
@@ -113,6 +162,7 @@ _ENTRY(__early_start) | |||
113 | #include "fsl_booke_entry_mapping.S" | 162 | #include "fsl_booke_entry_mapping.S" |
114 | #undef ENTRY_MAPPING_BOOT_SETUP | 163 | #undef ENTRY_MAPPING_BOOT_SETUP |
115 | 164 | ||
165 | set_ivor: | ||
116 | /* Establish the interrupt vector offsets */ | 166 | /* Establish the interrupt vector offsets */ |
117 | SET_IVOR(0, CriticalInput); | 167 | SET_IVOR(0, CriticalInput); |
118 | SET_IVOR(1, MachineCheck); | 168 | SET_IVOR(1, MachineCheck); |
@@ -166,8 +216,7 @@ _ENTRY(__early_start) | |||
166 | /* Check to see if we're the second processor, and jump | 216 | /* Check to see if we're the second processor, and jump |
167 | * to the secondary_start code if so | 217 | * to the secondary_start code if so |
168 | */ | 218 | */ |
169 | lis r24, boot_cpuid@h | 219 | LOAD_REG_ADDR_PIC(r24, boot_cpuid) |
170 | ori r24, r24, boot_cpuid@l | ||
171 | lwz r24, 0(r24) | 220 | lwz r24, 0(r24) |
172 | cmpwi r24, -1 | 221 | cmpwi r24, -1 |
173 | mfspr r24,SPRN_PIR | 222 | mfspr r24,SPRN_PIR |
@@ -197,6 +246,18 @@ _ENTRY(__early_start) | |||
197 | 246 | ||
198 | bl early_init | 247 | bl early_init |
199 | 248 | ||
249 | #ifdef CONFIG_RELOCATABLE | ||
250 | mr r3,r30 | ||
251 | mr r4,r31 | ||
252 | #ifdef CONFIG_PHYS_64BIT | ||
253 | mr r5,r23 | ||
254 | mr r6,r25 | ||
255 | #else | ||
256 | mr r5,r25 | ||
257 | #endif | ||
258 | bl relocate_init | ||
259 | #endif | ||
260 | |||
200 | #ifdef CONFIG_DYNAMIC_MEMSTART | 261 | #ifdef CONFIG_DYNAMIC_MEMSTART |
201 | lis r3,kernstart_addr@ha | 262 | lis r3,kernstart_addr@ha |
202 | la r3,kernstart_addr@l(r3) | 263 | la r3,kernstart_addr@l(r3) |
@@ -856,6 +917,33 @@ KernelSPE: | |||
856 | #endif /* CONFIG_SPE */ | 917 | #endif /* CONFIG_SPE */ |
857 | 918 | ||
858 | /* | 919 | /* |
920 | * Translate the effec addr in r3 to phys addr. The phys addr will be put | ||
921 | * into r3(higher 32bit) and r4(lower 32bit) | ||
922 | */ | ||
923 | get_phys_addr: | ||
924 | mfmsr r8 | ||
925 | mfspr r9,SPRN_PID | ||
926 | rlwinm r9,r9,16,0x3fff0000 /* turn PID into MAS6[SPID] */ | ||
927 | rlwimi r9,r8,28,0x00000001 /* turn MSR[DS] into MAS6[SAS] */ | ||
928 | mtspr SPRN_MAS6,r9 | ||
929 | |||
930 | tlbsx 0,r3 /* must succeed */ | ||
931 | |||
932 | mfspr r8,SPRN_MAS1 | ||
933 | mfspr r12,SPRN_MAS3 | ||
934 | rlwinm r9,r8,25,0x1f /* r9 = log2(page size) */ | ||
935 | li r10,1024 | ||
936 | slw r10,r10,r9 /* r10 = page size */ | ||
937 | addi r10,r10,-1 | ||
938 | and r11,r3,r10 /* r11 = page offset */ | ||
939 | andc r4,r12,r10 /* r4 = page base */ | ||
940 | or r4,r4,r11 /* r4 = devtree phys addr */ | ||
941 | #ifdef CONFIG_PHYS_64BIT | ||
942 | mfspr r3,SPRN_MAS7 | ||
943 | #endif | ||
944 | blr | ||
945 | |||
946 | /* | ||
859 | * Global functions | 947 | * Global functions |
860 | */ | 948 | */ |
861 | 949 | ||
@@ -1057,24 +1145,36 @@ _GLOBAL(__flush_disable_L1) | |||
1057 | /* When we get here, r24 needs to hold the CPU # */ | 1145 | /* When we get here, r24 needs to hold the CPU # */ |
1058 | .globl __secondary_start | 1146 | .globl __secondary_start |
1059 | __secondary_start: | 1147 | __secondary_start: |
1060 | lis r3,__secondary_hold_acknowledge@h | 1148 | LOAD_REG_ADDR_PIC(r3, tlbcam_index) |
1061 | ori r3,r3,__secondary_hold_acknowledge@l | 1149 | lwz r3,0(r3) |
1062 | stw r24,0(r3) | ||
1063 | |||
1064 | li r3,0 | ||
1065 | mr r4,r24 /* Why? */ | ||
1066 | bl call_setup_cpu | ||
1067 | |||
1068 | lis r3,tlbcam_index@ha | ||
1069 | lwz r3,tlbcam_index@l(r3) | ||
1070 | mtctr r3 | 1150 | mtctr r3 |
1071 | li r26,0 /* r26 safe? */ | 1151 | li r26,0 /* r26 safe? */ |
1072 | 1152 | ||
1153 | bl switch_to_as1 | ||
1154 | mr r27,r3 /* tlb entry */ | ||
1073 | /* Load each CAM entry */ | 1155 | /* Load each CAM entry */ |
1074 | 1: mr r3,r26 | 1156 | 1: mr r3,r26 |
1075 | bl loadcam_entry | 1157 | bl loadcam_entry |
1076 | addi r26,r26,1 | 1158 | addi r26,r26,1 |
1077 | bdnz 1b | 1159 | bdnz 1b |
1160 | mr r3,r27 /* tlb entry */ | ||
1161 | LOAD_REG_ADDR_PIC(r4, memstart_addr) | ||
1162 | lwz r4,0(r4) | ||
1163 | mr r5,r25 /* phys kernel start */ | ||
1164 | rlwinm r5,r5,0,~0x3ffffff /* aligned 64M */ | ||
1165 | subf r4,r5,r4 /* memstart_addr - phys kernel start */ | ||
1166 | li r5,0 /* no device tree */ | ||
1167 | li r6,0 /* not boot cpu */ | ||
1168 | bl restore_to_as0 | ||
1169 | |||
1170 | |||
1171 | lis r3,__secondary_hold_acknowledge@h | ||
1172 | ori r3,r3,__secondary_hold_acknowledge@l | ||
1173 | stw r24,0(r3) | ||
1174 | |||
1175 | li r3,0 | ||
1176 | mr r4,r24 /* Why? */ | ||
1177 | bl call_setup_cpu | ||
1078 | 1178 | ||
1079 | /* get current_thread_info and current */ | 1179 | /* get current_thread_info and current */ |
1080 | lis r1,secondary_ti@ha | 1180 | lis r1,secondary_ti@ha |
@@ -1111,6 +1211,112 @@ __secondary_hold_acknowledge: | |||
1111 | #endif | 1211 | #endif |
1112 | 1212 | ||
1113 | /* | 1213 | /* |
1214 | * Create a tlb entry with the same effective and physical address as | ||
1215 | * the tlb entry used by the current running code. But set the TS to 1. | ||
1216 | * Then switch to the address space 1. It will return with the r3 set to | ||
1217 | * the ESEL of the new created tlb. | ||
1218 | */ | ||
1219 | _GLOBAL(switch_to_as1) | ||
1220 | mflr r5 | ||
1221 | |||
1222 | /* Find a entry not used */ | ||
1223 | mfspr r3,SPRN_TLB1CFG | ||
1224 | andi. r3,r3,0xfff | ||
1225 | mfspr r4,SPRN_PID | ||
1226 | rlwinm r4,r4,16,0x3fff0000 /* turn PID into MAS6[SPID] */ | ||
1227 | mtspr SPRN_MAS6,r4 | ||
1228 | 1: lis r4,0x1000 /* Set MAS0(TLBSEL) = 1 */ | ||
1229 | addi r3,r3,-1 | ||
1230 | rlwimi r4,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ | ||
1231 | mtspr SPRN_MAS0,r4 | ||
1232 | tlbre | ||
1233 | mfspr r4,SPRN_MAS1 | ||
1234 | andis. r4,r4,MAS1_VALID@h | ||
1235 | bne 1b | ||
1236 | |||
1237 | /* Get the tlb entry used by the current running code */ | ||
1238 | bl 0f | ||
1239 | 0: mflr r4 | ||
1240 | tlbsx 0,r4 | ||
1241 | |||
1242 | mfspr r4,SPRN_MAS1 | ||
1243 | ori r4,r4,MAS1_TS /* Set the TS = 1 */ | ||
1244 | mtspr SPRN_MAS1,r4 | ||
1245 | |||
1246 | mfspr r4,SPRN_MAS0 | ||
1247 | rlwinm r4,r4,0,~MAS0_ESEL_MASK | ||
1248 | rlwimi r4,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ | ||
1249 | mtspr SPRN_MAS0,r4 | ||
1250 | tlbwe | ||
1251 | isync | ||
1252 | sync | ||
1253 | |||
1254 | mfmsr r4 | ||
1255 | ori r4,r4,MSR_IS | MSR_DS | ||
1256 | mtspr SPRN_SRR0,r5 | ||
1257 | mtspr SPRN_SRR1,r4 | ||
1258 | sync | ||
1259 | rfi | ||
1260 | |||
1261 | /* | ||
1262 | * Restore to the address space 0 and also invalidate the tlb entry created | ||
1263 | * by switch_to_as1. | ||
1264 | * r3 - the tlb entry which should be invalidated | ||
1265 | * r4 - __pa(PAGE_OFFSET in AS1) - __pa(PAGE_OFFSET in AS0) | ||
1266 | * r5 - device tree virtual address. If r4 is 0, r5 is ignored. | ||
1267 | * r6 - boot cpu | ||
1268 | */ | ||
1269 | _GLOBAL(restore_to_as0) | ||
1270 | mflr r0 | ||
1271 | |||
1272 | bl 0f | ||
1273 | 0: mflr r9 | ||
1274 | addi r9,r9,1f - 0b | ||
1275 | |||
1276 | /* | ||
1277 | * We may map the PAGE_OFFSET in AS0 to a different physical address, | ||
1278 | * so we need calculate the right jump and device tree address based | ||
1279 | * on the offset passed by r4. | ||
1280 | */ | ||
1281 | add r9,r9,r4 | ||
1282 | add r5,r5,r4 | ||
1283 | add r0,r0,r4 | ||
1284 | |||
1285 | 2: mfmsr r7 | ||
1286 | li r8,(MSR_IS | MSR_DS) | ||
1287 | andc r7,r7,r8 | ||
1288 | |||
1289 | mtspr SPRN_SRR0,r9 | ||
1290 | mtspr SPRN_SRR1,r7 | ||
1291 | sync | ||
1292 | rfi | ||
1293 | |||
1294 | /* Invalidate the temporary tlb entry for AS1 */ | ||
1295 | 1: lis r9,0x1000 /* Set MAS0(TLBSEL) = 1 */ | ||
1296 | rlwimi r9,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ | ||
1297 | mtspr SPRN_MAS0,r9 | ||
1298 | tlbre | ||
1299 | mfspr r9,SPRN_MAS1 | ||
1300 | rlwinm r9,r9,0,2,31 /* Clear MAS1 Valid and IPPROT */ | ||
1301 | mtspr SPRN_MAS1,r9 | ||
1302 | tlbwe | ||
1303 | isync | ||
1304 | |||
1305 | cmpwi r4,0 | ||
1306 | cmpwi cr1,r6,0 | ||
1307 | cror eq,4*cr1+eq,eq | ||
1308 | bne 3f /* offset != 0 && is_boot_cpu */ | ||
1309 | mtlr r0 | ||
1310 | blr | ||
1311 | |||
1312 | /* | ||
1313 | * The PAGE_OFFSET will map to a different physical address, | ||
1314 | * jump to _start to do another relocation again. | ||
1315 | */ | ||
1316 | 3: mr r3,r5 | ||
1317 | bl _start | ||
1318 | |||
1319 | /* | ||
1114 | * We put a few things here that have to be page-aligned. This stuff | 1320 | * We put a few things here that have to be page-aligned. This stuff |
1115 | * goes at the beginning of the data segment, which is page-aligned. | 1321 | * goes at the beginning of the data segment, which is page-aligned. |
1116 | */ | 1322 | */ |