#include "opt_arm_debug.h"
#include "opt_console.h"
#include "opt_cpuoptions.h"
#include "opt_ddb.h"
#include "opt_fdt.h"
#include "opt_kasan.h"
#include "opt_multiprocessor.h"
#include <aarch64/asm.h>
#include <aarch64/hypervisor.h>
#include "assym.h"
RCSID("$NetBSD: locore.S,v 1.107 2026/07/11 12:23:51 skrll Exp $")
#ifdef AARCH64_DEVICE_MEM_NONPOSTED
#define MAIR_DEVICE_MEM MAIR_DEVICE_nGnRnE
#else
#define MAIR_DEVICE_MEM MAIR_DEVICE_nGnRE
#endif
#define MAIR_DEVICE_MEM_NP MAIR_DEVICE_nGnRnE
#define LOCORE_EL2
#define BOOT_AP_STACKSIZE 256
#define PMAPBOOT_PAGEALLOCMAX (1024 * 1024)
#if (defined(VERBOSE_INIT_ARM) || defined(DEBUG_LOCORE)) && defined(EARLYCONS)
#if !defined(CONSADDR)
#error CONSADDR required with EARLYCONS
#endif
#define VERBOSE_LOCORE
#endif
#ifdef VERBOSE_LOCORE
#define VPRINT(string) PRINT(string)
#else
#define VPRINT(string)
#endif
#if (defined(DEBUG_LOCORE) && defined(EARLYCONS))
#define DPRINT(string) PRINT(string)
#define DPRINTREG(str, reg) mov x19,reg; PRINT(str); mov x0,x19; bl print_x0
#define DPRINTSREG(str, reg) mrs x19,reg; PRINT(str); mov x0,x19; bl print_x0
#define CPU_DPRINT(str) \
bl locore_lock_enter; \
bl printcpu; \
DPRINT(str); \
bl locore_lock_exit
#define CPU_DPRINTREG(str,reg) \
mov x19, reg; \
bl locore_lock_enter; \
bl printcpu; \
PRINT(str); \
mov x0, x19; \
bl print_x0; \
bl locore_lock_exit
#define CPU_DPRINTSREG(str, reg) \
mrs x19, reg; \
CPU_DPRINTREG(str, x19)
#else
#define DPRINT(string)
#define DPRINTREG(str, reg)
#define DPRINTSREG(str, reg)
#define CPU_DPRINT(str)
#define CPU_DPRINTREG(str,reg)
#define CPU_DPRINTSREG(str, reg)
#endif
#define PRINT(string) bl xprint; .asciz string; .align 2
.text
.align 3
ASENTRY_NP(aarch64_start)
mov x27, lr
mov x28, sp
adrl x0, bootstk
mov sp, x0
PRINT("boot NetBSD/aarch64\n")
bl 1f
1: DPRINTREG("PC = ", lr)
DPRINTREG("SP = ", sp)
mrs x20, CurrentEL
lsr x20, x20, #2
DPRINTREG("CurrentEL = ", x20)
cmp x20, #2
bcc 1f
DPRINTSREG("SCTLR_EL2 = ", sctlr_el2)
DPRINTSREG("TCR_EL2 = ", tcr_el2)
DPRINTSREG("HCR_EL2 = ", hcr_el2)
DPRINTSREG("VTTBR_EL2 = ", vttbr_el2)
DPRINTSREG("MAIR_EL2 = ", mair_el2)
#if 0
DPRINTSREG("ICH_VTR_EL2 = ", ich_vtr_el2)
#endif
1:
DPRINTSREG("SPSR_EL1 = ", spsr_el1)
DPRINTSREG("CNTFREQ_EL0 = ", cntfrq_el0)
DPRINTSREG("SCTLR_EL1 = ", sctlr_el1)
DPRINTSREG("MIDR_EL1 = ", midr_el1)
DPRINTSREG("MPIDR_EL1 = ", mpidr_el1)
DPRINTSREG("ID_AA64MPFR0_EL1 = ", id_aa64pfr0_el1)
DPRINTSREG("ID_AA64MPFR1_EL1 = ", id_aa64pfr1_el1)
DPRINTSREG("ID_AA64ISAR0_EL1 = ", id_aa64isar0_el1)
DPRINTSREG("ID_AA64ISAR1_EL1 = ", id_aa64isar1_el1)
DPRINTSREG("ID_AA64MMFR0_EL1 = ", id_aa64mmfr0_el1)
DPRINTSREG("ID_AA64MMFR1_EL1 = ", id_aa64mmfr1_el1)
#ifdef LOCORE_EL2
VPRINT("Drop to EL1...")
# include <aarch64/aarch64/locore_el2.S>
VPRINT("OK\n")
mrs x20, CurrentEL
lsr x20, x20, #2
DPRINTREG("CurrentEL = ", x20)
#endif
bl mmu_disable
bl init_sysregs
bl init_mmutable
cbnz x0, aarch64_fatal
bl save_ttbrs
VPRINT("MMU Enable...")
bl mmu_enable
VPRINT("OK\n")
ldr x20, =vstart
DPRINTSREG("SPSR_EL1 = ", spsr_el1)
DPRINTSREG("DAIF = ", daif)
DPRINTREG("vstart = ", x20)
br x20
aarch64_fatal:
PRINT("fatal error occurred while booting\n")
mov lr, x27
mov sp, x28
ret
vstart:
DPRINTREG("PC = ", x20)
adrl x0, _C_LABEL(el1_vectors)
msr vbar_el1, x0
adrl x0, lwp0uspace
add x0, x0, #(UPAGES * PAGE_SIZE)
sub x0, x0, #TF_SIZE
mov sp, x0
DPRINTREG("SP(lwp0,kvm) = ", sp)
msr tpidr_el0, xzr
msr tpidrro_el0, xzr
adrl x0, lwp0
msr tpidr_el1, x0
DPRINTREG("curlwp = ", x0);
mov x0, #1
bl aarch64_hafdbs_init
mov x0, #1
bl aarch64_pan_init
mov x0, #1
bl aarch64_pac_init
cbnz w0, 1f
mrs x0, sctlr_el1
ldr x1, sctlr_pac
orr x0, x0, x1
msr sctlr_el1, x0
isb
1:
adrl x19, cpu_info_store
mov x0, x19
bl cpu_setup_id
mov x0, x19
mrs x1, mpidr_el1
mov x2, #0
bl arm_cpu_topology_set
mov x0, x19
bl aarch64_getcacheinfo
mov x0, x19
bl aarch64_parsecacheinfo
#ifdef KASAN
adrl x0, lwp0uspace
bl _C_LABEL(kasan_early_init)
#endif
mov fp, #0
PRINT("initarm\n")
bl _C_LABEL(initarm)
PRINT("main\n")
bl _C_LABEL(main)
adr x0, .Lmainreturned
b _C_LABEL(panic)
ASEND(aarch64_start)
.Lmainreturned:
.asciz "main() returned"
.align 2
init_sysregs:
msr mdscr_el1, xzr
msr oslar_el1, xzr
msr contextidr_el1, xzr
msr cpacr_el1, xzr
isb
mov x0, #CNTKCTL_EL0VCTEN
msr cntkctl_el1, x0
ret
#ifdef MULTIPROCESSOR
#ifdef DEBUG_LOCORE
locore_lock_enter:
#ifdef DEBUG_LOCORE_PRINT_LOCK
mov x3, xzr
levelloop:
adrl x0, kern_vtopdiff
ldr x0, [x0]
ldr x4, =lock_level
sub x4, x4, x0
ldr x5, =lock_turn
sub x5, x5, x0
strh w3, [x4, x27, lsl #1]
dsb sy
strh w27, [x5, x3, lsl #1]
dsb sy
waitloop:
dmb sy
ldrh w0, [x5, x3, lsl #1]
cmp x27, x0
bne nextlevel
mov x2, xzr
levelcheck:
cmp x2, x27
beq levelcheck_next
dmb sy
ldrsh w0, [x4, x2, lsl #1]
cmp w0, w3
bge waitloop
levelcheck_next:
add x2, x2, #1
cmp x2, #MAXCPUS
bne levelcheck
nextlevel:
add x3, x3, #1
cmp x3, #(MAXCPUS - 1)
bne levelloop
#endif
ret
locore_lock_exit:
#ifdef DEBUG_LOCORE_PRINT_LOCK
adrl x0, kern_vtopdiff
ldr x0, [x0]
ldr x1, =lock_level
sub x1, x1, x0
mvn x0, xzr
strh w0, [x1, x27, lsl #1]
dsb sy
#endif
ret
printcpu:
stp x0, lr, [sp, #-16]!
PRINT("[CPU")
mov x0, x27
bl _printdec_x0
PRINT("] ")
ldp x0, lr, [sp], #16
ret
#endif
ENTRY_NP(cpu_mpstart)
mrs x8, CurrentEL
lsr x8, x8, #2
cmp x8, #0x2
b.lo 1f
mrs x8, sctlr_el2
#ifdef __AARCH64EB__
orr x8, x8, #SCTLR_EE
#else
bic x8, x8, #SCTLR_EE
#endif
msr sctlr_el2, x8
isb
1:
mrs x8, sctlr_el1
#ifdef __AARCH64EB__
orr x8, x8, #(SCTLR_EE | SCTLR_E0E)
#else
bic x8, x8, #(SCTLR_EE | SCTLR_E0E)
#endif
msr sctlr_el1, x8
isb
mrs x3, mpidr_el1
ldr x0, =(MPIDR_AFF0 | MPIDR_AFF1 | MPIDR_AFF2 | MPIDR_AFF3)
and x3, x3, x0
adrl x0, _C_LABEL(cpu_mpidr)
mov x1, xzr
1:
add x1, x1, #1
cmp x1, #MAXCPUS
bge toomanycpus
ldr x2, [x0, x1, lsl #3]
cmp x2, x3
bne 1b
mov x27, x1
mov x1, #BOOT_AP_STACKSIZE
mul x1, x1, x27
adrl x0, bootstk
add sp, x0, x1
bl 1f
1: CPU_DPRINTREG("PC = ", lr)
CPU_DPRINTREG("SP = ", sp)
mrs x20, CurrentEL
lsr x20, x20, #2
CPU_DPRINTREG("CurrentEL = ", x20)
cmp x20, #2
bcc 1f
CPU_DPRINTSREG("SCTLR_EL2 = ", sctlr_el2)
CPU_DPRINTSREG("TCR_EL2 = ", tcr_el2)
CPU_DPRINTSREG("HCR_EL2 = ", hcr_el2)
CPU_DPRINTSREG("VTTBR_EL2 = ", vttbr_el2)
CPU_DPRINTSREG("MAIR_EL2 = ", mair_el2)
1:
CPU_DPRINTSREG("SPSR_EL1 = ", spsr_el1)
CPU_DPRINTSREG("SCTLR_EL1 = ", sctlr_el1)
CPU_DPRINTSREG("MIDR_EL1 = ", midr_el1)
CPU_DPRINTSREG("MPIDR_EL1 = ", mpidr_el1)
#ifdef LOCORE_EL2
CPU_DPRINT("Drop to EL1...\n")
bl drop_to_el1
CPU_DPRINT("Drop to EL1 OK\n")
mrs x20, CurrentEL
lsr x20, x20, #2
CPU_DPRINTREG("CurrentEL = ", x20)
#endif
bl mmu_disable
bl init_sysregs
CPU_DPRINT("MMU Enable...\n")
bl load_ttbrs
bl mmu_enable
CPU_DPRINT("MMU Enable OK\n")
ldr x20, =mp_vstart
br x20
mp_vstart:
hint 0x24
adrl x0, kern_vtopdiff
ldr x0, [x0]
add sp, sp, x0
CPU_DPRINTREG("PC = ", x20)
CPU_DPRINTREG("SP = ", sp)
CPU_DPRINTSREG("TTBR0 = ", ttbr0_el1)
CPU_DPRINTSREG("TTBR1 = ", ttbr1_el1)
mrs x0, tcr_el1
orr x0, x0, #TCR_EPD0
msr tcr_el1, x0
isb
tlbi vmalle1
dsb nsh
isb
adrl x0, _C_LABEL(el1_vectors)
msr vbar_el1, x0
msr tpidr_el0, xzr
msr tpidrro_el0, xzr
mov x0, x27
bl cpu_init_secondary_processor
mov x0, #1
and x2, x27, #63
lsl x29, x0, x2
adrl x0, _C_LABEL(arm_cpu_mbox)
orr x1, xzr, x27, lsr #6
add x28, x0, x1, lsl #3
1:
ldar x20, [x28]
tst x20, x29
bne 9f
wfe
b 1b
9:
mov x0, #CPU_INFO_SIZE
mul x0, x27, x0
adrl x1, _C_LABEL(cpu_info_store)
add x0, x0, x1
ldr x1, [x0, #CI_IDLELWP]
msr tpidr_el1, x1
str x1, [x0, #CI_CURLWP]
ldr x2, [x1, #L_PCB]
add x2, x2, #(UPAGES * PAGE_SIZE)
sub sp, x2, #TF_SIZE
mov x0, #0
bl aarch64_hafdbs_init
mov x0, #0
bl aarch64_pan_init
mov x0, #0
bl aarch64_pac_init
cbnz w0, 1f
mrs x0, sctlr_el1
ldr x1, sctlr_pac
orr x0, x0, x1
msr sctlr_el1, x0
isb
1:
mov fp, xzr
mrs x0, tpidr_el1
ldr x0, [x0, #L_CPU]
bl _C_LABEL(cpu_hatch)
mov x0, xzr
b _C_LABEL(idle_loop)
END(cpu_mpstart)
toomanycpus:
CPU_DPRINT("too many cpus, or MPIDR does not exist in cpu_mpidr[]\n")
1: wfi
b 1b
#else
ENTRY_NP(cpu_mpstart)
1: wfi
b 1b
END(cpu_mpstart)
#endif
xprint:
mov x0, lr
bl _C_LABEL(uartputs)
add x0, x0, #3
bic lr, x0, #3
ret
ENTRY_NP(uartputs)
stp x19, lr, [sp, #-16]!
mov x19, x0
ldrb w0, [x19], #1
cbz w0, 9f
1:
cmp x0, #'\n'
bne 2f
mov x0, #0x0d
bl uartputc
mov x0, #'\n'
2:
bl uartputc
ldrb w0, [x19], #1
cbnz w0, 1b
9:
mov x0, x19
ldp x19, lr, [sp], #16
ret
END(uartputs)
_print_x0:
stp x0, lr, [sp, #-16]!
stp x20, x21, [sp, #-16]!
mov x21, x0
mov x20, #60
1:
ror x0, x21, x20
and x0, x0, #0xf
cmp x0, #10
blt 2f
add x0, x0, #('a' - 10 - '0')
2: add x0, x0, #'0'
bl uartputc
subs x20, x20, #4
bge 1b
ldp x20, x21, [sp], #16
ldp x0, lr, [sp], #16
ret
_printdec_x0:
stp x0, lr, [sp, #-(16+32)]!
add x8, sp, #(16+32)
strb wzr, [x8, #-1]!
1:
mov x10, #10
udiv x1, x0, x10
msub x3, x1, x10, x0
mov x0, x1
add x3, x3, #'0'
strb w3, [x8, #-1]!
cbnz x0, 1b
mov x0, x8
bl uartputs
ldp x0, lr, [sp], #(16+32)
ret
print_x0:
stp x0, lr, [sp, #-16]!
bl _print_x0
PRINT("\n")
ldp x0, lr, [sp], #16
ret
#ifdef VERBOSE_LOCORE
tinyprintf:
stp x0, lr, [sp, #-16]!
stp x19, x20, [sp, #-16]!
stp x7, x8, [sp, #-16]!
stp x5, x6, [sp, #-16]!
stp x3, x4, [sp, #-16]!
stp x1, x2, [sp, #-16]!
mov x20, xzr
mov x19, x0
ldrb w0, [x19], #1
cbz w0, tinyprintf_done
tinyprintf_loop:
cmp x0, #'\n'
bne 1f
mov x0, #0x0d
bl uartputc
mov x0, #'\n'
1:
cmp x0, #'%'
bne tinyprintf_putc
cmp x20, #8
bcs tinyprintf_putc
tinyprintf_fetch_fmt:
ldrb w9, [x19], #1
cbz w9, tinyprintf_done
cmp x9, #'h'
beq tinyprintf_fetch_fmt
cmp x9, #'l'
beq tinyprintf_fetch_fmt
cmp x9, #'j'
beq tinyprintf_fetch_fmt
cmp x9, #'t'
beq tinyprintf_fetch_fmt
cmp x9, #'z'
beq tinyprintf_fetch_fmt
cmp x9, #'0'
bcc 1f
cmp x9, #'9'
bls tinyprintf_fetch_fmt
1:
ldr x0, [sp, x20, lsl #3]
add x20, x20, #1
cmp x9, #'x'
bne 5f
bl _print_x0
b tinyprintf_next
5:
cmp x9, #'d'
bne 5f
bl _printdec_x0
b tinyprintf_next
5:
cmp x9, #'s'
bne 5f
bl _C_LABEL(uartputs)
b tinyprintf_next
5:
tinyprintf_putc:
bl uartputc
tinyprintf_next:
ldrb w0, [x19], #1
cbnz w0, tinyprintf_loop
tinyprintf_done:
mov x0, x19
ldp x1, x2, [sp], #16
ldp x3, x4, [sp], #16
ldp x5, x6, [sp], #16
ldp x7, x8, [sp], #16
ldp x19, x20, [sp], #16
ldp x0, lr, [sp], #16
ret
#endif
save_ttbrs:
mrs x0, ttbr0_el1
mrs x1, ttbr1_el1
adrl x2, ttbr_save
stp x0, x1, [x2]
ret
load_ttbrs:
adrl x2, ttbr_save
ldp x0, x1, [x2]
msr ttbr0_el1, x0
msr ttbr1_el1, x1
ret
init_mmutable:
stp x26, lr, [sp, #-16]!
bl pmapboot_pagealloc
cbz x0, init_mmutable_error
msr ttbr1_el1, x0
bl pmapboot_pagealloc
cbz x0, init_mmutable_error
msr ttbr0_el1, x0
DPRINTSREG("TTBR0 = ", ttbr0_el1)
DPRINTSREG("TTBR1 = ", ttbr1_el1)
#ifdef VERBOSE_LOCORE
adr x26, tinyprintf
#else
mov x26, xzr
#endif
#ifdef CONSADDR
VPRINT("Creating identity mapping for CONSADDR\n")
ldr x0, =CONSADDR
mov x1, x0
mov x2, #L2_SIZE
mov x3, #L2_SIZE
mov x4, #LX_BLKPAG_ATTR_DEVICE_MEM | LX_BLKPAG_AP_RW
orr x4, x4, #LX_BLKPAG_UXN | LX_BLKPAG_PXN
mov x5, x26
bl pmapboot_enter
#endif
VPRINT("Creating identity mapping for kernel image\n")
adrl x0, start
mov x1, x0
adrl x2, _end
sub x2, x2, x1
add x2, x2, #PMAPBOOT_PAGEALLOCMAX
mov x3, #L2_SIZE
mov x4, #LX_BLKPAG_ATTR_NORMAL_WB | LX_BLKPAG_AP_RW
orr x4, x4, #LX_BLKPAG_UXN
mov x5, x26
bl pmapboot_enter
#ifdef FDT
VPRINT("Creating identity mapping for FDT\n")
adrl x8, _C_LABEL(fdt_addr_r)
ldr x8, [x8]
mov x0, x8
mov x1, x8
mov x2, #L2_SIZE
mov x3, #L2_SIZE
mov x4, #LX_BLKPAG_ATTR_NORMAL_WB | LX_BLKPAG_AP_RW
orr x4, x4, #LX_BLKPAG_UXN | LX_BLKPAG_PXN
mov x5, x26
bl pmapboot_enter
#endif
VPRINT("Creating KVA=PA tables\n")
ldr x0, =start
adrl x1, start
adrl x2, _end
sub x2, x2, x1
mov x3, #L2_SIZE
mov x4, #LX_BLKPAG_ATTR_NORMAL_WB | LX_BLKPAG_AP_RW
orr x4, x4, #LX_BLKPAG_UXN
mov x5, x26
bl pmapboot_enter
VPRINT("OK\n");
mov x0, xzr
b init_mmutable_done
init_mmutable_error:
mvn x0, xzr
init_mmutable_done:
ldp x26, lr, [sp], #16
ret
mmu_disable:
dsb sy
mrs x0, sctlr_el1
bic x0, x0, SCTLR_M
msr sctlr_el1, x0
isb
ret
mmu_enable:
dsb sy
tlbi vmalle1
dsb nsh
isb
ldr x0, mair_setting
msr mair_el1, x0
isb
ldr x0, tcr_setting
mrs x1, id_aa64mmfr0_el1
bfi x0, x1, #32, #3
msr tcr_el1, x0
mrs x0, sctlr_el1
ldr x1, sctlr_clear
bic x0, x0, x1
ldr x1, sctlr_pac
bic x0, x0, x1
ldr x1, sctlr_set
orr x0, x0, x1
msr sctlr_el1, x0
isb
ret
.align 3
mair_setting:
.quad ( \
__SHIFTIN(MAIR_NORMAL_WB, MAIR_ATTR0) | \
__SHIFTIN(MAIR_NORMAL_NC, MAIR_ATTR1) | \
__SHIFTIN(MAIR_NORMAL_WT, MAIR_ATTR2) | \
__SHIFTIN(MAIR_DEVICE_MEM, MAIR_ATTR3) | \
__SHIFTIN(MAIR_DEVICE_MEM_NP, MAIR_ATTR4))
#define VIRT_BIT 48
#ifdef MULTIPROCESSOR
#define TCR_SHAREABLE (TCR_SH0_INNER | TCR_SH1_INNER)
#else
#define TCR_SHAREABLE (TCR_SH0_NONE | TCR_SH1_NONE)
#endif
tcr_setting:
.quad ( \
__SHIFTIN(64 - VIRT_BIT, TCR_T1SZ) | \
__SHIFTIN(64 - VIRT_BIT, TCR_T0SZ) | \
TCR_AS64K | \
TCR_TG1_4KB | TCR_TG0_4KB | \
TCR_ORGN0_WB_WA | \
TCR_IRGN0_WB_WA | \
TCR_ORGN1_WB_WA | \
TCR_IRGN1_WB_WA) | TCR_SHAREABLE
#ifdef AARCH64_ALIGNMENT_CHECK
#define SCTLR_A_CONFIG SCTLR_A
#else
#define SCTLR_A_CONFIG 0
#endif
#ifdef AARCH64_EL0_STACK_ALIGNMENT_CHECK
#define SCTLR_SA0_CONFIG SCTLR_SA0
#else
#define SCTLR_SA0_CONFIG 0
#endif
#ifdef AARCH64_EL1_STACK_ALIGNMENT_CHECK
#define SCTLR_SA_CONFIG SCTLR_SA
#else
#define SCTLR_SA_CONFIG 0
#endif
sctlr_set:
.quad ( \
SCTLR_LSMAOE | \
SCTLR_nTLSMD | \
SCTLR_UCI | \
SCTLR_SPAN | \
SCTLR_UCT | \
SCTLR_nTWE | \
SCTLR_nTWI | \
SCTLR_DZE | \
SCTLR_I | \
SCTLR_SED | \
SCTLR_C | \
SCTLR_M | \
SCTLR_EOS | \
SCTLR_SA0_CONFIG | \
SCTLR_SA_CONFIG | \
SCTLR_A_CONFIG | \
0)
sctlr_clear:
.quad ( \
SCTLR_IESB | \
SCTLR_WXN | \
SCTLR_UMA | \
SCTLR_ITD | \
SCTLR_nAA | \
SCTLR_CP15BEN | \
SCTLR_SA0 | \
SCTLR_SA | \
SCTLR_A | \
0)
sctlr_pac:
.quad ( \
SCTLR_EnIA | \
SCTLR_EnIB | \
SCTLR_EnDA | \
SCTLR_EnDB | \
0)
.L_devmap_addr:
.quad VM_KERNEL_IO_BASE
.data
#ifdef DEBUG_LOCORE_PRINT_LOCK
.align 2
lock_level:
.fill MAXCPUS, 2, -1
lock_turn:
.fill (MAXCPUS - 1), 2, -1
#endif
.align 3
ttbr_save:
.space 8 * 2
.bss
.align PGSHIFT
.global _C_LABEL(lwp0uspace)
_C_LABEL(lwp0uspace):
.space UPAGES * PAGE_SIZE
bootstk:
#ifdef MULTIPROCESSOR
.space BOOT_AP_STACKSIZE * (MAXCPUS - 1)
#endif
.section ".init_pagetable", "aw", %nobits
.align PGSHIFT
.global ARM_BOOTSTRAP_LxPT
ARM_BOOTSTRAP_LxPT:
l0pt_kern:
.section "_init_memory", "aw", %nobits
.align PGSHIFT