Adds a one-time boot diagnostic in kernel_main.c, right before sk_repl()
is entered: bounded wait for 3 real heartbeat ticks, then prints tick
count, TIME-TRUST, and variance. Needed because printing immediately
after apic_timer_start() (as first tried) measured 1 tick on amd64 and
0 on riscv64 -- not evidence the heartbeat doesn't work, just that
almost no wall time elapses between arming the timer and that point in
boot; report it honestly rather than let it stand as a false negative.
Verified this session (logs/20260804-001727, -001805, -001850,
-001948, -002021):
- All three architectures boot to ok>.
- Tick count non-zero: amd64 4, riscv64 3, aarch64 3.
- riscv64: trust=Q48_ONE exactly, variance=0 -- architecturally
invariant counter, as designed.
- amd64: dict_hash=0x3d4e1daf289da94f, identical to the pre-item-0.8
baseline (logs/20260803-231322) -- unchanged output, satisfying the
GAP-A1 control.
- Two consecutive amd64 boots produced the identical dict hash --
reproducible, no wall-clock leakage into patron state.
Phase 0 (Substrate) is complete.
Punch list §25 item 0.10 complete.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>