summaryrefslogtreecommitdiffstats
path: root/rsnix/src/sched.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rsnix/src/sched.rs99
1 files changed, 74 insertions, 25 deletions
diff --git a/rsnix/src/sched.rs b/rsnix/src/sched.rs
index f48e210..a195d1c 100644
--- a/rsnix/src/sched.rs
+++ b/rsnix/src/sched.rs
@@ -28,9 +28,7 @@ use core::fmt;
28use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; 28use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
29 29
30extern crate alloc; 30extern crate alloc;
31use alloc::format;
32use alloc::string::String; 31use alloc::string::String;
33use alloc::string::ToString;
34use alloc::vec::Vec; 32use alloc::vec::Vec;
35 33
36use crate::interrupts::IntFrame; 34use crate::interrupts::IntFrame;
@@ -40,7 +38,7 @@ use crate::paging;
40pub const MAX_TASKS: usize = 16; 38pub const MAX_TASKS: usize = 16;
41pub const SHELL_TID: usize = 0; 39pub const SHELL_TID: usize = 0;
42pub const IDLE_TID: usize = 1; 40pub const IDLE_TID: usize = 1;
43const STACK_PAGES: usize = 3; // 1 guard page + 8 KiB stack 41const STACK_PAGES: usize = 9; // 1 guard page + 32 KiB stack — faults dump on the task's own stack
44const NAME_MAX: usize = 24; 42const NAME_MAX: usize = 24;
45const PANIC_MAX: usize = 64; 43const PANIC_MAX: usize = 64;
46 44
@@ -556,8 +554,15 @@ pub fn abort_current(msg: &str) -> ! {
556/// Real hardware has no serial console, so the screen dump is what lets 554/// Real hardware has no serial console, so the screen dump is what lets
557/// a user report a crash precisely — vector, fault address, RIP and task. 555/// a user report a crash precisely — vector, fault address, RIP and task.
558/// Runs with interrupts disabled (we're inside the ISR). 556/// Runs with interrupts disabled (we're inside the ISR).
557///
558/// Heap-free by construction: the dump's own `alloc::format!` used to
559/// allocate from the heap, and when the underlying fault *was* heap
560/// corruption the reporter itself died (#PF → #DF → triple fault →
561/// silent reboot). Everything here formats into stack buffers, and the
562/// ISR `in_dump` guard halts instead of recursing if even that faults.
559#[allow(clippy::needless_return)] 563#[allow(clippy::needless_return)]
560pub(crate) fn fault_dump(kind: &str, cr2: u64, frame: &crate::interrupts::IntFrame) -> ! { 564pub(crate) fn fault_dump(kind: &str, cr2: u64, frame: &crate::interrupts::IntFrame) -> ! {
565 crate::interrupts::enter_dump();
561 let vector = frame.vector; 566 let vector = frame.vector;
562 let error = frame.error; 567 let error = frame.error;
563 let rip = frame.rip; 568 let rip = frame.rip;
@@ -565,35 +570,79 @@ pub(crate) fn fault_dump(kind: &str, cr2: u64, frame: &crate::interrupts::IntFra
565 let rsp = frame.rsp; 570 let rsp = frame.rsp;
566 let id = unsafe { CURRENT }; 571 let id = unsafe { CURRENT };
567 let name = name_str(id); 572 let name = name_str(id);
568 let name_buf = name.to_string();
569 let in_kernel = unsafe { CURRENT } <= IDLE_TID; 573 let in_kernel = unsafe { CURRENT } <= IDLE_TID;
570 574
571 // Serial: a full, parseable line. 575 // Serial: a full, parseable line (stack-formatted).
572 crate::serial_println!( 576 let mut buf = [0u8; 176];
573 "!!! {} vec={} err={:#x} rip={:#x} cr2={:#x} rsp={:#x} rflags={:#x} task={} \"{}\"", 577 let n = {
574 kind, 578 let mut w = crate::strbuf::FmtBuf::new(&mut buf);
575 vector, 579 let _ = fmt::write(
576 error, 580 &mut w,
577 rip, 581 core::format_args!(
578 cr2, 582 "!!! {} vec={} err={:#x} rip={:#x} cr2={:#x} rsp={:#x} rflags={:#x} task={} \"{}\"",
579 rsp, 583 kind,
580 rflags, 584 vector,
581 id, 585 error,
582 name_buf 586 rip,
583 ); 587 cr2,
584 crate::serial_println!("!!! halting (shell task fault — machine stops)"); 588 rsp,
585 589 rflags,
586 // Screen: white-on-red band via the clamped raw dump path. 590 id,
587 let l1 = alloc::format!("!!! {} vec={} err={:#x}", kind, vector, error); 591 name
588 let l2 = alloc::format!("rip={:#x} cr2={:#x}", rip, cr2); 592 ),
589 let l3 = alloc::format!("rsp={:#x} task={} {}", rsp, id, name_buf); 593 );
590 let lines = [l1.as_str(), l2.as_str(), l3.as_str()]; 594 w.len()
595 };
596 let line = core::str::from_utf8(&buf[..n]).unwrap_or("!!! dump");
597 crate::serial::write_str(line);
598 crate::serial::write_str("\r\n!!! halting (shell task fault — machine stops)\r\n");
599
600 // Screen: white-on-red band via the clamped raw dump path (heap-free).
601 let mut b1 = [0u8; 72];
602 let mut b2 = [0u8; 72];
603 let mut b3 = [0u8; 96];
604 let n1 = {
605 let mut w = crate::strbuf::FmtBuf::new(&mut b1);
606 let _ = fmt::write(
607 &mut w,
608 core::format_args!("!!! {} vec={} err={:#x}", kind, vector, error),
609 );
610 w.len()
611 };
612 let n2 = {
613 let mut w = crate::strbuf::FmtBuf::new(&mut b2);
614 let _ = fmt::write(&mut w, core::format_args!("rip={:#x} cr2={:#x}", rip, cr2));
615 w.len()
616 };
617 let n3 = {
618 let mut w = crate::strbuf::FmtBuf::new(&mut b3);
619 let _ = fmt::write(
620 &mut w,
621 core::format_args!("rsp={:#x} task={} {}", rsp, id, name),
622 );
623 w.len()
624 };
625 let l1 = core::str::from_utf8(&b1[..n1]).unwrap_or("!!!");
626 let l2 = core::str::from_utf8(&b2[..n2]).unwrap_or("");
627 let l3 = core::str::from_utf8(&b3[..n3]).unwrap_or("");
628 let lines = [l1, l2, l3];
591 crate::gop::dump_lines(&lines); 629 crate::gop::dump_lines(&lines);
592 630
631 // Best-effort: persist the report to the disk so it survives the
632 // reboot on real hardware (no serial console). Any fault here is
633 // caught by the in_dump guard and halts.
634 crate::fs::write_crash_log(&lines);
635
593 if in_kernel { 636 if in_kernel {
594 crate::interrupts::halt() 637 crate::interrupts::halt()
595 } else { 638 } else {
596 abort_current(&format!("{} vec={}", kind, vector)) 639 let mut mb = [0u8; 48];
640 let mn = {
641 let mut w = crate::strbuf::FmtBuf::new(&mut mb);
642 let _ = fmt::write(&mut w, core::format_args!("{} vec={}", kind, vector));
643 w.len()
644 };
645 abort_current(core::str::from_utf8(&mb[..mn]).unwrap_or("fault"))
597 } 646 }
598} 647}
599 648