yggdrasil/kernel/src/panic.rs

109 lines
2.9 KiB
Rust

//! Kernel panic handler code
use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use device_api::interrupt::{IpiDeliveryTarget, IpiMessage};
use kernel_arch::{Architecture, ArchitectureImpl};
use libk::arch::Cpu;
use libk_util::sync::{hack_locks, SpinFence};
use crate::{
arch::{Platform, PLATFORM},
debug::LogLevel,
device::display::console::flush_consoles,
};
static PANIC_HANDLED_FENCE: SpinFence = SpinFence::new();
// Just a simple sequencer to ensure secondary panics don't trash the screen
static PANIC_FINISHED_FENCE: SpinFence = SpinFence::new();
static PANIC_SEQUENCE: AtomicU32 = AtomicU32::new(0);
/// Panic handler for CPUs other than the one that initiated it
pub fn panic_secondary() -> ! {
// Will also mask IRQs in this section
let cpu = Cpu::local();
PANIC_HANDLED_FENCE.signal();
PANIC_FINISHED_FENCE.wait_one();
while PANIC_SEQUENCE.load(Ordering::Acquire) != cpu.id() {
core::hint::spin_loop();
}
log_print_raw!(LogLevel::Fatal, "X");
flush_consoles();
PANIC_SEQUENCE.fetch_add(1, Ordering::Release);
loop {
ArchitectureImpl::wait_for_interrupt();
}
}
pub(crate) fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
let cpu = Cpu::local();
static PANIC_HAPPENED: AtomicBool = AtomicBool::new(false);
fatalln!("panic_handler({:?})", pi);
if PANIC_HAPPENED
.compare_exchange(false, true, Ordering::Release, Ordering::Acquire)
.is_ok()
{
// Let other CPUs know we're screwed
unsafe {
PLATFORM
.send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Panic)
.ok();
}
let ap_count = ArchitectureImpl::cpu_count() - 1;
PANIC_HANDLED_FENCE.wait_all(ap_count);
unsafe {
hack_locks();
}
log_print_raw!(LogLevel::Fatal, "--- BEGIN PANIC ---\n");
log_print_raw!(LogLevel::Fatal, "In CPU {}\n", cpu.id());
log_print_raw!(LogLevel::Fatal, "Kernel panic ");
if let Some(location) = pi.location() {
log_print_raw!(
LogLevel::Fatal,
"at {}:{}:",
location.file(),
location.line()
);
} else {
log_print_raw!(LogLevel::Fatal, ":");
}
log_print_raw!(LogLevel::Fatal, "\n");
log_print_raw!(LogLevel::Fatal, "{}\n", pi.message());
log_print_raw!(LogLevel::Fatal, "--- END PANIC ---\n");
PANIC_FINISHED_FENCE.signal();
while PANIC_SEQUENCE.load(Ordering::Acquire) != cpu.id() {
core::hint::spin_loop();
}
log_print_raw!(LogLevel::Fatal, "X");
flush_consoles();
PANIC_SEQUENCE.fetch_add(1, Ordering::Release);
unsafe {
PLATFORM.reset();
}
}
loop {
ArchitectureImpl::wait_for_interrupt();
}
}