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 58a3e632b6d5..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 _sdata @ 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) | ||
