1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * linux/arch/arm/kernel/head-common.S 4 * 5 * Copyright (C) 1994-2002 Russell King 6 * Copyright (c) 2003 ARM Limited 7 * All Rights Reserved 8 */ 9#include <asm/assembler.h> 10 11#define ATAG_CORE 0x54410001 12#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) 13#define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2) 14 15#ifdef CONFIG_CPU_BIG_ENDIAN 16#define OF_DT_MAGIC 0xd00dfeed 17#else 18#define OF_DT_MAGIC 0xedfe0dd0 /* 0xd00dfeed in big-endian */ 19#endif 20 21/* 22 * Exception handling. Something went wrong and we can't proceed. We 23 * ought to tell the user, but since we don't have any guarantee that 24 * we're even running on the right architecture, we do virtually nothing. 25 * 26 * If CONFIG_DEBUG_LL is set we try to print out something about the error 27 * and hope for the best (useful if bootloader fails to pass a proper 28 * machine ID for example). 29 */ 30 __HEAD 31 32/* Determine validity of the r2 atags pointer. The heuristic requires 33 * that the pointer be aligned, in the first 16k of physical RAM and 34 * that the ATAG_CORE marker is first and present. If CONFIG_OF_FLATTREE 35 * is selected, then it will also accept a dtb pointer. Future revisions 36 * of this function may be more lenient with the physical address and 37 * may also be able to move the ATAGS block if necessary. 38 * 39 * Returns: 40 * r2 either valid atags pointer, valid dtb pointer, or zero 41 * r5, r6 corrupted 42 */ 43__vet_atags: 44 tst r2, #0x3 @ aligned? 45 bne 1f 46 47 ldr r5, [r2, #0] 48#ifdef CONFIG_OF_FLATTREE 49 ldr r6, =OF_DT_MAGIC @ is it a DTB? 50 cmp r5, r6 51 beq 2f 52#endif 53 cmp r5, #ATAG_CORE_SIZE @ is first tag ATAG_CORE? 54 cmpne r5, #ATAG_CORE_SIZE_EMPTY 55 bne 1f 56 ldr r5, [r2, #4] 57 ldr r6, =ATAG_CORE 58 cmp r5, r6 59 bne 1f 60 612: ret lr @ atag/dtb pointer is ok 62 631: mov r2, #0 64 ret lr 65ENDPROC(__vet_atags) 66 67/* 68 * The following fragment of code is executed with the MMU on in MMU mode, 69 * and uses absolute addresses; this is not position independent. 70 * 71 * r0 = cp#15 control register (exc_ret for M-class) 72 * r1 = machine ID 73 * r2 = atags/dtb pointer 74 * r9 = processor ID 75 */ 76 __INIT 77__mmap_switched: 78 79 mov r7, r1 80 mov r8, r2 81 mov r10, r0 82 83 adr r4, __mmap_switched_data 84 mov fp, #0 85 86#if defined(CONFIG_XIP_DEFLATED_DATA) 87 ARM( ldr sp, [r4], #4 ) 88 THUMB( ldr sp, [r4] ) 89 THUMB( add r4, #4 ) 90 bl __inflate_kernel_data @ decompress .data to RAM 91 teq r0, #0 92 bne __error 93#elif defined(CONFIG_XIP_KERNEL) 94 ARM( ldmia r4!, {r0, r1, r2, sp} ) 95 THUMB( ldmia r4!, {r0, r1, r2, r3} ) 96 THUMB( mov sp, r3 ) 97 sub r2, r2, r1 98 bl memcpy @ copy .data to RAM 99#endif 100 101 ARM( ldmia r4!, {r0, r1, sp} ) 102 THUMB( ldmia r4!, {r0, r1, r3} ) 103 THUMB( mov sp, r3 ) 104 sub r2, r1, r0 105 mov r1, #0 106 bl memset @ clear .bss 107 108 ldmia r4, {r0, r1, r2, r3} 109 str r9, [r0] @ Save processor ID 110 str r7, [r1] @ Save machine type 111 str r8, [r2] @ Save atags pointer 112 cmp r3, #0 113 strne r10, [r3] @ Save control register values 114 mov lr, #0 115 b start_kernel 116ENDPROC(__mmap_switched) 117 118 .align 2 119 .type __mmap_switched_data, %object 120__mmap_switched_data: 121#ifdef CONFIG_XIP_KERNEL 122#ifndef CONFIG_XIP_DEFLATED_DATA 123 .long _sdata @ r0 124 .long __data_loc @ r1 125 .long _edata_loc @ r2 126#endif 127 .long __bss_stop @ sp (temporary stack in .bss) 128#endif 129 130 .long __bss_start @ r0 131 .long __bss_stop @ r1 132 .long init_thread_union + THREAD_START_SP @ sp 133 134 .long processor_id @ r0 135 .long __machine_arch_type @ r1 136 .long __atags_pointer @ r2 137#ifdef CONFIG_CPU_CP15 138 .long cr_alignment @ r3 139#else 140M_CLASS(.long exc_ret) @ r3 141AR_CLASS(.long 0) @ r3 142#endif 143 .size __mmap_switched_data, . - __mmap_switched_data 144 145 __FINIT 146 .text 147 148/* 149 * This provides a C-API version of __lookup_processor_type 150 */ 151ENTRY(lookup_processor_type) 152 stmfd sp!, {r4 - r6, r9, lr} 153 mov r9, r0 154 bl __lookup_processor_type 155 mov r0, r5 156 ldmfd sp!, {r4 - r6, r9, pc} 157ENDPROC(lookup_processor_type) 158 159/* 160 * Read processor ID register (CP#15, CR0), and look up in the linker-built 161 * supported processor list. Note that we can't use the absolute addresses 162 * for the __proc_info lists since we aren't running with the MMU on 163 * (and therefore, we are not in the correct address space). We have to 164 * calculate the offset. 165 * 166 * r9 = cpuid 167 * Returns: 168 * r3, r4, r6 corrupted 169 * r5 = proc_info pointer in physical address space 170 * r9 = cpuid (preserved) 171 */ 172__lookup_processor_type: 173 adr r3, __lookup_processor_type_data 174 ldmia r3, {r4 - r6} 175 sub r3, r3, r4 @ get offset between virt&phys 176 add r5, r5, r3 @ convert virt addresses to 177 add r6, r6, r3 @ physical address space 1781: ldmia r5, {r3, r4} @ value, mask 179 and r4, r4, r9 @ mask wanted bits 180 teq r3, r4 181 beq 2f 182 add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) 183 cmp r5, r6 184 blo 1b 185 mov r5, #0 @ unknown processor 1862: ret lr 187ENDPROC(__lookup_processor_type) 188 189/* 190 * Look in <asm/procinfo.h> for information about the __proc_info structure. 191 */ 192 .align 2 193 .type __lookup_processor_type_data, %object 194__lookup_processor_type_data: 195 .long . 196 .long __proc_info_begin 197 .long __proc_info_end 198 .size __lookup_processor_type_data, . - __lookup_processor_type_data 199 200__error_lpae: 201#ifdef CONFIG_DEBUG_LL 202 adr r0, str_lpae 203 bl printascii 204 b __error 205str_lpae: .asciz "\nError: Kernel with LPAE support, but CPU does not support LPAE.\n" 206#else 207 b __error 208#endif 209 .align 210ENDPROC(__error_lpae) 211 212__error_p: 213#ifdef CONFIG_DEBUG_LL 214 adr r0, str_p1 215 bl printascii 216 mov r0, r9 217 bl printhex8 218 adr r0, str_p2 219 bl printascii 220 b __error 221str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x" 222str_p2: .asciz ").\n" 223 .align 224#endif 225ENDPROC(__error_p) 226 227__error: 228#ifdef CONFIG_ARCH_RPC 229/* 230 * Turn the screen red on a error - RiscPC only. 231 */ 232 mov r0, #0x02000000 233 mov r3, #0x11 234 orr r3, r3, r3, lsl #8 235 orr r3, r3, r3, lsl #16 236 str r3, [r0], #4 237 str r3, [r0], #4 238 str r3, [r0], #4 239 str r3, [r0], #4 240#endif 2411: mov r0, r0 242 b 1b 243ENDPROC(__error) 244