Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | /* * linux/arch/arm/kernel/head-common.S * * Copyright (C) 1994-2002 Russell King * Copyright (c) 2003 ARM Limited * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #define ATAG_CORE 0x54410001 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) .type __switch_data, %object __switch_data: .long __mmap_switched .long __data_loc @ r4 .long __data_start @ r5 .long __bss_start @ r6 .long _end @ r7 .long processor_id @ r4 .long __machine_arch_type @ r5 .long __atags_pointer @ r6 .long cr_alignment @ r7 .long init_thread_union + THREAD_START_SP @ sp /* * The following fragment of code is executed with the MMU on in MMU mode, * and uses absolute addresses; this is not position independent. * * r0 = cp#15 control register * r1 = machine ID * r2 = atags pointer * r9 = processor ID */ .type __mmap_switched, %function __mmap_switched: adr r3, __switch_data + 4 ldmia r3!, {r4, r5, r6, r7} cmp r4, r5 @ Copy data segment if needed 1: cmpne r5, r6 ldrne fp, [r4], #4 strne fp, [r5], #4 bne 1b mov fp, #0 @ Clear BSS (and zero fp) 1: cmp r6, r7 strcc fp, [r6],#4 bcc 1b ldmia r3, {r4, r5, r6, r7, sp} str r9, [r4] @ Save processor ID str r1, [r5] @ Save machine type str r2, [r6] @ Save atags pointer bic r4, r0, #CR_A @ Clear 'A' bit stmia r7, {r0, r4} @ Save control register values b start_kernel /* * Exception handling. Something went wrong and we can't proceed. We * ought to tell the user, but since we don't have any guarantee that * we're even running on the right architecture, we do virtually nothing. * * If CONFIG_DEBUG_LL is set we try to print out something about the error * and hope for the best (useful if bootloader fails to pass a proper * machine ID for example). */ .type __error_p, %function __error_p: #ifdef CONFIG_DEBUG_LL adr r0, str_p1 bl printascii b __error str_p1: .asciz "\nError: unrecognized/unsupported processor variant.\n" .align #endif .type __error_a, %function __error_a: #ifdef CONFIG_DEBUG_LL mov r4, r1 @ preserve machine ID adr r0, str_a1 bl printascii mov r0, r4 bl printhex8 adr r0, str_a2 bl printascii adr r3, 3f ldmia r3, {r4, r5, r6} @ get machine desc list sub r4, r3, r4 @ get offset between virt&phys add r5, r5, r4 @ convert virt addresses to add r6, r6, r4 @ physical address space 1: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type bl printhex8 mov r0, #'\t' bl printch ldr r0, [r5, #MACHINFO_NAME] @ get machine name add r0, r0, r4 bl printascii mov r0, #'\n' bl printch add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc cmp r5, r6 blo 1b adr r0, str_a3 bl printascii b __error str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x" str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n" str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" .align #endif .type __error, %function __error: #ifdef CONFIG_ARCH_RPC /* * Turn the screen red on a error - RiscPC only. */ mov r0, #0x02000000 mov r3, #0x11 orr r3, r3, r3, lsl #8 orr r3, r3, r3, lsl #16 str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 #endif 1: mov r0, r0 b 1b /* * Read processor ID register (CP#15, CR0), and look up in the linker-built * supported processor list. Note that we can't use the absolute addresses * for the __proc_info lists since we aren't running with the MMU on * (and therefore, we are not in the correct address space). We have to * calculate the offset. * * r9 = cpuid * Returns: * r3, r4, r6 corrupted * r5 = proc_info pointer in physical address space * r9 = cpuid (preserved) */ .type __lookup_processor_type, %function __lookup_processor_type: adr r3, 3f ldmda r3, {r5 - r7} sub r3, r3, r7 @ get offset between virt&phys add r5, r5, r3 @ convert virt addresses to add r6, r6, r3 @ physical address space 1: ldmia r5, {r3, r4} @ value, mask and r4, r4, r9 @ mask wanted bits teq r3, r4 beq 2f add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) cmp r5, r6 blo 1b mov r5, #0 @ unknown processor 2: mov pc, lr /* * This provides a C-API version of the above function. */ ENTRY(lookup_processor_type) stmfd sp!, {r4 - r7, r9, lr} mov r9, r0 bl __lookup_processor_type mov r0, r5 ldmfd sp!, {r4 - r7, r9, pc} /* * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for * more information about the __proc_info and __arch_info structures. */ .long __proc_info_begin .long __proc_info_end 3: .long . .long __arch_info_begin .long __arch_info_end /* * Lookup machine architecture in the linker-build list of architectures. * Note that we can't use the absolute addresses for the __arch_info * lists since we aren't running with the MMU on (and therefore, we are * not in the correct address space). We have to calculate the offset. * * r1 = machine architecture number * Returns: * r3, r4, r6 corrupted * r5 = mach_info pointer in physical address space */ .type __lookup_machine_type, %function __lookup_machine_type: adr r3, 3b ldmia r3, {r4, r5, r6} sub r3, r3, r4 @ get offset between virt&phys add r5, r5, r3 @ convert virt addresses to add r6, r6, r3 @ physical address space 1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type teq r3, r1 @ matches loader number? beq 2f @ found add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc cmp r5, r6 blo 1b mov r5, #0 @ unknown machine 2: mov pc, lr /* * This provides a C-API version of the above function. */ ENTRY(lookup_machine_type) stmfd sp!, {r4 - r6, lr} mov r1, r0 bl __lookup_machine_type mov r0, r5 ldmfd sp!, {r4 - r6, pc} /* Determine validity of the r2 atags pointer. The heuristic requires * that the pointer be aligned, in the first 16k of physical RAM and * that the ATAG_CORE marker is first and present. Future revisions * of this function may be more lenient with the physical address and * may also be able to move the ATAGS block if necessary. * * r8 = machinfo * * Returns: * r2 either valid atags pointer, or zero * r5, r6 corrupted */ .type __vet_atags, %function __vet_atags: tst r2, #0x3 @ aligned? bne 1f ldr r5, [r2, #0] @ is first tag ATAG_CORE? subs r5, r5, #ATAG_CORE_SIZE bne 1f ldr r5, [r2, #4] ldr r6, =ATAG_CORE cmp r5, r6 bne 1f mov pc, lr @ atag pointer is ok 1: mov r2, #0 mov pc, lr |