Skip to main content

kernel/
panic.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Kernel panic paths: [`kernel_panic`] for explicit kernel panics and the
3//! required `#[panic_handler]` for language-level panics.
4//!
5//! Authors: MarioS271
6
7use core::panic::PanicInfo;
8use core::sync::atomic::{AtomicBool, Ordering};
9use crate::types::panic_codes::PanicCode;
10use crate::arch::instructions;
11use crate::SIMPLE_STATE;
12use crate::types::fmt_buffer::FmtBuffer;
13
14/// Prevents infinite panic re-entry on the `kernel_panic` path.
15static KERNEL_PANIC_TRIGERRED: AtomicBool = AtomicBool::new(false);
16
17/// Prevents infinite panic re-entry on the `#[panic_handler]` path.
18static RUST_PANIC_TRIGERRED: AtomicBool = AtomicBool::new(false);
19
20/// Halt the kernel with a diagnostic message; re-entrant calls skip straight to the halt loop.
21pub fn kernel_panic(panic_code: PanicCode, panic_message: &str) -> ! {
22    instructions::disable_interrupts();
23
24    // Worst case, serial + basic fb output gets interrupted/cut off, which isn't a big deal
25    // considering the kernel has panicked
26    unsafe { crate::logging::kprint::force_unlock_kprint_state(); }
27
28    if KERNEL_PANIC_TRIGERRED.load(Ordering::Acquire) {
29        loop {
30            instructions::halt_cpu();
31        }
32    }
33    KERNEL_PANIC_TRIGERRED.store(true, Ordering::Release);
34
35    if SIMPLE_STATE.serial.is_completed() {
36        use crate::logging::_serial::_Serial;
37        let serial = SIMPLE_STATE.serial.get().unwrap();
38
39        serial.write("Kernel Panic! :(\n");
40        serial.write(panic_code.as_str());
41        serial.write("\n");
42        serial.write(panic_message);
43    }
44
45    if SIMPLE_STATE.basic_fb.is_completed() && SIMPLE_STATE.basic_fb_psf2_font.is_completed() {
46        let fb = SIMPLE_STATE.basic_fb.get().unwrap();
47        let font = SIMPLE_STATE.basic_fb_psf2_font.get().unwrap();
48        let mut x: usize = 0;
49        let mut y: usize = 0;
50
51        fb.clear();
52        font.draw_string(fb, "Kernel Panic! :(\n", &mut x, &mut y, Some(0x00FF0000));
53        font.draw_string(fb, panic_code.as_str(), &mut x, &mut y, None);
54        font.draw_string(fb, "\n", &mut x, &mut y, None);
55        font.draw_string(fb, panic_message, &mut x, &mut y, None);
56    }
57
58    loop {
59        instructions::halt_cpu();
60    }
61}
62
63/// Rust's required `#[panic_handler]` for language-level panics.
64#[panic_handler]
65fn panic(panic_info: &PanicInfo) -> ! {
66    use core::fmt::Write;
67
68    instructions::disable_interrupts();
69
70    // Worst case, serial + basic fb output gets interrupted/cut off, which isn't a big deal
71    // considering the kernel has panicked
72    unsafe { crate::logging::kprint::force_unlock_kprint_state(); }
73
74    if RUST_PANIC_TRIGERRED.load(Ordering::Acquire) {
75        loop {
76            instructions::halt_cpu();
77        }
78    }
79    RUST_PANIC_TRIGERRED.store(true, Ordering::Release);
80
81    let mut message_buf: FmtBuffer<128> = FmtBuffer::new();
82    if panic_info.message().as_str().is_none() {
83        let _ = write!(message_buf, "(No panic message given)\n\n");
84    } else {
85        let _ = write!(message_buf, "Panic Message: {}\n\n", panic_info.message());
86    }
87
88    let mut location_buf: FmtBuffer<256> = FmtBuffer::new();
89    if panic_info.location().is_none() {
90        let _ = write!(location_buf, "(No panic location given)");
91    } else {
92        let location = panic_info.location().unwrap();
93        let _ = write!(location_buf, "{}\n  on line {}", location.file(), location.line());
94    }
95
96    if SIMPLE_STATE.serial.is_completed() {
97        use crate::logging::_serial::_Serial;
98        let serial = SIMPLE_STATE.serial.get().unwrap();
99
100        serial.write("\nKernel Panic! :(\n");
101        serial.write("[!] This panic was triggered by Rust (language-triggered or via a panic!() call)\n\n");
102        serial.write(message_buf.as_str());
103        serial.write(location_buf.as_str());
104    }
105
106    if SIMPLE_STATE.basic_fb.is_completed() && SIMPLE_STATE.basic_fb_psf2_font.is_completed() {
107        let fb = SIMPLE_STATE.basic_fb.get().unwrap();
108        let font = SIMPLE_STATE.basic_fb_psf2_font.get().unwrap();
109        let mut x: usize = 0;
110        let mut y: usize = 0;
111
112        fb.clear();
113        font.draw_string(fb, "Kernel Panic! :(\n", &mut x, &mut y, Some(0x00FF0000));
114        font.draw_string(fb, "[!] This panic was triggered by Rust (runtime error or panic!() called)\n\n", &mut x, &mut y, None);
115        font.draw_string(fb, message_buf.as_str(), &mut x, &mut y, None);
116        font.draw_string(fb, location_buf.as_str(), &mut x, &mut y, None);
117    }
118
119    loop {
120        instructions::halt_cpu();
121    }
122}