aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/head_fsl_booke.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/head_fsl_booke.S')
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S266
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
850: 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
1161:
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
1302: 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
165set_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 */
923get_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 */
10741: mr r3,r26 11561: 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
12281: 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
12390: 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
12730: 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
12852: 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 */
12951: 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 */
13163: 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 */