summaryrefslogtreecommitdiffstats
path: root/rsnix/src/interrupts.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rsnix/src/interrupts.rs')
-rw-r--r--rsnix/src/interrupts.rs41
1 files changed, 41 insertions, 0 deletions
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 {
393 pub(crate) ss: u64, 393 pub(crate) ss: u64,
394} 394}
395 395
396// ---------------------------------------------------------------------------
397// Fault-dump re-entry guard
398// ---------------------------------------------------------------------------
399
400/// Set when `sched::fault_dump` is running. Any CPU exception that
401/// fires *while the dump is already in progress* (typically because the
402/// heap is corrupted and the dump path tripped over it) must never
403/// recurse into the dump — that chain (#PF → #DF → #PF) is a triple
404/// fault, which silently resets the machine with no report (black
405/// screen, firmware splash — exactly what real hardware showed). The
406/// guard short-circuits to a raw heap-free band and a hard halt.
407static mut IN_DUMP: bool = false;
408
409pub fn enter_dump() {
410 unsafe {
411 IN_DUMP = true;
412 }
413}
414
415fn in_dump() -> bool {
416 unsafe { IN_DUMP }
417}
418
419/// Raw, heap-free fallback: a fault fired inside the fault dump.
420fn dump_guard_halt() -> ! {
421 crate::gop::dump_lines(&[
422 "!!! fault inside fault dump",
423 "!!! halting (no triple fault)",
424 ]);
425 halt();
426}
427
396/// Called from the asm common handler — dispatches to the right Rust 428/// Called from the asm common handler — dispatches to the right Rust
397/// handler and returns the frame pointer the asm should switch to (the 429/// handler and returns the frame pointer the asm should switch to (the
398/// next task's, or the same one when no switch happens). 430/// next task's, or the same one when no switch happens).
@@ -433,9 +465,15 @@ unsafe extern "C" fn isr_dispatch(frame: &IntFrame) -> usize {
433 8 => { 465 8 => {
434 // Double fault — dump the frame (we're on the IST stack 466 // Double fault — dump the frame (we're on the IST stack
435 // so this is safe) and halt. 467 // so this is safe) and halt.
468 if in_dump() {
469 dump_guard_halt();
470 }
436 crate::sched::fault_dump("double fault", 0, frame) 471 crate::sched::fault_dump("double fault", 0, frame)
437 } 472 }
438 14 => { 473 14 => {
474 if in_dump() {
475 dump_guard_halt();
476 }
439 let cr2: u64; 477 let cr2: u64;
440 core::arch::asm!("mov {}, cr2", out(reg) cr2, 478 core::arch::asm!("mov {}, cr2", out(reg) cr2,
441 options(nostack, preserves_flags)); 479 options(nostack, preserves_flags));
@@ -445,6 +483,9 @@ unsafe extern "C" fn isr_dispatch(frame: &IntFrame) -> usize {
445 v if v < 32 => { 483 v if v < 32 => {
446 // Any other CPU exception: full dump (screen + serial), 484 // Any other CPU exception: full dump (screen + serial),
447 // then halt the shell or abort the faulting background task. 485 // then halt the shell or abort the faulting background task.
486 if in_dump() {
487 dump_guard_halt();
488 }
448 crate::sched::fault_dump("exception", 0, frame) 489 crate::sched::fault_dump("exception", 0, frame)
449 } 490 }
450 _ => fp, 491 _ => fp,