109 lines
2.9 KiB
Rust
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();
|
|
}
|
|
}
|