summaryrefslogtreecommitdiff
path: root/Makefile
diff options
context:
space:
mode:
authorBradley Morgan <brads@mainlining.org>2026-10-03 20:02:29 +0000
committerBradley Morgan <brads@mainlining.org>2026-10-03 21:37:00 +0000
commit9dbdb15abf8ffb9dbdd972d6bbbcea9a3591e2a3 (patch)
tree0fc03f69c4ca60b3306afc7d3a7c86c1fee8437b /Makefile
tashaboot: arm64 bootloader
A small arm64 bootloader. No board code, no device tree porting, the architecture manual is the whole story: exception vectors in the fixed 16 slot layout (Table D1-7), ESR_ELx decoded by exception class (D1-2172), EL entry and eret chains per the programmers model (D1-2146), cache maintenance by set/way over the CLIDR_EL1 levels, semihosting for console and file io per DUI 0203, and the A64 boot protocol from Documentation/arch/arm64/booting.rst. The loader boots a stock mainline Image end to end on the qemu virt machine. Boot receipt with 7.3-rc3 (42MB Image): tashaboot 0.1 loaded 43450368 bytes at 40200000, entry 40200000 jumping [ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x411fd070] [ 0.000000] Linux version 7.3.0-rc3 [ 0.000000] Machine model: linux,dummy-virt [ 0.000000] earlycon: pl11 MMIO32:0x0000000009000000 ... ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs ]--- The panic is the expected end state, no root filesystem is handed over yet. The boot chain, state per stage, start to payload: +-----------+-----+--------------+----------------------------------+ | stage | EL | state | work | +-----------+-----+--------------+----------------------------------+ | firmware | any | MMU maybe on | x0 = dtb, jump in | +-----------+-----+--------------+----------------------------------+ | tashaboot | 3-2 | | SCR_EL3.NS = 1, eret to EL2 | +-----------+-----+--------------+----------------------------------+ | | 2 | virt scrub | HCR/CNTHCTL/CPTR/HSTR, CNTFRQ, | | | | | VBAR_EL2, MMU off, tlbi alle2 | +-----------+-----+--------------+----------------------------------+ | | 2 | | load Image over semihosting, | | | | | validate header, place per | | | | | booting.rst | +-----------+-----+--------------+----------------------------------+ | | 2 | caches clean | flush dcache, inval icache, | | | | | args ride x20/x21, regs last | +-----------+-----+--------------+----------------------------------+ | payload | 2 | fresh start | x0 = dtb, x1-x3 = 0, DAIF | | | | | masked, br to image entry | +-----------+-----+--------------+----------------------------------+ Two handoff bugs the kernel caught, both AAPCS clobbers in the final jump. Cache maintenance was called after the register setup, x0-x18 are caller saved, so tb_flush_dcache_all() wiped the dtb pointer and the kernel spun in setup_machine_fdt() with an invalid device tree blob. The flush helpers also clobbered x1 (u-boot's void call convention left mov x1, x0 in cache.S) which handed the kernel a wild x0. The arguments ride in x20/x21 across the cache calls now, callee saved, and the register setup is the last thing before the branch. What is missing on purpose: no SMP bringup (secondary cores park), no PSCI, no initrd or root filesystem handoff, single serial console. Those come next. Signed-off-by: Bradley Morgan <brads@mainlining.org>
Diffstat (limited to 'Makefile')
-rw-r--r--Makefile53
1 files changed, 53 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..be2cb63
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,53 @@
+# tashaboot
+#
+# build: make CROSS=aarch64-linux-gnu-
+# run: make run (qemu virt, semihosting, Image on the host)
+#
+# arm64 only. the architecture contract comes from the ARM ARM
+# (DDI 0487), the payload protocol from the kernel booting docs.
+
+CROSS ?= aarch64-linux-gnu-
+CC := $(CROSS)gcc
+LD := $(CROSS)ld
+OBJCOPY := $(CROSS)objcopy
+
+CFLAGS := -nostdlib -ffreestanding -mgeneral-regs-only \
+ -fno-builtin -fno-stack-protector -fno-pie -no-pie \
+ -Wall -Werror -O2 \
+ -Iinclude -Iarch/arm64/include
+
+LDFLAGS := -T arch/arm64/kernel/tashaboot.lds
+
+OBJS := arch/arm64/kernel/start.o \
+ arch/arm64/kernel/exceptions.o \
+ arch/arm64/kernel/halt.o \
+ arch/arm64/kernel/boot.o \
+ arch/arm64/lib/cache.o \
+ arch/arm64/lib/semihosting.o \
+ common/main.o common/console.o common/image.o common/load.o \
+ lib/printf.o lib/itoa.o lib/semihosting.o \
+ $(patsubst %.c,%.o,$(wildcard lib/string/*.c))
+
+all: build/tashaboot.bin
+
+build/tashaboot.elf: $(OBJS) arch/arm64/kernel/tashaboot.lds
+ mkdir -p build
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+build/tashaboot.bin: build/tashaboot.elf
+ $(OBJCOPY) -O binary $< $@
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.S
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+run: all
+ qemu-system-aarch64 -M virt -cpu cortex-a57 -nographic -no-reboot \
+ -semihosting -kernel build/tashaboot.bin
+
+clean:
+ rm -rf build $(OBJS)
+
+.PHONY: all run clean