strat9_kernel/boot/
panic.rs1use core::{
2 panic::PanicInfo,
3 sync::atomic::{AtomicBool, Ordering},
4};
5use spin::Mutex;
6use x86_64::VirtAddr;
7
8type PanicHook = fn(&PanicInfo);
9const MAX_PANIC_HOOKS: usize = 8;
10
11static PANIC_HOOKS: Mutex<[Option<PanicHook>; MAX_PANIC_HOOKS]> =
12 Mutex::new([None; MAX_PANIC_HOOKS]);
13static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false);
14
15pub fn panic_in_progress() -> bool {
16 PANIC_IN_PROGRESS.load(Ordering::SeqCst)
17}
18
19pub fn register_panic_hook(hook: PanicHook) -> bool {
21 let mut hooks = PANIC_HOOKS.lock();
22 for slot in hooks.iter_mut() {
23 if slot.is_none() {
24 *slot = Some(hook);
25 return true;
26 }
27 }
28 false
29}
30
31fn run_panic_hooks(info: &PanicInfo) {
33 if let Some(hooks) = PANIC_HOOKS.try_lock() {
37 for hook in hooks.iter().flatten() {
38 hook(info);
39 }
40 }
41}
42
43fn panic_hook_dump_context(_info: &PanicInfo) {
45 let cpu = crate::arch::x86_64::percpu::current_cpu_index();
46 let ticks = crate::process::scheduler::ticks();
47 let cr3 = crate::memory::paging::active_page_table().as_u64();
48 crate::serial_println!("panic-hook: cpu={} ticks={} cr3=0x{:x}", cpu, ticks, cr3);
49 if let Some(task) = crate::process::scheduler::current_task_clone_try() {
52 crate::serial_println!(
53 "panic-hook: current_task id={} name={}",
54 task.id.as_u64(),
55 task.name
56 );
57 } else {
58 crate::serial_println!("panic-hook: current_task none (scheduler locked or idle)");
59 }
60 let sched = crate::process::scheduler::state_snapshot();
61 if cpu < sched.cpu_count {
62 crate::serial_println!(
63 "panic-hook: sched cpu={} current_tid={} need_resched={} rq(rt/fair/idle)={}/{}/{} blocked={} init={} phase={}",
64 cpu,
65 sched.current_task[cpu],
66 sched.need_resched[cpu],
67 sched.rq_rt[cpu],
68 sched.rq_fair[cpu],
69 sched.rq_idle[cpu],
70 sched.blocked_tasks,
71 sched.initialized,
72 sched.boot_phase
73 );
74 }
75 let fb = crate::arch::x86_64::vga::framebuffer_info();
76 crate::serial_println!(
77 "panic-hook: fb={}x{} {}bpp pitch={} text={}x{}",
78 fb.width,
79 fb.height,
80 fb.bpp,
81 fb.pitch,
82 fb.text_cols,
83 fb.text_rows
84 );
85}
86
87#[inline(always)]
89fn read_rbp() -> u64 {
90 let rbp: u64;
91 unsafe {
92 core::arch::asm!("mov {}, rbp", out(reg) rbp, options(nomem, nostack, preserves_flags));
93 }
94 rbp
95}
96
97#[inline(always)]
99fn read_rsp() -> u64 {
100 let rsp: u64;
101 unsafe {
102 core::arch::asm!("mov {}, rsp", out(reg) rsp, options(nomem, nostack, preserves_flags));
103 }
104 rsp
105}
106
107fn addr_readable(addr: u64) -> bool {
109 crate::memory::paging::translate(VirtAddr::new(addr)).is_some()
110}
111
112fn panic_hook_backtrace(_info: &PanicInfo) {
114 let mut rbp = read_rbp();
115 let rsp = read_rsp();
116 crate::serial_println!("panic-hook: stack rsp=0x{:x} rbp=0x{:x}", rsp, rbp);
117 crate::serial_println!("panic-hook: backtrace (frame-pointer)");
118
119 for i in 0..16 {
121 if rbp == 0 || (rbp & 0x7) != 0 {
122 crate::serial_println!(" #{:02}: stop (invalid rbp=0x{:x})", i, rbp);
123 break;
124 }
125 if !addr_readable(rbp) || !addr_readable(rbp.saturating_add(8)) {
126 crate::serial_println!(" #{:02}: stop (unmapped rbp=0x{:x})", i, rbp);
127 break;
128 }
129
130 let prev = unsafe { *(rbp as *const u64) };
131 let ret = unsafe { *((rbp + 8) as *const u64) };
132 crate::serial_println!(" #{:02}: rip=0x{:x} rbp=0x{:x}", i, ret, rbp);
133
134 if prev <= rbp || prev.saturating_sub(rbp) > 1024 * 1024 {
136 break;
137 }
138 rbp = prev;
139 }
140}
141
142pub fn install_default_panic_hooks() {
144 let _ = register_panic_hook(panic_hook_dump_context);
145 let _ = register_panic_hook(panic_hook_backtrace);
146}
147
148pub fn panic_handler(info: &PanicInfo) -> ! {
150 crate::arch::x86_64::serial::enter_emergency_mode();
153
154 if PANIC_IN_PROGRESS.swap(true, Ordering::SeqCst) {
156 loop {
157 crate::arch::x86_64::hlt();
158 }
159 }
160
161 crate::arch::x86_64::cli();
163
164 crate::serial_println!("\n\x1b[31;1m!!! KERNEL PANIC !!!\x1b[0m");
167 crate::serial_println!("=== GURU MEDIATiON :: KERNEL PANiK ===");
168 if let Some(location) = info.location() {
169 crate::serial_println!(
170 "not kalm :: panik at {}:{}:{}",
171 location.file(),
172 location.line(),
173 location.column()
174 );
175 }
176 crate::serial_println!("Message: {}", info.message());
177 crate::serial_println!("====================");
178
179 crate::arch::x86_64::smp::broadcast_panic_halt();
181
182 run_panic_hooks(info);
184
185 if crate::arch::x86_64::vga::is_available() {
187 if let Some(mut writer) = crate::arch::x86_64::vga::VGA_WRITER.try_lock() {
188 use core::fmt::Write;
189 writer.set_rgb_color(
190 crate::arch::x86_64::vga::RgbColor::new(0xFF, 0xE7, 0xA0),
191 crate::arch::x86_64::vga::RgbColor::new(0x3A, 0x1F, 0x00),
192 );
193 writer.clear();
194 let _ = writeln!(writer, "=== GURU MEDIATiON :: KERNEL PANiK ===");
195 if let Some(location) = info.location() {
196 let _ = writeln!(
197 writer,
198 "not kalm :: panik at {}:{}:{}",
199 location.file(),
200 location.line(),
201 location.column()
202 );
203 }
204 let _ = writeln!(writer, "Message: {}", info.message());
205 }
206 }
207
208 loop {
210 crate::arch::x86_64::hlt();
211 }
212}