From c7d92071e1dd11c45999457b16554b4abaa73b28 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 2 Aug 2026 15:21:34 +0200 Subject: v0.5.5: crash reports go to a dedicated CRASHLOG USB stick The fault handler now writes crash.log to the volume labeled CRASHLOG (label-selected via fat::crash_vol), falling back to slot 0. On real hardware the boot USB may be unwritable, so a second stick labeled CRASHLOG survives the write; the shell auto-prints the previous crash report from it at next boot (read_crash_log resolves /disk//crash.log through the FAT path, since Disk nodes hold no cached children). - fat.rs: volume_label() + crash_vol() (no allocation) - fs.rs: write_crash_log targets crash_vol(); read_crash_log prefers the CRASHLOG disk node; drop now-unused first_disk() - mkdisk.sh: --label option - test-fault.sh: boots with a dedicated CRASHLOG stick (mkfs -F 32 -n CRASHLOG), verifies crash.log lands there and NOT on the ESP --- rsnix/src/interrupts.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'rsnix/src/interrupts.rs') diff --git a/rsnix/src/interrupts.rs b/rsnix/src/interrupts.rs index be252df..927e4f1 100644 --- a/rsnix/src/interrupts.rs +++ b/rsnix/src/interrupts.rs @@ -393,6 +393,38 @@ pub(crate) struct IntFrame { pub(crate) ss: u64, } +// --------------------------------------------------------------------------- +// Fault-dump re-entry guard +// --------------------------------------------------------------------------- + +/// Set when `sched::fault_dump` is running. Any CPU exception that +/// fires *while the dump is already in progress* (typically because the +/// heap is corrupted and the dump path tripped over it) must never +/// recurse into the dump — that chain (#PF → #DF → #PF) is a triple +/// fault, which silently resets the machine with no report (black +/// screen, firmware splash — exactly what real hardware showed). The +/// guard short-circuits to a raw heap-free band and a hard halt. +static mut IN_DUMP: bool = false; + +pub fn enter_dump() { + unsafe { + IN_DUMP = true; + } +} + +fn in_dump() -> bool { + unsafe { IN_DUMP } +} + +/// Raw, heap-free fallback: a fault fired inside the fault dump. +fn dump_guard_halt() -> ! { + crate::gop::dump_lines(&[ + "!!! fault inside fault dump", + "!!! halting (no triple fault)", + ]); + halt(); +} + /// Called from the asm common handler — dispatches to the right Rust /// handler and returns the frame pointer the asm should switch to (the /// next task's, or the same one when no switch happens). @@ -433,9 +465,15 @@ unsafe extern "C" fn isr_dispatch(frame: &IntFrame) -> usize { 8 => { // Double fault — dump the frame (we're on the IST stack // so this is safe) and halt. + if in_dump() { + dump_guard_halt(); + } crate::sched::fault_dump("double fault", 0, frame) } 14 => { + if in_dump() { + dump_guard_halt(); + } let cr2: u64; core::arch::asm!("mov {}, cr2", out(reg) cr2, options(nostack, preserves_flags)); @@ -445,6 +483,9 @@ unsafe extern "C" fn isr_dispatch(frame: &IntFrame) -> usize { v if v < 32 => { // Any other CPU exception: full dump (screen + serial), // then halt the shell or abort the faulting background task. + if in_dump() { + dump_guard_halt(); + } crate::sched::fault_dump("exception", 0, frame) } _ => fp, -- cgit v1.2.3