added panic handling
This commit is contained in:
parent
31a0fd5202
commit
7cb116229f
3 changed files with 208 additions and 1 deletions
203
src/debug.zig
203
src/debug.zig
|
|
@ -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", .{});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue