Files
LithosAnanake/src/starkernel/arch/riscv64/kernel_entry.S
T
Robert Allan JamesandClaude Sonnet 5 736627510b Fix riscv64 boot crash: add missing kernel stack trampoline
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>
2026-08-02 06:59:48 -04:00

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 */