Files
Zag/src/kern/panic.zig
T
2026-09-27 21:32:00 -04:00

123 lines
3.1 KiB
Zig

const std = @import("std");
const config = @import("config");
const r = @import("root");
const ksyms = @import("ksyms");
const ke = r.ke;
const kep = ke.private;
const bv = r.bv;
extern var text_start_addr: u8;
extern var text_end_addr: u8;
const StackFrame = struct {
prev: ?*StackFrame,
return_addr: usize,
};
const Symbol = struct {
name: []const u8,
offset: usize,
};
fn get_symbol_name(addr: usize) ?Symbol {
const symbols = ksyms.get_symbols();
// Do a binary search on the ksyms array.
// The address may not be exact, so we look for the closest
// symbol that is less than or equal to the address.
var left: usize = 0;
var right: usize = symbols.len;
while (left < right) {
const mid = left + (right - left) / 2;
const sym = symbols[mid];
if (sym.addr == addr) {
return .{ .name = sym.name_ptr[0..sym.name_len], .offset = 0 };
} else if (sym.addr < addr) {
left = mid + 1;
} else {
right = mid;
}
}
if (left > 0) {
const sym = symbols[left - 1];
if (sym.addr <= addr) {
return .{ .name = sym.name_ptr[0..sym.name_len], .offset = addr - sym.addr };
}
}
return null;
}
fn is_kernel_text(addr: usize) bool {
const s = @intFromPtr(&text_start_addr);
const e = @intFromPtr(&text_end_addr);
return addr >= s and addr < e;
}
fn walk_stack_frame(base: usize) void {
var frame: ?*StackFrame = @ptrFromInt(if (config.arch == .riscv64) base - 16 else base);
var depth: usize = 0;
while (frame) |f| : (depth += 1) {
if (depth > 64) break;
const ret_addr = f.return_addr;
if (!is_kernel_text(ret_addr)) {
break;
}
const sym = get_symbol_name(ret_addr) orelse Symbol{ .name = "???", .offset = 0 };
std.log.err(" #{d} {s}+0x{x} - 0x{x}", .{ depth, sym.name, sym.offset, ret_addr });
frame = if (config.arch == .riscv64 and f.prev != null)
@ptrFromInt(@intFromPtr(f.prev.?) - 16)
else
f.prev;
}
}
pub var panic_lock: ke.SpinLock = .init();
var crash_count: std.atomic.Value(u8) = .init(0);
pub fn panic_with_frame(
msg: []const u8,
frame: usize,
) noreturn {
_ = kep.impl.disable_interrupts();
bv.crash();
if (crash_count.fetchAdd(1, .monotonic) != 0) {
std.log.err("Recursive panic from CPU {}", .{ke.cpu.current()});
// Another CPU has already crashed, just freeze manually right now.
while (true) {
kep.impl.halt();
}
}
// We're the first one who actually crashed, that means we get to handle
// things like dumping the system info and freezing other CPUs. Start by
// doing the freeze.
kep.ipi.freeze_cpus();
_ = ke.ipl.raise(.High);
std.log.err("KERNEL PANIC: {s} on CPU {}", .{
msg,
ke.cpu.current(),
});
std.log.err("Stack trace:", .{});
walk_stack_frame(frame);
while (true) {
kep.impl.halt();
}
}
pub fn panic(
msg: []const u8,
_: ?usize,
) noreturn {
panic_with_frame(msg, @frameAddress());
}