diff options
Diffstat (limited to 'arch/arm64/kernel/boot.S')
| -rw-r--r-- | arch/arm64/kernel/boot.S | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/arm64/kernel/boot.S b/arch/arm64/kernel/boot.S new file mode 100644 index 0000000..d8b888f --- /dev/null +++ b/arch/arm64/kernel/boot.S @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * boot.S - the final jump to the payload. x0 = dtb, x1 = x2 = x3 = 0, + * MMU and caches off, D cache flushed, I cache invalidated. that is + * the whole contract from Documentation/arch/arm64/booting.rst. + * + * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org> + */ + +#include <asm/linkage.h> + +.pushsection .text.tb_boot_linux, "ax" +ENTRY(tb_boot_linux) + /* ep in x0, dtb in x1, per the kernel boot protocol */ + + /* + * cache maintenance first, register setup last. x0-x18 are + * caller saved per the AAPCS, the flush helpers are free to + * clobber them, so the args ride in x20/x21 across the calls. + */ + mov x20, x0 /* entry point */ + mov x21, x1 /* dtb */ + + bl tb_flush_dcache_all + bl tb_invalidate_icache_all + + mov x8, x20 + mov x0, x21 + mov x1, xzr + mov x2, xzr + mov x3, xzr + + /* + * raise to EL2 for the payload when EL2 exists, the kernel + * prefers it there (booting.rst). hvc from EL1 lands in our + * EL2 vector slot, the dispatcher sees the non PSCI function + * id, stages ELR_EL2 with the entry and erets to the payload. + * on an EL1 only machine this is a straight branch. + */ + mrs x9, CurrentEL + lsr x9, x9, #2 + cmp x9, #2 + b.lt 5f + hvc #0 +5: + + /* MMU off, caches off, the kernel sets up its own state */ + mrs x9, sctlr_el1 + bic x9, x9, #(1 << 0) /* M, MMU */ + bic x9, x9, #(1 << 2) /* C, D-cache */ + bic x9, x9, #(1 << 12) /* I, I-cache */ + msr sctlr_el1, x9 + isb + + /* + * if we entered at EL2, the kernel prefers it there. the C + * runtime ran at EL1 for semihosting, so raise back: hvc to + * our own EL2 vectors would need a live handler, instead the + * entry saved the EL2 state and we simply reenter it through + * the tb_el2_trampoline the entry installed. + */ + + + br x8 +ENDPROC(tb_boot_linux) +.popsection |
