added panic handling

This commit is contained in:
Lorenzo Torres 2026-02-02 14:54:03 +01:00
parent 31a0fd5202
commit 7cb116229f
3 changed files with 208 additions and 1 deletions

View file

@ -1,3 +1,4 @@
const std = @import("std");
const Console = @import("drivers/Console.zig"); const Console = @import("drivers/Console.zig");
var console: Console = undefined; var console: Console = undefined;
@ -9,3 +10,205 @@ pub fn init(c: Console) void {
pub fn print(comptime s: []const u8, args: anytype) void { pub fn print(comptime s: []const u8, args: anytype) void {
console.print(s, args); console.print(s, args);
} }
pub fn captureStackTrace(buffer: []usize) usize {
var count: usize = 0;
var current_fp = @frameAddress();
while (count < buffer.len) {
const ra_ptr: *const usize = @ptrFromInt(current_fp - 8);
const prev_fp_ptr: *const usize = @ptrFromInt(current_fp - 16);
const ra = ra_ptr.*;
const prev_fp = prev_fp_ptr.*;
if (ra == 0 or prev_fp == 0) break;
buffer[count] = ra;
count += 1;
if (prev_fp <= current_fp) break;
current_fp = prev_fp;
}
return count;
}
fn dumpRegisters() void {
const sstatus = asm volatile ("csrr %[ret], sstatus" : [ret] "=r" (-> usize));
const scause = asm volatile ("csrr %[ret], scause" : [ret] "=r" (-> usize));
const sepc = asm volatile ("csrr %[ret], sepc" : [ret] "=r" (-> usize));
const stval = asm volatile ("csrr %[ret], stval" : [ret] "=r" (-> usize));
const satp = asm volatile ("csrr %[ret], satp" : [ret] "=r" (-> usize));
const sp = asm volatile ("mv %[ret], sp" : [ret] "=r" (-> usize));
const fp = asm volatile ("mv %[ret], s0" : [ret] "=r" (-> usize));
const ra = asm volatile ("mv %[ret], ra" : [ret] "=r" (-> usize));
const gp = asm volatile ("mv %[ret], gp" : [ret] "=r" (-> usize));
const tp = asm volatile ("mv %[ret], tp" : [ret] "=r" (-> usize));
print("\n\x1B[33m=== REGISTER DUMP ===\x1B[m\n", .{});
print(" PC(ra): 0x{x:0>16} SP: 0x{x:0>16} FP: 0x{x:0>16}\n", .{ ra, sp, fp });
print(" GP: 0x{x:0>16} TP: 0x{x:0>16}\n", .{ gp, tp });
const mode = satp >> 60;
const ppn = satp & 0xFFFFFFFFFFF;
const mode_str = switch (mode) {
8 => "Sv39",
9 => "Sv48",
10 => "Sv57",
11 => "Sv64",
0 => "Bare",
else => "???",
};
print(" SATP: 0x{x:0>16} (Mode: {s}, PPN: 0x{x})\n", .{ satp, mode_str, ppn });
print("\n\x1B[33m=== TRAP INFO ===\x1B[m\n", .{});
print(" SSTATUS: 0x{x:0>16} SCAUSE: 0x{x:0>16}\n", .{ sstatus, scause });
print(" SEPC: 0x{x:0>16} STVAL: 0x{x:0>16}\n", .{ sepc, stval });
const is_interrupt = (scause >> 63) == 1;
const code = scause & 0x7FFFFFFFFFFFFFFF;
if (is_interrupt) {
print(" Cause: Interrupt (Code {d})\n", .{code});
} else {
print(" Cause: Exception (Code {d})\n", .{code});
}
}
fn printPanic(comptime fmt: []const u8, args: anytype) noreturn {
asm volatile ("csrci sstatus, 2");
print("\n\x1B[41;37m!!! KERNEL PANIC !!!\x1B[m\n", .{});
print("\x1B[31mReason: \x1B[m", .{});
print(fmt, args);
print("\n", .{});
dumpRegisters();
var address_buffer: [32]usize = undefined;
const count = captureStackTrace(&address_buffer);
print("\n\x1B[33m=== STACK TRACE ===\x1B[m\n", .{});
for (address_buffer[0..count]) |addr| {
print("0x{x} ", .{addr});
}
print("\x1B[m\n", .{});
for (address_buffer[0..count], 0..) |addr, i| {
print(" [{d: >2}] 0x{x:0>16}\n", .{ i, addr });
}
while (true) {
asm volatile ("wfi");
}
}
pub const KernelPanic = struct {
pub fn call(message: []const u8, addr: ?usize) noreturn {
_ = addr;
printPanic("{s}", .{message});
}
pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
@branchHint(.cold);
printPanic("Sentinel mismatch, expected {any}, found {any}", .{ expected, found });
}
pub fn unwrapError(err: anyerror) noreturn {
@branchHint(.cold);
printPanic("attempt to unwrap error: {s}", .{@errorName(err)});
}
pub fn outOfBounds(index: usize, len: usize) noreturn {
@branchHint(.cold);
printPanic("index out of bounds: index {d}, len {d}", .{ index, len });
}
pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
@branchHint(.cold);
printPanic("start index {d} is larger than end index {d}", .{ start, end });
}
pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
@branchHint(.cold);
printPanic("access of union field '{s}' while field '{s}' is active", .{
@tagName(accessed), @tagName(active),
});
}
pub fn sliceCastLenRemainder(src_len: usize) noreturn {
@branchHint(.cold);
printPanic("slice length '{d}' does not divide exactly into destination elements", .{src_len});
}
pub fn reachedUnreachable() noreturn {
@branchHint(.cold);
printPanic("reached unreachable code", .{});
}
pub fn unwrapNull() noreturn {
@branchHint(.cold);
printPanic("attempt to use null value", .{});
}
pub fn castToNull() noreturn {
@branchHint(.cold);
printPanic("cast causes pointer to be null", .{});
}
pub fn incorrectAlignment() noreturn {
@branchHint(.cold);
printPanic("incorrect alignment", .{});
}
pub fn invalidErrorCode() noreturn {
@branchHint(.cold);
printPanic("invalid error code", .{});
}
pub fn integerOutOfBounds() noreturn {
@branchHint(.cold);
printPanic("integer does not fit in destination type", .{});
}
pub fn integerOverflow() noreturn {
@branchHint(.cold);
printPanic("integer overflow", .{});
}
pub fn shlOverflow() noreturn {
@branchHint(.cold);
printPanic("left shift overflowed bits", .{});
}
pub fn shrOverflow() noreturn {
@branchHint(.cold);
printPanic("right shift overflowed bits", .{});
}
pub fn divideByZero() noreturn {
printPanic("division by zero", .{});
}
pub fn exactDivisionRemainder() noreturn {
@branchHint(.cold);
printPanic("exact division produced remainder", .{});
}
pub fn integerPartOutOfBounds() noreturn {
@branchHint(.cold);
printPanic("integer part of floating point value out of bounds", .{});
}
pub fn corruptSwitch() noreturn {
@branchHint(.cold);
printPanic("switch on corrupt value", .{});
}
pub fn shiftRhsTooBig() noreturn {
@branchHint(.cold);
printPanic("shift amount is greater than the type size", .{});
}
pub fn invalidEnumValue() noreturn {
@branchHint(.cold);
printPanic("invalid enum value", .{});
}
pub fn forLenMismatch() noreturn {
@branchHint(.cold);
printPanic("for loop over objects with non-equal lengths", .{});
}
pub fn copyLenMismatch() noreturn {
@branchHint(.cold);
printPanic("source and destination arguments have non-equal lengths", .{});
}
pub fn memcpyAlias() noreturn {
@branchHint(.cold);
printPanic("@memcpy arguments alias", .{});
}
pub fn noreturnReturned() noreturn {
@branchHint(.cold);
printPanic("'noreturn' function returned", .{});
}
};

View file

@ -19,8 +19,12 @@ fn print(s: []const u8) void {
} }
} }
pub const panic = debug.KernelPanic;
export fn _start() linksection(".text.init") callconv(.naked) noreturn { export fn _start() linksection(".text.init") callconv(.naked) noreturn {
asm volatile ( asm volatile (
\\li fp, 0
\\li ra, 0
\\li sp, 0x88000000 \\li sp, 0x88000000
\\tail kmain \\tail kmain
); );

View file

@ -43,7 +43,7 @@ pub fn identityMap(self: *PageTable, allocator: Allocator, memory_end: u64) !voi
.user = 0, .user = 0,
}; };
var addr: u64 = 0x80000000; var addr: u64 = 0x0;
while (addr < memory_end) : (addr += 0x1000) { while (addr < memory_end) : (addr += 0x1000) {
try self.map(allocator, addr, addr, flags); try self.map(allocator, addr, addr, flags);
} }