diff options
Diffstat (limited to 'arch/arm/kernel/head-common.S')
-rw-r--r-- | arch/arm/kernel/head-common.S | 305 |
1 files changed, 159 insertions, 146 deletions
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index b9505aa267c0..bbecaac1e013 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S | |||
@@ -15,55 +15,6 @@ | |||
15 | #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) | 15 | #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) |
16 | #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2) | 16 | #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2) |
17 | 17 | ||
18 | .align 2 | ||
19 | .type __switch_data, %object | ||
20 | __switch_data: | ||
21 | .long __mmap_switched | ||
22 | .long __data_loc @ r4 | ||
23 | .long _data @ r5 | ||
24 | .long __bss_start @ r6 | ||
25 | .long _end @ r7 | ||
26 | .long processor_id @ r4 | ||
27 | .long __machine_arch_type @ r5 | ||
28 | .long __atags_pointer @ r6 | ||
29 | .long cr_alignment @ r7 | ||
30 | .long init_thread_union + THREAD_START_SP @ sp | ||
31 | |||
32 | /* | ||
33 | * The following fragment of code is executed with the MMU on in MMU mode, | ||
34 | * and uses absolute addresses; this is not position independent. | ||
35 | * | ||
36 | * r0 = cp#15 control register | ||
37 | * r1 = machine ID | ||
38 | * r2 = atags pointer | ||
39 | * r9 = processor ID | ||
40 | */ | ||
41 | __mmap_switched: | ||
42 | adr r3, __switch_data + 4 | ||
43 | |||
44 | ldmia r3!, {r4, r5, r6, r7} | ||
45 | cmp r4, r5 @ Copy data segment if needed | ||
46 | 1: cmpne r5, r6 | ||
47 | ldrne fp, [r4], #4 | ||
48 | strne fp, [r5], #4 | ||
49 | bne 1b | ||
50 | |||
51 | mov fp, #0 @ Clear BSS (and zero fp) | ||
52 | 1: cmp r6, r7 | ||
53 | strcc fp, [r6],#4 | ||
54 | bcc 1b | ||
55 | |||
56 | ARM( ldmia r3, {r4, r5, r6, r7, sp}) | ||
57 | THUMB( ldmia r3, {r4, r5, r6, r7} ) | ||
58 | THUMB( ldr sp, [r3, #16] ) | ||
59 | str r9, [r4] @ Save processor ID | ||
60 | str r1, [r5] @ Save machine type | ||
61 | str r2, [r6] @ Save atags pointer | ||
62 | bic r4, r0, #CR_A @ Clear 'A' bit | ||
63 | stmia r7, {r0, r4} @ Save control register values | ||
64 | b start_kernel | ||
65 | ENDPROC(__mmap_switched) | ||
66 | |||
67 | /* | 18 | /* |
68 | * Exception handling. Something went wrong and we can't proceed. We | 19 | * Exception handling. Something went wrong and we can't proceed. We |
69 | * ought to tell the user, but since we don't have any guarantee that | 20 | * ought to tell the user, but since we don't have any guarantee that |
@@ -73,21 +24,7 @@ ENDPROC(__mmap_switched) | |||
73 | * and hope for the best (useful if bootloader fails to pass a proper | 24 | * and hope for the best (useful if bootloader fails to pass a proper |
74 | * machine ID for example). | 25 | * machine ID for example). |
75 | */ | 26 | */ |
76 | __error_p: | 27 | __HEAD |
77 | #ifdef CONFIG_DEBUG_LL | ||
78 | adr r0, str_p1 | ||
79 | bl printascii | ||
80 | mov r0, r9 | ||
81 | bl printhex8 | ||
82 | adr r0, str_p2 | ||
83 | bl printascii | ||
84 | b __error | ||
85 | str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x" | ||
86 | str_p2: .asciz ").\n" | ||
87 | .align | ||
88 | #endif | ||
89 | ENDPROC(__error_p) | ||
90 | |||
91 | __error_a: | 28 | __error_a: |
92 | #ifdef CONFIG_DEBUG_LL | 29 | #ifdef CONFIG_DEBUG_LL |
93 | mov r4, r1 @ preserve machine ID | 30 | mov r4, r1 @ preserve machine ID |
@@ -97,7 +34,7 @@ __error_a: | |||
97 | bl printhex8 | 34 | bl printhex8 |
98 | adr r0, str_a2 | 35 | adr r0, str_a2 |
99 | bl printascii | 36 | bl printascii |
100 | adr r3, 4f | 37 | adr r3, __lookup_machine_type_data |
101 | ldmia r3, {r4, r5, r6} @ get machine desc list | 38 | ldmia r3, {r4, r5, r6} @ get machine desc list |
102 | sub r4, r3, r4 @ get offset between virt&phys | 39 | sub r4, r3, r4 @ get offset between virt&phys |
103 | add r5, r5, r4 @ convert virt addresses to | 40 | add r5, r5, r4 @ convert virt addresses to |
@@ -125,78 +62,6 @@ str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" | |||
125 | .align | 62 | .align |
126 | #endif | 63 | #endif |
127 | 64 | ||
128 | __error: | ||
129 | #ifdef CONFIG_ARCH_RPC | ||
130 | /* | ||
131 | * Turn the screen red on a error - RiscPC only. | ||
132 | */ | ||
133 | mov r0, #0x02000000 | ||
134 | mov r3, #0x11 | ||
135 | orr r3, r3, r3, lsl #8 | ||
136 | orr r3, r3, r3, lsl #16 | ||
137 | str r3, [r0], #4 | ||
138 | str r3, [r0], #4 | ||
139 | str r3, [r0], #4 | ||
140 | str r3, [r0], #4 | ||
141 | #endif | ||
142 | 1: mov r0, r0 | ||
143 | b 1b | ||
144 | ENDPROC(__error) | ||
145 | |||
146 | |||
147 | /* | ||
148 | * Read processor ID register (CP#15, CR0), and look up in the linker-built | ||
149 | * supported processor list. Note that we can't use the absolute addresses | ||
150 | * for the __proc_info lists since we aren't running with the MMU on | ||
151 | * (and therefore, we are not in the correct address space). We have to | ||
152 | * calculate the offset. | ||
153 | * | ||
154 | * r9 = cpuid | ||
155 | * Returns: | ||
156 | * r3, r4, r6 corrupted | ||
157 | * r5 = proc_info pointer in physical address space | ||
158 | * r9 = cpuid (preserved) | ||
159 | */ | ||
160 | __lookup_processor_type: | ||
161 | adr r3, 3f | ||
162 | ldmia r3, {r5 - r7} | ||
163 | add r3, r3, #8 | ||
164 | sub r3, r3, r7 @ get offset between virt&phys | ||
165 | add r5, r5, r3 @ convert virt addresses to | ||
166 | add r6, r6, r3 @ physical address space | ||
167 | 1: ldmia r5, {r3, r4} @ value, mask | ||
168 | and r4, r4, r9 @ mask wanted bits | ||
169 | teq r3, r4 | ||
170 | beq 2f | ||
171 | add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) | ||
172 | cmp r5, r6 | ||
173 | blo 1b | ||
174 | mov r5, #0 @ unknown processor | ||
175 | 2: mov pc, lr | ||
176 | ENDPROC(__lookup_processor_type) | ||
177 | |||
178 | /* | ||
179 | * This provides a C-API version of the above function. | ||
180 | */ | ||
181 | ENTRY(lookup_processor_type) | ||
182 | stmfd sp!, {r4 - r7, r9, lr} | ||
183 | mov r9, r0 | ||
184 | bl __lookup_processor_type | ||
185 | mov r0, r5 | ||
186 | ldmfd sp!, {r4 - r7, r9, pc} | ||
187 | ENDPROC(lookup_processor_type) | ||
188 | |||
189 | /* | ||
190 | * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for | ||
191 | * more information about the __proc_info and __arch_info structures. | ||
192 | */ | ||
193 | .align 2 | ||
194 | 3: .long __proc_info_begin | ||
195 | .long __proc_info_end | ||
196 | 4: .long . | ||
197 | .long __arch_info_begin | ||
198 | .long __arch_info_end | ||
199 | |||
200 | /* | 65 | /* |
201 | * Lookup machine architecture in the linker-build list of architectures. | 66 | * Lookup machine architecture in the linker-build list of architectures. |
202 | * Note that we can't use the absolute addresses for the __arch_info | 67 | * Note that we can't use the absolute addresses for the __arch_info |
@@ -209,7 +74,7 @@ ENDPROC(lookup_processor_type) | |||
209 | * r5 = mach_info pointer in physical address space | 74 | * r5 = mach_info pointer in physical address space |
210 | */ | 75 | */ |
211 | __lookup_machine_type: | 76 | __lookup_machine_type: |
212 | adr r3, 4b | 77 | adr r3, __lookup_machine_type_data |
213 | ldmia r3, {r4, r5, r6} | 78 | ldmia r3, {r4, r5, r6} |
214 | sub r3, r3, r4 @ get offset between virt&phys | 79 | sub r3, r3, r4 @ get offset between virt&phys |
215 | add r5, r5, r3 @ convert virt addresses to | 80 | add r5, r5, r3 @ convert virt addresses to |
@@ -225,15 +90,16 @@ __lookup_machine_type: | |||
225 | ENDPROC(__lookup_machine_type) | 90 | ENDPROC(__lookup_machine_type) |
226 | 91 | ||
227 | /* | 92 | /* |
228 | * This provides a C-API version of the above function. | 93 | * Look in arch/arm/kernel/arch.[ch] for information about the |
94 | * __arch_info structures. | ||
229 | */ | 95 | */ |
230 | ENTRY(lookup_machine_type) | 96 | .align 2 |
231 | stmfd sp!, {r4 - r6, lr} | 97 | .type __lookup_machine_type_data, %object |
232 | mov r1, r0 | 98 | __lookup_machine_type_data: |
233 | bl __lookup_machine_type | 99 | .long . |
234 | mov r0, r5 | 100 | .long __arch_info_begin |
235 | ldmfd sp!, {r4 - r6, pc} | 101 | .long __arch_info_end |
236 | ENDPROC(lookup_machine_type) | 102 | .size __lookup_machine_type_data, . - __lookup_machine_type_data |
237 | 103 | ||
238 | /* Determine validity of the r2 atags pointer. The heuristic requires | 104 | /* Determine validity of the r2 atags pointer. The heuristic requires |
239 | * that the pointer be aligned, in the first 16k of physical RAM and | 105 | * that the pointer be aligned, in the first 16k of physical RAM and |
@@ -265,3 +131,150 @@ __vet_atags: | |||
265 | 1: mov r2, #0 | 131 | 1: mov r2, #0 |
266 | mov pc, lr | 132 | mov pc, lr |
267 | ENDPROC(__vet_atags) | 133 | ENDPROC(__vet_atags) |
134 | |||
135 | /* | ||
136 | * The following fragment of code is executed with the MMU on in MMU mode, | ||
137 | * and uses absolute addresses; this is not position independent. | ||
138 | * | ||
139 | * r0 = cp#15 control register | ||
140 | * r1 = machine ID | ||
141 | * r2 = atags pointer | ||
142 | * r9 = processor ID | ||
143 | */ | ||
144 | __INIT | ||
145 | __mmap_switched: | ||
146 | adr r3, __mmap_switched_data | ||
147 | |||
148 | ldmia r3!, {r4, r5, r6, r7} | ||
149 | cmp r4, r5 @ Copy data segment if needed | ||
150 | 1: cmpne r5, r6 | ||
151 | ldrne fp, [r4], #4 | ||
152 | strne fp, [r5], #4 | ||
153 | bne 1b | ||
154 | |||
155 | mov fp, #0 @ Clear BSS (and zero fp) | ||
156 | 1: cmp r6, r7 | ||
157 | strcc fp, [r6],#4 | ||
158 | bcc 1b | ||
159 | |||
160 | ARM( ldmia r3, {r4, r5, r6, r7, sp}) | ||
161 | THUMB( ldmia r3, {r4, r5, r6, r7} ) | ||
162 | THUMB( ldr sp, [r3, #16] ) | ||
163 | str r9, [r4] @ Save processor ID | ||
164 | str r1, [r5] @ Save machine type | ||
165 | str r2, [r6] @ Save atags pointer | ||
166 | bic r4, r0, #CR_A @ Clear 'A' bit | ||
167 | stmia r7, {r0, r4} @ Save control register values | ||
168 | b start_kernel | ||
169 | ENDPROC(__mmap_switched) | ||
170 | |||
171 | .align 2 | ||
172 | .type __mmap_switched_data, %object | ||
173 | __mmap_switched_data: | ||
174 | .long __data_loc @ r4 | ||
175 | .long _sdata @ r5 | ||
176 | .long __bss_start @ r6 | ||
177 | .long _end @ r7 | ||
178 | .long processor_id @ r4 | ||
179 | .long __machine_arch_type @ r5 | ||
180 | .long __atags_pointer @ r6 | ||
181 | .long cr_alignment @ r7 | ||
182 | .long init_thread_union + THREAD_START_SP @ sp | ||
183 | .size __mmap_switched_data, . - __mmap_switched_data | ||
184 | |||
185 | /* | ||
186 | * This provides a C-API version of __lookup_machine_type | ||
187 | */ | ||
188 | ENTRY(lookup_machine_type) | ||
189 | stmfd sp!, {r4 - r6, lr} | ||
190 | mov r1, r0 | ||
191 | bl __lookup_machine_type | ||
192 | mov r0, r5 | ||
193 | ldmfd sp!, {r4 - r6, pc} | ||
194 | ENDPROC(lookup_machine_type) | ||
195 | |||
196 | /* | ||
197 | * This provides a C-API version of __lookup_processor_type | ||
198 | */ | ||
199 | ENTRY(lookup_processor_type) | ||
200 | stmfd sp!, {r4 - r6, r9, lr} | ||
201 | mov r9, r0 | ||
202 | bl __lookup_processor_type | ||
203 | mov r0, r5 | ||
204 | ldmfd sp!, {r4 - r6, r9, pc} | ||
205 | ENDPROC(lookup_processor_type) | ||
206 | |||
207 | /* | ||
208 | * Read processor ID register (CP#15, CR0), and look up in the linker-built | ||
209 | * supported processor list. Note that we can't use the absolute addresses | ||
210 | * for the __proc_info lists since we aren't running with the MMU on | ||
211 | * (and therefore, we are not in the correct address space). We have to | ||
212 | * calculate the offset. | ||
213 | * | ||
214 | * r9 = cpuid | ||
215 | * Returns: | ||
216 | * r3, r4, r6 corrupted | ||
217 | * r5 = proc_info pointer in physical address space | ||
218 | * r9 = cpuid (preserved) | ||
219 | */ | ||
220 | __CPUINIT | ||
221 | __lookup_processor_type: | ||
222 | adr r3, __lookup_processor_type_data | ||
223 | ldmia r3, {r4 - r6} | ||
224 | sub r3, r3, r4 @ get offset between virt&phys | ||
225 | add r5, r5, r3 @ convert virt addresses to | ||
226 | add r6, r6, r3 @ physical address space | ||
227 | 1: ldmia r5, {r3, r4} @ value, mask | ||
228 | and r4, r4, r9 @ mask wanted bits | ||
229 | teq r3, r4 | ||
230 | beq 2f | ||
231 | add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) | ||
232 | cmp r5, r6 | ||
233 | blo 1b | ||
234 | mov r5, #0 @ unknown processor | ||
235 | 2: mov pc, lr | ||
236 | ENDPROC(__lookup_processor_type) | ||
237 | |||
238 | /* | ||
239 | * Look in <asm/procinfo.h> for information about the __proc_info structure. | ||
240 | */ | ||
241 | .align 2 | ||
242 | .type __lookup_processor_type_data, %object | ||
243 | __lookup_processor_type_data: | ||
244 | .long . | ||
245 | .long __proc_info_begin | ||
246 | .long __proc_info_end | ||
247 | .size __lookup_processor_type_data, . - __lookup_processor_type_data | ||
248 | |||
249 | __error_p: | ||
250 | #ifdef CONFIG_DEBUG_LL | ||
251 | adr r0, str_p1 | ||
252 | bl printascii | ||
253 | mov r0, r9 | ||
254 | bl printhex8 | ||
255 | adr r0, str_p2 | ||
256 | bl printascii | ||
257 | b __error | ||
258 | str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x" | ||
259 | str_p2: .asciz ").\n" | ||
260 | .align | ||
261 | #endif | ||
262 | ENDPROC(__error_p) | ||
263 | |||
264 | __error: | ||
265 | #ifdef CONFIG_ARCH_RPC | ||
266 | /* | ||
267 | * Turn the screen red on a error - RiscPC only. | ||
268 | */ | ||
269 | mov r0, #0x02000000 | ||
270 | mov r3, #0x11 | ||
271 | orr r3, r3, r3, lsl #8 | ||
272 | orr r3, r3, r3, lsl #16 | ||
273 | str r3, [r0], #4 | ||
274 | str r3, [r0], #4 | ||
275 | str r3, [r0], #4 | ||
276 | str r3, [r0], #4 | ||
277 | #endif | ||
278 | 1: mov r0, r0 | ||
279 | b 1b | ||
280 | ENDPROC(__error) | ||