diff options
Diffstat (limited to 'arch/arm64/kernel')
| -rw-r--r-- | arch/arm64/kernel/boot.S | 35 | ||||
| -rw-r--r-- | arch/arm64/kernel/start.S | 94 | ||||
| -rw-r--r-- | arch/arm64/kernel/tashaboot.lds | 67 |
3 files changed, 196 insertions, 0 deletions
diff --git a/arch/arm64/kernel/boot.S b/arch/arm64/kernel/boot.S new file mode 100644 index 0000000..8c656b1 --- /dev/null +++ b/arch/arm64/kernel/boot.S @@ -0,0 +1,35 @@ +/* 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 */ + mov x8, x0 + mov x0, x1 + mov x1, xzr + mov x2, xzr + mov x3, xzr + + /* clean the caches so the kernel reads the image from RAM */ + bl tb_flush_dcache_all + bl tb_invalidate_icache_all + + /* 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 + + br x8 +ENDPROC(tb_boot_linux) +.popsection diff --git a/arch/arm64/kernel/start.S b/arch/arm64/kernel/start.S new file mode 100644 index 0000000..776744c --- /dev/null +++ b/arch/arm64/kernel/start.S @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * tashaboot arm64 entry. firmware drops us here, usually at EL2 on + * qemu virt. we park the secondaries, drop to EL1, set the stack and + * hand the dtb pointer to C. + * + * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org> + */ + +#include <asm/macro.h> + +.section .text.boot +.globl _start +_start: + b reset + + .balign 8 +.globl _text_base +_text_base: + .quad 0x40000000 + +reset: + /* keep the dtb pointer before anything clobbers x0 */ + mov x19, x0 + + /* park secondary cores, they have nothing to do yet */ + mrs x0, mpidr_el1 + and x0, x0, #0xff + cbnz x0, park + + /* figure out which EL we got */ + mrs x0, CurrentEL + lsr x0, x0, #2 + cmp x0, #3 + b.eq from_el3 + cmp x0, #2 + b.eq from_el2 + cmp x0, #1 + b.eq el1_entry + b park + +from_el3: + /* EL3 is a dead end for us, drop through the EL2 path if we can */ + b park + +from_el2: + /* EL1 must be aarch64 */ + mov x0, #(1 << 31) + msr hcr_el2, x0 + + /* scrub the EL2 state so EL1 starts clean */ + msr cptr_el2, xzr + msr hstr_el2, xzr + mrs x0, cnthctl_el2 + orr x0, x0, #(3 << 0) + msr cnthctl_el2, x0 + msr vpidr_el2, xzr + + mov x0, #0x3c5 + msr scr_el3, x0 + + /* no MMU, no caches at EL1 yet */ + msr sctlr_el1, xzr + isb + + /* SPSR for EL1h with interrupts masked */ + mov x0, #0x3c5 + msr spsr_el2, x0 + adr x0, el1_entry + msr elr_el2, x0 + eret + +el1_entry: + /* stack for the bootloader, grows down from the image end */ + ldr x0, =__image_end + mov sp, x0 + + /* clear bss */ + ldr x0, =__bss_start + ldr x1, =__bss_end +1: cmp x0, x1 + b.hs 2f + str xzr, [x0], #8 + b 1b +2: + + /* dtb pointer into C arg 0 */ + mov x0, x19 + bl tashaboot_main + + /* if main returns there is nothing sensible to do */ +park: + wfe + b park diff --git a/arch/arm64/kernel/tashaboot.lds b/arch/arm64/kernel/tashaboot.lds new file mode 100644 index 0000000..4f8dfb1 --- /dev/null +++ b/arch/arm64/kernel/tashaboot.lds @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * tashaboot arm64 memory layout. one segment, loaded at the bottom of + * RAM, right where qemu -kernel drops a raw image on virt. + * + * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org> + */ + +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_start) + +SECTIONS +{ + . = 0x40000000; + + __image_copy_start = .; + _text_start = .; + + .text : + { + arch/arm64/kernel/start.o (.text.boot) + *(.text.boot) + *(.text*) + } + + . = ALIGN(8); + __text_end = .; + + .rodata : + { + *(SORT_BY_ALIGNMENT(.rodata*)) + } + + . = ALIGN(8); + __rodata_end = .; + + .data : + { + *(.data*) + } + + . = ALIGN(8); + __image_end = .; + + __bss_start = .; + .bss : + { + *(.bss*) + *(COMMON) + } + . = ALIGN(8); + __bss_end = .; + + __image_copy_end = .; + + /DISCARD/ : { *(.dynsym) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.ARM.attributes) } + /DISCARD/ : { *(.comment) } + /DISCARD/ : { *(.note*) } + /DISCARD/ : { *(.eh_frame*) } +} |
