kernel_main on riscv64 ran directly on EDK2's UEFI boot-time stack, with no dedicated stack switch — amd64 has always had a kernel_entry.S trampoline for exactly this reason (its own comment: "the FORTH interpreter + DOE experiment loop can easily exceed that depth"). aarch64 happens to get away without one because its firmware's default stack is apparently larger, but that was never a guarantee. On riscv64 the VM bootstrap's call depth (27 word-registration modules -> physics/SSM init -> Tripod capsule birth) overflowed that small stack, corrupting a return address and producing a wild jump / page fault right after vm_init_with_host() returned — reproduced consistently across the 2026-08-01 DoE campaign logs. - src/starkernel/arch/riscv64/kernel_entry.S (new): RISC-V stack-switch trampoline mirroring amd64's, giving the kernel a dedicated 2 MiB BSS stack before anything deep runs. - kernel_main.c: riscv64 now builds kernel_main_impl (invoked via the trampoline) instead of kernel_main directly, same pattern as amd64. - Makefile.starkernel: wires the new file into the riscv64 build. - uefi_loader.c: RAW_LOG() was silently a no-op on every non-amd64 arch; added a real raw-UART writer for riscv64 (QEMU virt's uart8250 at MMIO 0x10000000) so existing loader diagnostics actually produce output. Verified: all three architectures boot clean to [Hera] ok> in the required order (amd64, aarch64, riscv64); logs and DoE CSVs from these runs included. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
70 lines
2.7 KiB
ArmAsm
70 lines
2.7 KiB
ArmAsm
/*
|
|
* kernel_entry.S — kernel stack setup and entry trampoline (riscv64)
|
|
*
|
|
* UEFI hands control to kernel_main() running on EDK2's own boot-time stack.
|
|
* Unlike amd64 (see arch/amd64/kernel_entry.S, which has carried this same
|
|
* trampoline since early on), riscv64 previously called straight into
|
|
* kernel_main_impl with no stack switch at all. The VM bootstrap's call
|
|
* depth (27 chained word-registration modules, physics/SSM init, capsule
|
|
* birth, Tripod fleet spawn) overflowed EDK2's riscv64 boot stack partway
|
|
* through vm_init_with_host()'s return, corrupting the return address and
|
|
* producing a wild jump shortly after — observed as a load/instruction
|
|
* page fault (scause 0xd or 0xc) whose exact address drifted between
|
|
* builds while the crash always landed in this same call region. amd64
|
|
* never had this problem because kernel_entry.S already switches to a
|
|
* dedicated 2 MiB BSS stack before anything deep runs; aarch64 apparently
|
|
* gets away with EDK2's default boot stack being large enough, but that's
|
|
* incidental, not a guarantee.
|
|
*
|
|
* kernel_main is the symbol the UEFI loader calls (extern in uefi_loader.c).
|
|
* kernel_main_impl is defined in kernel_main.c and contains all the C code.
|
|
*
|
|
* Calling convention: RISC-V LP64D — boot_info pointer arrives in a0 and is
|
|
* passed unchanged to kernel_main_impl via the tail-call.
|
|
*/
|
|
|
|
#include "starkernel/boot_info_offsets.h"
|
|
|
|
/* 2 MiB kernel stack in BSS — fallback when no dynamic stack requested */
|
|
.section .bss
|
|
.align 4
|
|
.global g_kernel_stack
|
|
g_kernel_stack:
|
|
.space 0x200000
|
|
g_kernel_stack_top:
|
|
.global g_kernel_stack_top
|
|
|
|
.section .text
|
|
.extern kernel_main_impl
|
|
|
|
/*
|
|
* kernel_main — stack-switch trampoline, then tail-call kernel_main_impl.
|
|
*
|
|
* a0 = BootInfo* (RISC-V LP64D ABI — first argument register)
|
|
*
|
|
* Stack selection (checked in order):
|
|
* 1. boot_info->kernel_stack_base != 0 → use loader-allocated stack
|
|
* (top = base + size, aligned down to 16)
|
|
* 2. Otherwise → fall back to g_kernel_stack (2 MiB BSS)
|
|
*
|
|
* Never returns; kernel_main_impl runs the REPL forever or panics.
|
|
*/
|
|
.global kernel_main
|
|
kernel_main:
|
|
ld t0, BOOT_INFO_KERNEL_STACK_BASE_OFFSET(a0)
|
|
bnez t0, .Ldynamic_stack
|
|
|
|
/* BSS fallback */
|
|
la t0, g_kernel_stack_top
|
|
j .Lstack_ready
|
|
|
|
.Ldynamic_stack:
|
|
ld t1, BOOT_INFO_KERNEL_STACK_SIZE_OFFSET(a0)
|
|
add t0, t0, t1 /* top = base + size (stack grows down) */
|
|
|
|
.Lstack_ready:
|
|
andi t0, t0, -16 /* 16-byte alignment (RISC-V psABI requirement) */
|
|
mv sp, t0
|
|
mv s0, zero /* terminate frame-pointer chain */
|
|
tail kernel_main_impl /* a0 (boot_info) already in place */
|