yggdrasil/kernel/src/panic.rs

103 lines
2.8 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, LocalCpu},
debug::{self, PanicLoggerSink},
device::display::console::flush_consoles,
};
use libk_util::sync::SpinFence;
use crate::arch::{Platform, PLATFORM};
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::error!(target: "raw", "X");
flush_consoles();
PANIC_SEQUENCE.fetch_add(1, Ordering::Release);
loop {
ArchitectureImpl::wait_for_interrupt();
}
}
fn dump_panic_info(cpu: &LocalCpu, pi: &core::panic::PanicInfo) {
let sink = PanicLoggerSink::lock();
debug::panic_log!(sink, "--- BEGIN PANIC ---\n");
debug::panic_log!(sink, "In CPU {}\n", cpu.id());
debug::panic_log!(sink, "Kernel panic");
if let Some(location) = pi.location() {
debug::panic_log!(sink, " at {}:{}:\n", location.file(), location.line());
} else {
debug::panic_log!(sink, ":\n");
}
debug::panic_log!(sink, "\n{}\n", pi.message());
debug::panic_log!(sink, "--- END PANIC ---\n");
}
pub(crate) fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
let cpu = Cpu::local();
static PANIC_HAPPENED: AtomicBool = AtomicBool::new(false);
if PANIC_HAPPENED
.compare_exchange(false, true, Ordering::Release, Ordering::Acquire)
.is_ok()
{
// TODO IPI leads to triple fault sometimes in x86-64
// // Let other CPUs know we're screwed
// if unsafe {
// PLATFORM
// .send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Panic)
// .unwrap_or(false)
// } {
// let ap_count = ArchitectureImpl::cpu_count() - 1;
// PANIC_HANDLED_FENCE.wait_all(ap_count);
// }
// unsafe { hack_locks() };
dump_panic_info(&cpu, pi);
PANIC_FINISHED_FENCE.signal();
while PANIC_SEQUENCE.load(Ordering::Acquire) != cpu.id() {
core::hint::spin_loop();
}
log::error!(target: "raw", "X");
flush_consoles();
PANIC_SEQUENCE.fetch_add(1, Ordering::Release);
unsafe {
PLATFORM.reset();
}
}
loop {
ArchitectureImpl::wait_for_interrupt();
}
}