| 1 | /* SPDX-License-Identifier: GPL-2.0-only */
|
| 2 | /*
|
| 3 | * Low-level CPU initialisation
|
| 4 | * Based on arch/arm/kernel/head.S
|
| 5 | *
|
| 6 | * Copyright (C) 1994-2002 Russell King
|
| 7 | * Copyright (C) 2003-2012 ARM Ltd.
|
| 8 | * Authors: Catalin Marinas <catalin.marinas@arm.com>
|
| 9 | * Will Deacon <will.deacon@arm.com>
|
| 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 | * Kernel startup entry point.
|
| 47 | * ---------------------------
|
| 48 | *
|
| 49 | * The requirements are:
|
| 50 | * MMU = off, D-cache = off, I-cache = on or off,
|
| 51 | * x0 = physical address to the FDT blob.
|
| 52 | *
|
| 53 | * Note that the callee-saved registers are used for storing variables
|
| 54 | * that are useful before the MMU is enabled. The allocations are described
|
| 55 | * in the entry routines.
|
| 56 | */
|
| 57 | __HEAD
|
| 58 | /*
|
| 59 | * DO NOT MODIFY. Image header expected by Linux boot-loaders.
|
| 60 | */
|
| 61 | efi_signature_nop // special NOP to identity as PE/COFF executable
|
| 62 | b primary_entry // branch to kernel start, magic
|
| 63 | .quad 0 // Image load offset from start of RAM, little-endian
|
| 64 | le64sym _kernel_size_le // Effective size of kernel image, little-endian
|
| 65 | le64sym _kernel_flags_le // Informative flags, little-endian
|
| 66 | .quad 0 // reserved
|
| 67 | .quad 0 // reserved
|
| 68 | .quad 0 // reserved
|
| 69 | .ascii ARM64_IMAGE_MAGIC // Magic number
|
| 70 | .long .Lpe_header_offset // Offset to the PE header.
|
| 71 |
|
| 72 | __EFI_PE_HEADER
|
| 73 |
|
| 74 | .section ".idmap.text","a"
|
| 75 |
|
| 76 | /*
|
| 77 | * The following callee saved general purpose registers are used on the
|
| 78 | * primary lowlevel boot path:
|
| 79 | *
|
| 80 | * Register Scope Purpose
|
| 81 | * x19 primary_entry() .. start_kernel() whether we entered with the MMU on
|
| 82 | * x20 primary_entry() .. __primary_switch() CPU boot mode
|
| 83 | * x21 primary_entry() .. start_kernel() FDT pointer passed at boot in x0
|
| 84 | */
|
| 85 | SYM_CODE_START(primary_entry)
|
| 86 | bl record_mmu_state
|
| 87 | bl preserve_boot_args
|
| 88 |
|
| 89 | adrp x1, early_init_stack
|
| 90 | mov sp, x1
|
| 91 | mov x29, xzr
|
| 92 | adrp x0, __pi_init_idmap_pg_dir
|
| 93 | mov x1, xzr
|
| 94 | bl __pi_create_init_idmap
|
| 95 |
|
| 96 | /*
|
| 97 | * If the page tables have been populated with non-cacheable
|
| 98 | * accesses (MMU disabled), invalidate those tables again to
|
| 99 | * remove any speculatively loaded cache lines.
|
| 100 | */
|
| 101 | cbnz x19, 0f
|
| 102 | dmb sy
|
| 103 | mov x1, x0 // end of used region
|
| 104 | adrp x0, __pi_init_idmap_pg_dir
|
| 105 | adr_l x2, dcache_inval_poc
|
| 106 | blr x2
|
| 107 | b 1f
|
| 108 |
|
| 109 | /*
|
| 110 | * If we entered with the MMU and caches on, clean the ID mapped part
|
| 111 | * of the primary boot code to the PoC so we can safely execute it with
|
| 112 | * the MMU off.
|
| 113 | */
|
| 114 | 0: adrp x0, __idmap_text_start
|
| 115 | adr_l x1, __idmap_text_end
|
| 116 | adr_l x2, dcache_clean_poc
|
| 117 | blr x2
|
| 118 |
|
| 119 | 1: mov x0, x19
|
| 120 | bl init_kernel_el // w0=cpu_boot_mode
|
| 121 | mov x20, x0
|
| 122 |
|
| 123 | /*
|
| 124 | * The following calls CPU setup code, see arch/arm64/mm/proc.S for
|
| 125 | * details.
|
| 126 | * On return, the CPU will be ready for the MMU to be turned on and
|
| 127 | * the TCR will have been set.
|
| 128 | */
|
| 129 | bl __cpu_setup // initialise processor
|
| 130 | b __primary_switch
|
| 131 | SYM_CODE_END(primary_entry)
|
| 132 |
|
| 133 | __INIT
|
| 134 | SYM_CODE_START_LOCAL(record_mmu_state)
|
| 135 | mrs x19, CurrentEL
|
| 136 | cmp x19, |
| 137 | mrs x19, sctlr_el1
|
| 138 | b.ne 0f
|
| 139 | mrs x19, sctlr_el2
|
| 140 | 0:
|
| 141 | tbnz x19, |
| 142 | tst x19, |
| 143 | and x19, x19, |
| 144 | csel x19, xzr, x19, eq // clear x19 if Z
|
| 145 | ret
|
| 146 |
|
| 147 | /*
|
| 148 | * Set the correct endianness early so all memory accesses issued
|
| 149 | * before init_kernel_el() occur in the correct byte order. Note that
|
| 150 | * this means the MMU must be disabled, or the active ID map will end
|
| 151 | * up getting interpreted with the wrong byte order.
|
| 152 | */
|
| 153 | 1: eor x19, x19, |
| 154 | bic x19, x19, |
| 155 | b.ne 2f
|
| 156 | pre_disable_mmu_workaround
|
| 157 | msr sctlr_el2, x19
|
| 158 | b 3f
|
| 159 | 2: pre_disable_mmu_workaround
|
| 160 | msr sctlr_el1, x19
|
| 161 | 3: isb
|
| 162 | mov x19, xzr
|
| 163 | ret
|
| 164 | SYM_CODE_END(record_mmu_state)
|
| 165 |
|
| 166 | /*
|
| 167 | * Preserve the arguments passed by the bootloader in x0 .. x3
|
| 168 | */
|
| 169 | SYM_CODE_START_LOCAL(preserve_boot_args)
|
| 170 | mov x21, x0 // x21=FDT
|
| 171 |
|
| 172 | adr_l x0, boot_args // record the contents of
|
| 173 | stp x21, x1, [x0] // x0 .. x3 at kernel entry
|
| 174 | stp x2, x3, [x0, |
| 175 |
|
| 176 | cbnz x19, 0f // skip cache invalidation if MMU is on
|
| 177 | dmb sy // needed before dc ivac with
|
| 178 | // MMU off
|
| 179 |
|
| 180 | add x1, x0, |
| 181 | b dcache_inval_poc // tail call
|
| 182 | 0: str_l x19, mmu_enabled_at_boot, x0
|
| 183 | ret
|
| 184 | SYM_CODE_END(preserve_boot_args)
|
| 185 |
|
| 186 | /*
|
| 187 | * Initialize CPU registers with task-specific and cpu-specific context.
|
| 188 | *
|
| 189 | * Create a final frame record at task_pt_regs(current)->stackframe, so
|
| 190 | * that the unwinder can identify the final frame record of any task by
|
| 191 | * its location in the task stack. We reserve the entire pt_regs space
|
| 192 | * for consistency with user tasks and kthreads.
|
| 193 | */
|
| 194 | .macro init_cpu_task tsk, tmp1, tmp2
|
| 195 | msr sp_el0, \tsk
|
| 196 |
|
| 197 | ldr \tmp1, [\tsk, |
| 198 | add sp, \tmp1, |
| 199 | sub sp, sp, |
| 200 |
|
| 201 | stp xzr, xzr, [sp, |
| 202 | mov \tmp1, |
| 203 | str \tmp1, [sp, |
| 204 | add x29, sp, |
| 205 |
|
| 206 | scs_load_current
|
| 207 |
|
| 208 | adr_l \tmp1, __per_cpu_offset
|
| 209 | ldr w\tmp2, [\tsk, |
| 210 | ldr \tmp1, [\tmp1, \tmp2, lsl |
| 211 | set_this_cpu_offset \tmp1
|
| 212 | .endm
|
| 213 |
|
| 214 | /*
|
| 215 | * The following fragment of code is executed with the MMU enabled.
|
| 216 | *
|
| 217 | * x0 = __pa(KERNEL_START)
|
| 218 | */
|
| 219 | SYM_FUNC_START_LOCAL(__primary_switched)
|
| 220 | adr_l x4, init_task
|
| 221 | init_cpu_task x4, x5, x6
|
| 222 |
|
| 223 | adr_l x8, vectors // load VBAR_EL1 with virtual
|
| 224 | msr vbar_el1, x8 // vector table address
|
| 225 | isb
|
| 226 |
|
| 227 | stp x29, x30, [sp, |
| 228 | mov x29, sp
|
| 229 |
|
| 230 | str_l x21, __fdt_pointer, x5 // Save FDT pointer
|
| 231 |
|
| 232 | adrp x4, _text // Save the offset between
|
| 233 | sub x4, x4, x0 // the kernel virtual and
|
| 234 | str_l x4, kimage_voffset, x5 // physical mappings
|
| 235 |
|
| 236 | mov x0, x20
|
| 237 | bl set_cpu_boot_mode_flag
|
| 238 |
|
| 239 | |
| 240 | bl kasan_early_init
|
| 241 | |
| 242 | mov x0, x20
|
| 243 | bl finalise_el2 // Prefer VHE if possible
|
| 244 | ldp x29, x30, [sp], |
| 245 | bl start_kernel
|
| 246 | ASM_BUG()
|
| 247 | SYM_FUNC_END(__primary_switched)
|
| 248 |
|
| 249 | /*
|
| 250 | * end early head section, begin head code that is also used for
|
| 251 | * hotplug and needs to have the same protections as the text region
|
| 252 | */
|
| 253 | .section ".idmap.text","a"
|
| 254 |
|
| 255 | /*
|
| 256 | * Starting from EL2 or EL1, configure the CPU to execute at the highest
|
| 257 | * reachable EL supported by the kernel in a chosen default state. If dropping
|
| 258 | * from EL2 to EL1, configure EL2 before configuring EL1.
|
| 259 | *
|
| 260 | * Since we cannot always rely on ERET synchronizing writes to sysregs (e.g. if
|
| 261 | * SCTLR_ELx.EOS is clear), we place an ISB prior to ERET.
|
| 262 | *
|
| 263 | * Returns either BOOT_CPU_MODE_EL1 or BOOT_CPU_MODE_EL2 in x0 if
|
| 264 | * booted in EL1 or EL2 respectively, with the top 32 bits containing
|
| 265 | * potential context flags. These flags are *not* stored in __boot_cpu_mode.
|
| 266 | *
|
| 267 | * x0: whether we are being called from the primary boot path with the MMU on
|
| 268 | */
|
| 269 | SYM_FUNC_START(init_kernel_el)
|
| 270 | mrs x1, CurrentEL
|
| 271 | cmp x1, |
| 272 | b.eq init_el2
|
| 273 |
|
| 274 | SYM_INNER_LABEL(init_el1, SYM_L_LOCAL)
|
| 275 | mov_q x0, INIT_SCTLR_EL1_MMU_OFF
|
| 276 | pre_disable_mmu_workaround
|
| 277 | msr sctlr_el1, x0
|
| 278 | isb
|
| 279 | mov_q x0, INIT_PSTATE_EL1
|
| 280 | msr spsr_el1, x0
|
| 281 | msr elr_el1, lr
|
| 282 | mov w0, |
| 283 | eret
|
| 284 |
|
| 285 | SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
|
| 286 | msr elr_el2, lr
|
| 287 |
|
| 288 | // clean all HYP code to the PoC if we booted at EL2 with the MMU on
|
| 289 | cbz x0, 0f
|
| 290 | adrp x0, __hyp_idmap_text_start
|
| 291 | adr_l x1, __hyp_text_end
|
| 292 | adr_l x2, dcache_clean_poc
|
| 293 | blr x2
|
| 294 |
|
| 295 | mov_q x0, INIT_SCTLR_EL2_MMU_OFF
|
| 296 | pre_disable_mmu_workaround
|
| 297 | msr sctlr_el2, x0
|
| 298 | isb
|
| 299 | 0:
|
| 300 |
|
| 301 | init_el2_hcr HCR_HOST_NVHE_FLAGS | HCR_ATA
|
| 302 | init_el2_state
|
| 303 |
|
| 304 | /* Hypervisor stub */
|
| 305 | adr_l x0, __hyp_stub_vectors
|
| 306 | msr vbar_el2, x0
|
| 307 | isb
|
| 308 |
|
| 309 | mov_q x1, INIT_SCTLR_EL1_MMU_OFF
|
| 310 |
|
| 311 | mrs x0, hcr_el2
|
| 312 | and x0, x0, |
| 313 | cbz x0, 2f
|
| 314 |
|
| 315 | /* Set a sane SCTLR_EL1, the VHE way */
|
| 316 | msr_s SYS_SCTLR_EL12, x1
|
| 317 | mov x2, |
| 318 | b 3f
|
| 319 |
|
| 320 | 2:
|
| 321 | msr sctlr_el1, x1
|
| 322 | mov x2, xzr
|
| 323 | 3:
|
| 324 | mov x0, |
| 325 | msr spsr_el2, x0
|
| 326 |
|
| 327 | mov w0, |
| 328 | orr x0, x0, x2
|
| 329 | eret
|
| 330 | SYM_FUNC_END(init_kernel_el)
|
| 331 |
|
| 332 | /*
|
| 333 | * This provides a "holding pen" for platforms to hold all secondary
|
| 334 | * cores are held until we're ready for them to initialise.
|
| 335 | */
|
| 336 | SYM_FUNC_START(secondary_holding_pen)
|
| 337 | mov x0, xzr
|
| 338 | bl init_kernel_el // w0=cpu_boot_mode
|
| 339 | mrs x2, mpidr_el1
|
| 340 | mov_q x1, MPIDR_HWID_BITMASK
|
| 341 | and x2, x2, x1
|
| 342 | adr_l x3, secondary_holding_pen_release
|
| 343 | pen: ldr x4, [x3]
|
| 344 | cmp x4, x2
|
| 345 | b.eq secondary_startup
|
| 346 | wfe
|
| 347 | b pen
|
| 348 | SYM_FUNC_END(secondary_holding_pen)
|
| 349 |
|
| 350 | /*
|
| 351 | * Secondary entry point that jumps straight into the kernel. Only to
|
| 352 | * be used where CPUs are brought online dynamically by the kernel.
|
| 353 | */
|
| 354 | SYM_FUNC_START(secondary_entry)
|
| 355 | mov x0, xzr
|
| 356 | bl init_kernel_el // w0=cpu_boot_mode
|
| 357 | b secondary_startup
|
| 358 | SYM_FUNC_END(secondary_entry)
|
| 359 |
|
| 360 | SYM_FUNC_START_LOCAL(secondary_startup)
|
| 361 | /*
|
| 362 | * Common entry point for secondary CPUs.
|
| 363 | */
|
| 364 | mov x20, x0 // preserve boot mode
|
| 365 |
|
| 366 | #ifdef CONFIG_ARM64_VA_BITS_52
|
| 367 | alternative_if ARM64_HAS_VA52
|
| 368 | bl __cpu_secondary_check52bitva
|
| 369 | alternative_else_nop_endif
|
| 370 | #endif
|
| 371 |
|
| 372 | bl __cpu_setup // initialise processor
|
| 373 | adrp x1, swapper_pg_dir
|
| 374 | adrp x2, idmap_pg_dir
|
| 375 | bl __enable_mmu
|
| 376 | ldr x8, =__secondary_switched
|
| 377 | br x8
|
| 378 | SYM_FUNC_END(secondary_startup)
|
| 379 |
|
| 380 | .text
|
| 381 | SYM_FUNC_START_LOCAL(__secondary_switched)
|
| 382 | mov x0, x20
|
| 383 | bl set_cpu_boot_mode_flag
|
| 384 |
|
| 385 | mov x0, x20
|
| 386 | bl finalise_el2
|
| 387 |
|
| 388 | str_l xzr, __early_cpu_boot_status, x3
|
| 389 | adr_l x5, vectors
|
| 390 | msr vbar_el1, x5
|
| 391 | isb
|
| 392 |
|
| 393 | adr_l x0, secondary_data
|
| 394 | ldr x2, [x0, #CPU_BOOT_TASK]
|
| 395 | cbz x2, __secondary_too_slow
|
| 396 |
|
| 397 | init_cpu_task x2, x1, x3
|
| 398 |
|
| 399 | #ifdef CONFIG_ARM64_PTR_AUTH
|
| 400 | ptrauth_keys_init_cpu x2, x3, x4, x5
|
| 401 | #endif
|
| 402 |
|
| 403 | bl secondary_start_kernel
|
| 404 | ASM_BUG()
|
| 405 | SYM_FUNC_END(__secondary_switched)
|
| 406 |
|
| 407 | SYM_FUNC_START_LOCAL(__secondary_too_slow)
|
| 408 | wfe
|
| 409 | wfi
|
| 410 | b __secondary_too_slow
|
| 411 | SYM_FUNC_END(__secondary_too_slow)
|
| 412 |
|
| 413 | /*
|
| 414 | * Sets the __boot_cpu_mode flag depending on the CPU boot mode passed
|
| 415 | * in w0. See arch/arm64/include/asm/virt.h for more info.
|
| 416 | */
|
| 417 | SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
|
| 418 | adr_l x1, __boot_cpu_mode
|
| 419 | cmp w0, #BOOT_CPU_MODE_EL2
|
| 420 | b.ne 1f
|
| 421 | add x1, x1, #4
|
| 422 | 1: str w0, [x1] // Save CPU boot mode
|
| 423 | ret
|
| 424 | SYM_FUNC_END(set_cpu_boot_mode_flag)
|
| 425 |
|
| 426 | /*
|
| 427 | * The booting CPU updates the failed status @__early_cpu_boot_status,
|
| 428 | * with MMU turned off.
|
| 429 | *
|
| 430 | * update_early_cpu_boot_status tmp, status
|
| 431 | * - Corrupts tmp1, tmp2
|
| 432 | * - Writes 'status' to __early_cpu_boot_status and makes sure
|
| 433 | * it is committed to memory.
|
| 434 | */
|
| 435 |
|
| 436 | .macro update_early_cpu_boot_status status, tmp1, tmp2
|
| 437 | mov \tmp2, #\status
|
| 438 | adr_l \tmp1, __early_cpu_boot_status
|
| 439 | str \tmp2, [\tmp1]
|
| 440 | dmb sy
|
| 441 | dc ivac, \tmp1 // Invalidate potentially stale cache line
|
| 442 | .endm
|
| 443 |
|
| 444 | /*
|
| 445 | * Enable the MMU.
|
| 446 | *
|
| 447 | * x0 = SCTLR_EL1 value for turning on the MMU.
|
| 448 | * x1 = TTBR1_EL1 value
|
| 449 | * x2 = ID map root table address
|
| 450 | *
|
| 451 | * Returns to the caller via x30/lr. This requires the caller to be covered
|
| 452 | * by the .idmap.text section.
|
| 453 | *
|
| 454 | * Checks if the selected granule size is supported by the CPU.
|
| 455 | * If it isn't, park the CPU
|
| 456 | */
|
| 457 | .section ".idmap.text","a"
|
| 458 | SYM_FUNC_START(__enable_mmu)
|
| 459 | mrs x3, ID_AA64MMFR0_EL1
|
| 460 | ubfx x3, x3, |
| 461 | cmp x3, |
| 462 | b.lt __no_granule_support
|
| 463 | cmp x3, |
| 464 | b.gt __no_granule_support
|
| 465 | phys_to_ttbr x2, x2
|
| 466 | msr ttbr0_el1, x2 // load TTBR0
|
| 467 | load_ttbr1 x1, x1, x3
|
| 468 |
|
| 469 | set_sctlr_el1 x0
|
| 470 |
|
| 471 | ret
|
| 472 | SYM_FUNC_END(__enable_mmu)
|
| 473 |
|
| 474 | |
| 475 | SYM_FUNC_START(__cpu_secondary_check52bitva)
|
| 476 | |
| 477 | mrs_s x0, SYS_ID_AA64MMFR2_EL1
|
| 478 | and x0, x0, ID_AA64MMFR2_EL1_VARange_MASK
|
| 479 | cbnz x0, 2f
|
| 480 | |
| 481 | mrs x0, id_aa64mmfr0_el1
|
| 482 | sbfx x0, x0, |
| 483 | cmp x0, |
| 484 | b.ge 2f
|
| 485 | |
| 486 |
|
| 487 | update_early_cpu_boot_status \
|
| 488 | CPU_STUCK_IN_KERNEL | CPU_STUCK_REASON_52_BIT_VA, x0, x1
|
| 489 | 1: wfe
|
| 490 | wfi
|
| 491 | b 1b
|
| 492 |
|
| 493 | 2: ret
|
| 494 | SYM_FUNC_END(__cpu_secondary_check52bitva)
|
| 495 | |
| 496 |
|
| 497 | SYM_FUNC_START_LOCAL(__no_granule_support)
|
| 498 | /* Indicate that this CPU can't boot and is stuck in the kernel */
|
| 499 | update_early_cpu_boot_status \
|
| 500 | CPU_STUCK_IN_KERNEL | CPU_STUCK_REASON_NO_GRAN, x1, x2
|
| 501 | 1:
|
| 502 | wfe
|
| 503 | wfi
|
| 504 | b 1b
|
| 505 | SYM_FUNC_END(__no_granule_support)
|
| 506 |
|
| 507 | SYM_FUNC_START_LOCAL(__primary_switch)
|
| 508 | adrp x1, reserved_pg_dir
|
| 509 | adrp x2, __pi_init_idmap_pg_dir
|
| 510 | bl __enable_mmu
|
| 511 |
|
| 512 | adrp x1, early_init_stack
|
| 513 | mov sp, x1
|
| 514 | mov x29, xzr
|
| 515 | mov x0, x20 // pass the full boot status
|
| 516 | mov x1, x21 // pass the FDT
|
| 517 | bl __pi_early_map_kernel // Map and relocate the kernel
|
| 518 |
|
| 519 | ldr x8, =__primary_switched
|
| 520 | adrp x0, KERNEL_START // __pa(KERNEL_START)
|
| 521 | br x8
|
| 522 | SYM_FUNC_END(__primary_switch)
|