#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/pgtable.h>
#include <asm/asm_pointer_auth.h>
#include <asm/assembler.h>
#include <asm/boot.h>
#include <asm/bug.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
#include <asm/cache.h>
#include <asm/cputype.h>
#include <asm/el2_setup.h>
#include <asm/elf.h>
#include <asm/image.h>
#include <asm/kernel-pgtable.h>
#include <asm/kvm_arm.h>
#include <asm/memory.h>
#include <asm/pgtable-hwdef.h>
#include <asm/page.h>
#include <asm/scs.h>
#include <asm/smp.h>
#include <asm/sysreg.h>
#include <asm/stacktrace/frame.h>
#include <asm/thread_info.h>
#include <asm/virt.h>
#include "efi-header.S"
#if (PAGE_OFFSET & 0x1fffff) != 0
#error PAGE_OFFSET must be at least 2MB aligned
#endif
__HEAD
efi_signature_nop
b primary_entry
.quad 0
le64sym _kernel_size_le
le64sym _kernel_flags_le
.quad 0
.quad 0
.quad 0
.ascii ARM64_IMAGE_MAGIC
.long .Lpe_header_offset
__EFI_PE_HEADER
.section ".idmap.text","a"
SYM_CODE_START(primary_entry)
bl record_mmu_state
bl preserve_boot_args
adrp x1, early_init_stack
mov sp, x1
mov x29, xzr
adrp x0, __pi_init_idmap_pg_dir
mov x1, xzr
bl __pi_create_init_idmap
cbnz x19, 0f
dmb sy
mov x1, x0
adrp x0, __pi_init_idmap_pg_dir
adr_l x2, dcache_inval_poc
blr x2
b 1f
0: adrp x0, __idmap_text_start
adr_l x1, __idmap_text_end
adr_l x2, dcache_clean_poc
blr x2
1: mov x0, x19
bl init_kernel_el
mov x20, x0
bl __cpu_setup
b __primary_switch
SYM_CODE_END(primary_entry)
__INIT
SYM_CODE_START_LOCAL(record_mmu_state)
mrs x19, CurrentEL
cmp x19, #CurrentEL_EL2
mrs x19, sctlr_el1
b.ne 0f
mrs x19, sctlr_el2
0:
CPU_LE( tbnz x19, #SCTLR_ELx_EE_SHIFT, 1f )
CPU_BE( tbz x19, #SCTLR_ELx_EE_SHIFT, 1f )
tst x19, #SCTLR_ELx_C
and x19, x19, #SCTLR_ELx_M
csel x19, xzr, x19, eq
ret
1: eor x19, x19, #SCTLR_ELx_EE
bic x19, x19, #SCTLR_ELx_M
b.ne 2f
pre_disable_mmu_workaround
msr sctlr_el2, x19
b 3f
2: pre_disable_mmu_workaround
msr sctlr_el1, x19
3: isb
mov x19, xzr
ret
SYM_CODE_END(record_mmu_state)
SYM_CODE_START_LOCAL(preserve_boot_args)
mov x21, x0
adr_l x0, boot_args
stp x21, x1, [x0]
stp x2, x3, [x0, #16]
cbnz x19, 0f
dmb sy
add x1, x0, #0x20
b dcache_inval_poc
0: str_l x19, mmu_enabled_at_boot, x0
ret
SYM_CODE_END(preserve_boot_args)
.macro init_cpu_task tsk, tmp1, tmp2
msr sp_el0, \tsk
ldr \tmp1, [\tsk, #TSK_STACK]
add sp, \tmp1, #THREAD_SIZE
sub sp, sp, #PT_REGS_SIZE
stp xzr, xzr, [sp, #S_STACKFRAME]
mov \tmp1, #FRAME_META_TYPE_FINAL
str \tmp1, [sp, #S_STACKFRAME_TYPE]
add x29, sp, #S_STACKFRAME
scs_load_current
adr_l \tmp1, __per_cpu_offset
ldr w\tmp2, [\tsk, #TSK_TI_CPU]
ldr \tmp1, [\tmp1, \tmp2, lsl #3]
set_this_cpu_offset \tmp1
.endm
SYM_FUNC_START_LOCAL(__primary_switched)
adr_l x4, init_task
init_cpu_task x4, x5, x6
adr_l x8, vectors
msr vbar_el1, x8
isb
stp x29, x30, [sp, #-16]!
mov x29, sp
str_l x21, __fdt_pointer, x5
adrp x4, _text
sub x4, x4, x0
str_l x4, kimage_voffset, x5
mov x0, x20
bl set_cpu_boot_mode_flag
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
bl kasan_early_init
#endif
mov x0, x20
bl finalise_el2
ldp x29, x30, [sp], #16
bl start_kernel
ASM_BUG()
SYM_FUNC_END(__primary_switched)
.section ".idmap.text","a"
SYM_FUNC_START(init_kernel_el)
mrs x1, CurrentEL
cmp x1, #CurrentEL_EL2
b.eq init_el2
SYM_INNER_LABEL(init_el1, SYM_L_LOCAL)
mov_q x0, INIT_SCTLR_EL1_MMU_OFF
pre_disable_mmu_workaround
msr sctlr_el1, x0
isb
mov_q x0, INIT_PSTATE_EL1
msr spsr_el1, x0
msr elr_el1, lr
mov w0, #BOOT_CPU_MODE_EL1
eret
SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
msr elr_el2, lr
cbz x0, 0f
adrp x0, __hyp_idmap_text_start
adr_l x1, __hyp_text_end
adr_l x2, dcache_clean_poc
blr x2
mov_q x0, INIT_SCTLR_EL2_MMU_OFF
pre_disable_mmu_workaround
msr sctlr_el2, x0
isb
0:
init_el2_hcr HCR_HOST_NVHE_FLAGS | HCR_ATA
init_el2_state
adr_l x0, __hyp_stub_vectors
msr vbar_el2, x0
isb
mov_q x1, INIT_SCTLR_EL1_MMU_OFF
mrs x0, hcr_el2
and x0, x0, #HCR_E2H
cbz x0, 2f
msr_s SYS_SCTLR_EL12, x1
mov x2, #BOOT_CPU_FLAG_E2H
b 3f
2:
msr sctlr_el1, x1
mov x2, xzr
3:
mov x0, #INIT_PSTATE_EL1
msr spsr_el2, x0
mov w0, #BOOT_CPU_MODE_EL2
orr x0, x0, x2
eret
SYM_FUNC_END(init_kernel_el)
SYM_FUNC_START(secondary_holding_pen)
mov x0, xzr
bl init_kernel_el
mrs x2, mpidr_el1
mov_q x1, MPIDR_HWID_BITMASK
and x2, x2, x1
adr_l x3, secondary_holding_pen_release
pen: ldr x4, [x3]
cmp x4, x2
b.eq secondary_startup
wfe
b pen
SYM_FUNC_END(secondary_holding_pen)
SYM_FUNC_START(secondary_entry)
mov x0, xzr
bl init_kernel_el
b secondary_startup
SYM_FUNC_END(secondary_entry)
SYM_FUNC_START_LOCAL(secondary_startup)
mov x20, x0
#ifdef CONFIG_ARM64_VA_BITS_52
alternative_if ARM64_HAS_VA52
bl __cpu_secondary_check52bitva
alternative_else_nop_endif
#endif
bl __cpu_setup
adrp x1, swapper_pg_dir
adrp x2, idmap_pg_dir
bl __enable_mmu
ldr x8, =__secondary_switched
br x8
SYM_FUNC_END(secondary_startup)
.text
SYM_FUNC_START_LOCAL(__secondary_switched)
mov x0, x20
bl set_cpu_boot_mode_flag
mov x0, x20
bl finalise_el2
str_l xzr, __early_cpu_boot_status, x3
adr_l x5, vectors
msr vbar_el1, x5
isb
adr_l x0, secondary_data
ldr x2, [x0, #CPU_BOOT_TASK]
cbz x2, __secondary_too_slow
init_cpu_task x2, x1, x3
#ifdef CONFIG_ARM64_PTR_AUTH
ptrauth_keys_init_cpu x2, x3, x4, x5
#endif
bl secondary_start_kernel
ASM_BUG()
SYM_FUNC_END(__secondary_switched)
SYM_FUNC_START_LOCAL(__secondary_too_slow)
wfe
wfi
b __secondary_too_slow
SYM_FUNC_END(__secondary_too_slow)
SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
adr_l x1, __boot_cpu_mode
cmp w0, #BOOT_CPU_MODE_EL2
b.ne 1f
add x1, x1, #4
1: str w0, [x1]
ret
SYM_FUNC_END(set_cpu_boot_mode_flag)
.macro update_early_cpu_boot_status status, tmp1, tmp2
mov \tmp2, #\status
adr_l \tmp1, __early_cpu_boot_status
str \tmp2, [\tmp1]
dmb sy
dc ivac, \tmp1
.endm
.section ".idmap.text","a"
SYM_FUNC_START(__enable_mmu)
mrs x3, ID_AA64MMFR0_EL1
ubfx x3, x3, #ID_AA64MMFR0_EL1_TGRAN_SHIFT, 4
cmp x3, #ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN
b.lt __no_granule_support
cmp x3, #ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX
b.gt __no_granule_support
phys_to_ttbr x2, x2
msr ttbr0_el1, x2
load_ttbr1 x1, x1, x3
set_sctlr_el1 x0
ret
SYM_FUNC_END(__enable_mmu)
#ifdef CONFIG_ARM64_VA_BITS_52
SYM_FUNC_START(__cpu_secondary_check52bitva)
#ifndef CONFIG_ARM64_LPA2
mrs_s x0, SYS_ID_AA64MMFR2_EL1
and x0, x0, ID_AA64MMFR2_EL1_VARange_MASK
cbnz x0, 2f
#else
mrs x0, id_aa64mmfr0_el1
sbfx x0, x0, #ID_AA64MMFR0_EL1_TGRAN_SHIFT, 4
cmp x0, #ID_AA64MMFR0_EL1_TGRAN_LPA2
b.ge 2f
#endif
update_early_cpu_boot_status \
CPU_STUCK_IN_KERNEL | CPU_STUCK_REASON_52_BIT_VA, x0, x1
1: wfe
wfi
b 1b
2: ret
SYM_FUNC_END(__cpu_secondary_check52bitva)
#endif
SYM_FUNC_START_LOCAL(__no_granule_support)
update_early_cpu_boot_status \
CPU_STUCK_IN_KERNEL | CPU_STUCK_REASON_NO_GRAN, x1, x2
1:
wfe
wfi
b 1b
SYM_FUNC_END(__no_granule_support)
SYM_FUNC_START_LOCAL(__primary_switch)
adrp x1, reserved_pg_dir
adrp x2, __pi_init_idmap_pg_dir
bl __enable_mmu
adrp x1, early_init_stack
mov sp, x1
mov x29, xzr
mov x0, x20
mov x1, x21
bl __pi_early_map_kernel
ldr x8, =__primary_switched
adrp x0, KERNEL_START
br x8
SYM_FUNC_END(__primary_switch)