feat: multi-arch ARM64/RISC-V bring-up with QEMU virt boot
ARM64 (AArch64):
- boot.S: EL2->EL1 transition, FP/SIMD enable (CPACR_EL1.FPEN),
BSS zeroing, 16KB stack
- PL011 UART at 0x09000000 for serial console
- Linker script at 0x40000000 with proper section alignment
- Stubs for kernel subsystems not yet ported (PMM, VMM, scheduler,
filesystem, syscalls, etc.)
RISC-V 64:
- boot.S: M-mode CSR init, BSS zeroing, 16KB stack
- NS16550 UART at 0x10000000 for serial console
- Linker script at 0x80000000 with proper section alignment
- Stubs matching ARM64 coverage
Build system:
- Makefile restructured: x86 gets full kernel/drivers/mm wildcards,
ARM/RISC-V get minimal KERNEL_COMMON set (main, console, utils,
cmdline, driver, cpu_features) + HAL + arch sources
- BOOT_OBJ now arch-specific (build/ARCH/arch/ARCH/boot.o)
- Added QEMU run targets: make run-arm, make run-riscv
- ARM64: -mno-outline-atomics to avoid libgcc atomic calls
Spinlock portability:
- Added AArch64 irq_save/irq_restore using DAIF register
- Simple volatile-flag spinlock for AArch64/RISC-V single-core
bring-up (exclusive monitors need cacheable memory / MMU)
Key bug fix:
- AArch64 variadic functions (kprintf etc.) trap without FP/SIMD
enabled — GCC saves q0-q7 in va_list register save area
Both architectures boot on QEMU virt and reach idle loop:
make ARCH=arm && make run-arm
make ARCH=riscv && make run-riscv
x86 unaffected: 35/35 smoke, 16/16 battery, cppcheck clean.