Xenon/src/panic.zig

158 lines
5.2 KiB
Zig

const builtin = @import("builtin");
const std = @import("std");
const apic = @import("apic.zig");
const cpio = @import("formats/cpio.zig");
const cpu = @import("cpu.zig");
const global = @import("global.zig");
const log = @import("logger.zig").log;
var panicking: bool = false;
var panic_allocator: ?std.heap.FixedBufferAllocator = null;
var panic_memory: []u8 = undefined;
pub fn initialize() void {
panic_memory = global.kernel_memory.?.alloc(.{ .writeable = true }, 32 * 1024 * 1024, 4096) catch |err| {
log(.Warning, "Failed to allocate panic memory, extended debug features are unavailable: {}", .{err});
return;
};
panic_allocator = std.heap.FixedBufferAllocator.init(panic_memory);
}
pub fn panic(reason: []const u8, _: ?*builtin.StackTrace) noreturn {
@setCold(true);
if (!panicking) {
panicking = true;
displayErrorScreen();
log(.Error, "KERNEL PANIC: {}", .{reason});
// TODO This is only here because AP's don't do anything atm
if (apic.bootstrapCpuCore() and global.bp_stack != null) {
var stack_iter = if (builtin.mode == .Debug)
StackTrace.init(@frameAddress(), @ptrToInt(&global.bp_stack.?[0]) + global.bp_stack.?.len)
else blk: {
log(.Warning, "Using a release build, stack trace information might be incorrect", .{});
break :blk struct {
// A fake iterator to get a one entry stack trace in optimised builds
value: ?usize = null,
pub fn next(self: *@This()) ?usize {
const ret = self.value;
self.value = null;
return ret;
}
}{ .value = @returnAddress() };
};
var debug_info: ?*std.debug.DebugInfo = null;
if (panic_allocator) |*alloc| {
if (std.debug.openSelfDebugInfo(&alloc.allocator)) |*di| {
debug_info = di;
} else |err| {
log(.Warning, "[panic] Reading debug info failed: {}", .{err});
}
}
log(.Error, "Stack trace:", .{});
while (stack_iter.next()) |address| {
if (debug_info) |di| {
di.printSourceAtAddress(global.log_stream, address, .no_color, printSourceLine) catch |_| {};
} else {
log(.Error, "0x{0x:0>16}", .{address});
}
}
}
} else {
log(.Error, "KERNEL PANIC PANIC, oof: {}", .{reason});
}
while (true) {
cpu.hlt();
}
}
fn displayErrorScreen() void {
const ppm = @import("formats/ppm.zig");
if (global.framebuffer) |*fb| {
const initrd = cpio.Cpio.init(global.initrd orelse return);
if (initrd.findFile("debug/panic.ppm")) |file_err| {
const file = file_err catch return;
var picture = ppm.Ppm.init(file.data() catch return) catch return;
var x = fb.width -% @intCast(u32, picture.width);
if (x > fb.width) // We wrapped around
x = 0;
var y = fb.height -% @intCast(u32, picture.height);
if (y > fb.height)
y = 0;
fb.image(x, y, &picture);
}
}
}
fn printSourceLine(out_stream: var, line_info: std.debug.LineInfo) PrintError!void {
return PrintError.FileNotFound;
}
const PrintError = error{
BadPathName,
FileNotFound,
EndOfFile,
};
const StackTrace = struct {
const Self = @This();
frame_pointer: usize,
stack_start: usize,
pub fn init(frame_pointer: usize, stack_start: usize) Self {
return .{
.frame_pointer = frame_pointer,
.stack_start = stack_start,
};
}
pub fn next(self: *Self) ?usize {
if (self.frame_pointer > self.stack_start - 2 * @sizeOf(usize)) {
return null;
}
const return_address = @intToPtr(*usize, self.frame_pointer + @sizeOf(usize)).*;
self.frame_pointer = @intToPtr(*usize, self.frame_pointer).*;
return return_address;
}
};
pub const os = struct {
pub const debug = struct {
pub fn openSelfDebugInfo(allocator: *std.mem.Allocator) !std.debug.DebugInfo {
var initrd = cpio.Cpio.init(global.initrd orelse return error.InitrdNotFound);
if (initrd.findFile("sys/core")) |err_file| {
const file = err_file catch return error.CouldNotReadKernel;
const kernel_file = file.data() catch return error.CouldNotReadKernel;
// Does not need to be free'd because the system is failing or
// the debug data is reused on the next failure
const kernel_copy = try allocator.alloc(u8, kernel_file.len);
std.mem.copy(u8, kernel_copy, kernel_file);
var dwarfinfo = try std.debug.openElfDebugInfo(
allocator,
kernel_copy,
);
try std.debug.openDwarfDebugInfo(&dwarfinfo, allocator);
return dwarfinfo;
}
return error.KernelNotFound;
}
};
};