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