diff options
| author | Bobby <[email protected]> | 2026-02-15 20:05:15 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-02-15 20:05:15 +0530 |
| commit | 90663e30db47e87f896245cc20ce0b0284fcdc5f (patch) | |
| tree | 738687ecaaf338d396faea98c724523273159035 | |
| parent | 84d9abdb8f4a92ca99c75e4dd8948c1196f6260f (diff) | |
| download | akiba-90663e30db47e87f896245cc20ce0b0284fcdc5f.tar.xz akiba-90663e30db47e87f896245cc20ce0b0284fcdc5f.zip | |
Refactor Crimson Panic Handler and Exception Management
- Renamed panic.zig to crimson.zig for clarity and restructured panic handling functions.
- Moved exception handling logic from exceptions.zig to a new exception.zig file.
- Updated imports across the codebase to reflect the new file structure.
- Introduced a new types.zig file to define Context and ExceptionFrame structures.
- Added formatting utilities in format.zig for better register and stack frame representation.
- Implemented screen rendering functions in render.zig for displaying error messages and system state during panic.
- Consolidated color definitions in colors.zig and added new constants for better readability.
- Removed obsolete exception handling code and integrated it into the new structure.
| -rw-r--r-- | mirai/boot/sequence/sequence.zig | 2 | ||||
| -rw-r--r-- | mirai/common/constants/colors.zig | 5 | ||||
| -rw-r--r-- | mirai/common/limits/crimson.zig | 6 | ||||
| -rw-r--r-- | mirai/crimson/crimson.zig | 15 | ||||
| -rw-r--r-- | mirai/crimson/exception.zig | 102 | ||||
| -rw-r--r-- | mirai/crimson/exceptions.zig | 188 | ||||
| -rw-r--r-- | mirai/crimson/format.zig | 132 | ||||
| -rw-r--r-- | mirai/crimson/panic.zig | 423 | ||||
| -rw-r--r-- | mirai/crimson/render.zig | 155 | ||||
| -rw-r--r-- | mirai/crimson/types.zig | 50 | ||||
| -rw-r--r-- | mirai/interrupts/idt.zig | 2 | ||||
| -rw-r--r-- | mirai/mirai.zig | 2 |
12 files changed, 488 insertions, 594 deletions
diff --git a/mirai/boot/sequence/sequence.zig b/mirai/boot/sequence/sequence.zig index 15f745b..c178698 100644 --- a/mirai/boot/sequence/sequence.zig +++ b/mirai/boot/sequence/sequence.zig @@ -5,7 +5,7 @@ const ahci = @import("../../drivers/ahci/ahci.zig"); const boot_limits = @import("../../common/limits/boot.zig"); const colors = @import("../../common/constants/colors.zig"); const cpu = @import("../../asm/cpu.zig"); -const crimson = @import("../../crimson/panic.zig"); +const crimson = @import("../../crimson/crimson.zig"); const font = @import("../../graphics/fonts/psf.zig"); const gdt = @import("../gdt/gdt.zig"); const gpt = @import("../../fs/gpt/gpt.zig"); diff --git a/mirai/common/constants/colors.zig b/mirai/common/constants/colors.zig index d7bf8b4..a959663 100644 --- a/mirai/common/constants/colors.zig +++ b/mirai/common/constants/colors.zig @@ -1,5 +1,7 @@ //! Display colors +pub const AKIBA_PINK: u32 = 0x00FF6B9D; + pub const WHITE: u32 = 0x00FFFFFF; pub const BLACK: u32 = 0x00000000; pub const RED: u32 = 0x00FF0000; @@ -9,5 +11,4 @@ pub const YELLOW: u32 = 0x00FFFF00; pub const CYAN: u32 = 0x0000FFFF; pub const MAGENTA: u32 = 0x00FF00FF; pub const GRAY: u32 = 0x00808080; - -pub const AKIBA_PINK: u32 = 0x00FF6B9D; +pub const CRIMSON: u32 = 0x00DC143C; diff --git a/mirai/common/limits/crimson.zig b/mirai/common/limits/crimson.zig new file mode 100644 index 0000000..9f80985 --- /dev/null +++ b/mirai/common/limits/crimson.zig @@ -0,0 +1,6 @@ +//! Crimson limits + +pub const MAX_STACK_FRAMES: usize = 16; +pub const REGISTER_BUFFER_SIZE: usize = 100; +pub const STACK_FRAME_BUFFER_SIZE: usize = 50; +pub const ASSERT_BUFFER_SIZE: usize = 256; diff --git a/mirai/crimson/crimson.zig b/mirai/crimson/crimson.zig new file mode 100644 index 0000000..37542aa --- /dev/null +++ b/mirai/crimson/crimson.zig @@ -0,0 +1,15 @@ +//! Crimson - Kernel panic handler + +pub const types = @import("types.zig"); +pub const panic = @import("panic.zig"); +pub const exception = @import("exception.zig"); +pub const render = @import("render.zig"); +pub const format = @import("format.zig"); + +pub const Context = types.Context; +pub const ExceptionFrame = types.ExceptionFrame; + +pub const init = panic.init; +pub const collapse = panic.collapse; +pub const assert_failed = panic.assert_failed; +pub const exception_handler = exception.exception_handler; diff --git a/mirai/crimson/exception.zig b/mirai/crimson/exception.zig new file mode 100644 index 0000000..6ba9b96 --- /dev/null +++ b/mirai/crimson/exception.zig @@ -0,0 +1,102 @@ +//! CPU exception handler + +const memory = @import("../asm/memory.zig"); +const panic = @import("panic.zig"); +const serial = @import("../drivers/serial/serial.zig"); +const types = @import("types.zig"); + +const NAMES = [_][]const u8{ + "Division By Zero", + "Debug", + "Non-Maskable Interrupt", + "Breakpoint", + "Overflow", + "Bound Range Exceeded", + "Invalid Opcode", + "Device Not Available", + "Double Fault", + "Coprocessor Segment Overrun", + "Invalid TSS", + "Segment Not Present", + "Stack-Segment Fault", + "General Protection Fault", + "Page Fault", + "Reserved", + "x87 Floating-Point Exception", + "Alignment Check", + "Machine Check", + "SIMD Floating-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Hypervisor Injection Exception", + "VMM Communication Exception", + "Security Exception", + "Reserved", +}; + +export fn exception_handler(frame_ptr: u64) void { + const frame = @as(*types.ExceptionFrame, @ptrFromInt(frame_ptr)); + + serial.print("\n!!! EXCEPTION: "); + if (frame.int_num < NAMES.len) { + serial.print(NAMES[frame.int_num]); + } else { + serial.print("Unknown"); + } + serial.print(" !!!\n"); + + serial.printf("Vector: {x}\n", .{frame.int_num}); + serial.printf("Error Code: {x}\n", .{frame.error_code}); + serial.printf("RIP: {x}\n", .{frame.rip}); + serial.printf("CS: {x}\n", .{frame.cs}); + serial.printf("RFLAGS: {x}\n", .{frame.rflags}); + serial.printf("RSP: {x}\n", .{frame.rsp}); + serial.printf("SS: {x}\n", .{frame.ss}); + + if (frame.int_num == 14) { + const cr2 = memory.read_page_fault_address(); + serial.printf("CR2 (fault addr): {x}\n", .{cr2}); + + serial.print("Fault type: "); + if ((frame.error_code & 1) == 0) { + serial.print("Page not present"); + } else { + serial.print("Protection violation"); + } + if ((frame.error_code & 2) != 0) { + serial.print(", Write"); + } else { + serial.print(", Read"); + } + if ((frame.error_code & 4) != 0) { + serial.print(", User mode"); + } else { + serial.print(", Kernel mode"); + } + serial.print("\n"); + + serial.printf("CR3 (page table): {x}\n", .{memory.read_page_table_base()}); + } + + serial.print("\nRegisters:\n"); + serial.printf("RAX: {x} RBX: {x}\n", .{ frame.rax, frame.rbx }); + serial.printf("RCX: {x} RDX: {x}\n", .{ frame.rcx, frame.rdx }); + serial.printf("RSI: {x} RDI: {x}\n", .{ frame.rsi, frame.rdi }); + serial.printf("RBP: {x}\n", .{frame.rbp}); + serial.printf("R8: {x} R9: {x}\n", .{ frame.r8, frame.r9 }); + serial.printf("R10: {x} R11: {x}\n", .{ frame.r10, frame.r11 }); + serial.printf("R12: {x} R13: {x}\n", .{ frame.r12, frame.r13 }); + serial.printf("R14: {x} R15: {x}\n", .{ frame.r14, frame.r15 }); + + if (frame.int_num < NAMES.len) { + panic.collapse(NAMES[frame.int_num], null); + } else { + panic.collapse("Unknown Exception", null); + } +} diff --git a/mirai/crimson/exceptions.zig b/mirai/crimson/exceptions.zig deleted file mode 100644 index c1897e1..0000000 --- a/mirai/crimson/exceptions.zig +++ /dev/null @@ -1,188 +0,0 @@ -//! Exception Handler - Crimson panic for CPU exceptions - -const memory = @import("../asm/memory.zig"); -const panic = @import("panic.zig"); -const serial = @import("../drivers/serial/serial.zig"); - -// ISR stubs are defined in mirai/asm/isr.zig -// The comptime assembly block has been moved there - -const ExceptionFrame = packed struct { - r15: u64, - r14: u64, - r13: u64, - r12: u64, - r11: u64, - r10: u64, - r9: u64, - r8: u64, - rbp: u64, - rdi: u64, - rsi: u64, - rdx: u64, - rcx: u64, - rbx: u64, - rax: u64, - int_num: u64, - error_code: u64, - rip: u64, - cs: u64, - rflags: u64, - rsp: u64, - ss: u64, -}; - -const EXCEPTION_NAMES = [_][]const u8{ - "Division By Zero", - "Debug", - "Non-Maskable Interrupt", - "Breakpoint", - "Overflow", - "Bound Range Exceeded", - "Invalid Opcode", - "Device Not Available", - "Double Fault", - "Coprocessor Segment Overrun", - "Invalid TSS", - "Segment Not Present", - "Stack-Segment Fault", - "General Protection Fault", - "Page Fault", - "Reserved", - "x87 Floating-Point Exception", - "Alignment Check", - "Machine Check", - "SIMD Floating-Point Exception", - "Virtualization Exception", - "Control Protection Exception", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Hypervisor Injection Exception", - "VMM Communication Exception", - "Security Exception", - "Reserved", -}; - -export fn exception_handler(frame_ptr: u64) void { - const frame = @as(*ExceptionFrame, @ptrFromInt(frame_ptr)); - - serial.print("\n!!! EXCEPTION: "); - if (frame.int_num < EXCEPTION_NAMES.len) { - serial.print(EXCEPTION_NAMES[frame.int_num]); - } else { - serial.print("Unknown"); - } - serial.print(" !!!\n"); - - serial.print("Vector: "); - serial.print_hex(frame.int_num); - serial.print("\n"); - - serial.print("Error Code: "); - serial.print_hex(frame.error_code); - serial.print("\n"); - - serial.print("RIP: "); - serial.print_hex(frame.rip); - serial.print("\n"); - - serial.print("CS: "); - serial.print_hex(frame.cs); - serial.print("\n"); - - serial.print("RFLAGS: "); - serial.print_hex(frame.rflags); - serial.print("\n"); - - serial.print("RSP: "); - serial.print_hex(frame.rsp); - serial.print("\n"); - - serial.print("SS: "); - serial.print_hex(frame.ss); - serial.print("\n"); - - // Page fault specific info - if (frame.int_num == 14) { - const cr2 = memory.read_page_fault_address(); - serial.print("CR2 (fault addr): "); - serial.print_hex(cr2); - serial.print("\n"); - - serial.print("Fault type: "); - if ((frame.error_code & 1) == 0) { - serial.print("Page not present"); - } else { - serial.print("Protection violation"); - } - if ((frame.error_code & 2) != 0) { - serial.print(", Write"); - } else { - serial.print(", Read"); - } - if ((frame.error_code & 4) != 0) { - serial.print(", User mode"); - } else { - serial.print(", Kernel mode"); - } - serial.print("\n"); - - const cr3 = memory.read_page_table_base(); - serial.print("CR3 (page table): "); - serial.print_hex(cr3); - serial.print("\n"); - } - - serial.print("\nRegisters:\n"); - serial.print("RAX: "); - serial.print_hex(frame.rax); - serial.print(" RBX: "); - serial.print_hex(frame.rbx); - serial.print("\n"); - serial.print("RCX: "); - serial.print_hex(frame.rcx); - serial.print(" RDX: "); - serial.print_hex(frame.rdx); - serial.print("\n"); - serial.print("RSI: "); - serial.print_hex(frame.rsi); - serial.print(" RDI: "); - serial.print_hex(frame.rdi); - serial.print("\n"); - serial.print("RBP: "); - serial.print_hex(frame.rbp); - serial.print("\n"); - serial.print("R8: "); - serial.print_hex(frame.r8); - serial.print(" R9: "); - serial.print_hex(frame.r9); - serial.print("\n"); - serial.print("R10: "); - serial.print_hex(frame.r10); - serial.print(" R11: "); - serial.print_hex(frame.r11); - serial.print("\n"); - serial.print("R12: "); - serial.print_hex(frame.r12); - serial.print(" R13: "); - serial.print_hex(frame.r13); - serial.print("\n"); - serial.print("R14: "); - serial.print_hex(frame.r14); - serial.print(" R15: "); - serial.print_hex(frame.r15); - serial.print("\n"); - - // Trigger Crimson panic - // Note: We pass null for context since ExceptionFrame layout differs from panic.Context - // All register info has already been printed to serial above - if (frame.int_num < EXCEPTION_NAMES.len) { - panic.collapse(EXCEPTION_NAMES[frame.int_num], null); - } else { - panic.collapse("Unknown Exception", null); - } -} diff --git a/mirai/crimson/format.zig b/mirai/crimson/format.zig new file mode 100644 index 0000000..1681ded --- /dev/null +++ b/mirai/crimson/format.zig @@ -0,0 +1,132 @@ +//! Crimson formatting utilities + +pub fn u32_decimal(value: u32, buffer: []u8) usize { + if (buffer.len == 0) return 0; + + var temp: [10]u8 = undefined; + var temp_pos: usize = 0; + var val = value; + + if (val == 0) { + buffer[0] = '0'; + return 1; + } + + while (val > 0 and temp_pos < 10) { + temp[temp_pos] = @as(u8, @truncate(val % 10)) + '0'; + val /= 10; + temp_pos += 1; + } + + var pos: usize = 0; + while (temp_pos > 0 and pos < buffer.len) { + temp_pos -= 1; + buffer[pos] = temp[temp_pos]; + pos += 1; + } + + return pos; +} + +pub fn u64_hex(value: u64, buffer: []u8) usize { + const hex = "0123456789ABCDEF"; + var shift: u6 = 60; + var pos: usize = 0; + + while (pos < 16 and pos < buffer.len) : (pos += 1) { + const nibble = @as(u8, @truncate((value >> shift) & 0xF)); + buffer[pos] = hex[nibble]; + if (shift >= 4) { + shift -= 4; + } + } + + return pos; +} + +pub fn register(label: []const u8, value: u64, buffer: []u8) []const u8 { + var pos: usize = 0; + + for (label) |c| { + if (pos < buffer.len) { + buffer[pos] = c; + pos += 1; + } + } + + if (pos < buffer.len) { + buffer[pos] = ':'; + pos += 1; + } + if (pos < buffer.len) { + buffer[pos] = ' '; + pos += 1; + } + + pos += u64_hex(value, buffer[pos..]); + + return buffer[0..pos]; +} + +pub fn stack_frame(num: usize, addr: u64, buffer: []u8) []const u8 { + var pos: usize = 0; + + if (pos < buffer.len) { + buffer[pos] = '#'; + pos += 1; + } + + pos += u32_decimal(@truncate(num), buffer[pos..]); + + if (pos < buffer.len) { + buffer[pos] = ' '; + pos += 1; + } + + pos += u64_hex(addr, buffer[pos..]); + + return buffer[0..pos]; +} + +pub fn assert_message(condition: []const u8, file: []const u8, line: u32, buffer: []u8) []const u8 { + var pos: usize = 0; + + const prefix = "Assertion failed: "; + for (prefix) |c| { + if (pos < buffer.len) { + buffer[pos] = c; + pos += 1; + } + } + + for (condition) |c| { + if (pos < buffer.len) { + buffer[pos] = c; + pos += 1; + } + } + + const at_str = " at "; + for (at_str) |c| { + if (pos < buffer.len) { + buffer[pos] = c; + pos += 1; + } + } + + for (file) |c| { + if (pos < buffer.len) { + buffer[pos] = c; + pos += 1; + } + } + + if (pos < buffer.len) { + buffer[pos] = ':'; + pos += 1; + } + + pos += u32_decimal(line, buffer[pos..]); + + return buffer[0..pos]; +} diff --git a/mirai/crimson/panic.zig b/mirai/crimson/panic.zig index 235a85f..a0e52b1 100644 --- a/mirai/crimson/panic.zig +++ b/mirai/crimson/panic.zig @@ -1,55 +1,23 @@ -//! Crimson Panic Handler - "Hey! You finally met Crimson!" +//! Crimson panic handler -const boot = @import("../boot/multiboot/multiboot.zig"); const cpu = @import("../asm/cpu.zig"); -const font = @import("../graphics/fonts/psf.zig"); +const crimson_limits = @import("../common/limits/crimson.zig"); +const format = @import("format.zig"); +const multiboot = @import("../boot/multiboot/multiboot.zig"); +const render = @import("render.zig"); const serial = @import("../drivers/serial/serial.zig"); +const types = @import("types.zig"); -// Crimson color scheme -const CRIMSON_BG: u32 = 0x00DC143C; // Crimson red -const WHITE_FG: u32 = 0x00FFFFFF; // White text +var framebuffer: ?multiboot.FramebufferInfo = null; -var framebuffer: ?boot.FramebufferInfo = null; - -// Register context at time of collapse -pub const Context = struct { - rax: u64, - rbx: u64, - rcx: u64, - rdx: u64, - rsi: u64, - rdi: u64, - rbp: u64, - rsp: u64, - r8: u64, - r9: u64, - r10: u64, - r11: u64, - r12: u64, - r13: u64, - r14: u64, - r15: u64, - rip: u64, - rflags: u64, - error_code: u64, - cr2: u64, // Page fault address - cr3: u64, // Page table address -}; - -const MAX_STACK_FRAMES = 16; - -// Initialize panic handler with framebuffer -pub fn init(fb: boot.FramebufferInfo) void { +pub fn init(fb: multiboot.FramebufferInfo) void { framebuffer = fb; serial.print("Crimson panic handler initialized\n"); } -// Main collapse function - called on fatal errors -pub fn collapse(message: []const u8, context: ?*const Context) noreturn { - // Disable interrupts immediately +pub fn collapse(message: []const u8, context: ?*const types.Context) noreturn { cpu.disable_interrupts(); - // Log to serial first (in case framebuffer fails) serial.print("\n╔════════════════════════════════════╗\n"); serial.print("║ CRIMSON COLLAPSE ║\n"); serial.print("╚════════════════════════════════════╝\n"); @@ -57,382 +25,35 @@ pub fn collapse(message: []const u8, context: ?*const Context) noreturn { serial.print("\n"); if (context) |ctx| { - dump_registers_serial(ctx); + dump_registers(ctx); } - // Render to screen if framebuffer available if (framebuffer) |fb| { - render_crimson_screen(fb, message, context); + render.screen(fb, message, context); } halt(); } -// Assert macro helper pub fn assert_failed(condition: []const u8, file: []const u8, line: u32) noreturn { - var buffer: [256]u8 = undefined; - const msg = format_assert_message(condition, file, line, &buffer); + var buffer: [crimson_limits.ASSERT_BUFFER_SIZE]u8 = undefined; + const msg = format.assert_message(condition, file, line, &buffer); collapse(msg, null); } -fn format_assert_message(condition: []const u8, file: []const u8, line: u32, buffer: []u8) []const u8 { - var pos: usize = 0; - - // "Assertion failed: " - const prefix = "Assertion failed: "; - for (prefix) |c| { - if (pos < buffer.len) { - buffer[pos] = c; - pos += 1; - } - } - - // Condition - for (condition) |c| { - if (pos < buffer.len) { - buffer[pos] = c; - pos += 1; - } - } - - // " at " - const at_str = " at "; - for (at_str) |c| { - if (pos < buffer.len) { - buffer[pos] = c; - pos += 1; - } - } - - // File - for (file) |c| { - if (pos < buffer.len) { - buffer[pos] = c; - pos += 1; - } - } - - // ":" - if (pos < buffer.len) { - buffer[pos] = ':'; - pos += 1; - } - - // Line number - pos += format_u32(line, buffer[pos..]); - - return buffer[0..pos]; -} - -fn format_u32(value: u32, buffer: []u8) usize { - if (buffer.len == 0) return 0; - - var temp: [10]u8 = undefined; - var temp_pos: usize = 0; - var val = value; - - if (val == 0) { - buffer[0] = '0'; - return 1; - } - - while (val > 0 and temp_pos < 10) { - temp[temp_pos] = @as(u8, @truncate(val % 10)) + '0'; - val /= 10; - temp_pos += 1; - } - - var pos: usize = 0; - while (temp_pos > 0 and pos < buffer.len) { - temp_pos -= 1; - buffer[pos] = temp[temp_pos]; - pos += 1; - } - - return pos; -} - -fn render_crimson_screen(fb: boot.FramebufferInfo, message: []const u8, context: ?*const Context) void { - // Fill screen with crimson - fill_screen_crimson(fb); - - const char_height = font.get_height(); - var y: u32 = 60; - - // Heading - const heading = "Hey! You finally met Crimson!"; - render_centered_text(heading, y, fb, WHITE_FG); - y += char_height + 20; - - // Description - const desc1 = "Mirai Kernel has encountered an error and the system"; - const desc2 = "will need to be restarted. Please reboot your machine."; - render_centered_text(desc1, y, fb, WHITE_FG); - y += char_height + 4; - render_centered_text(desc2, y, fb, WHITE_FG); - y += char_height + 30; - - // Error message - render_centered_text("Error:", y, fb, WHITE_FG); - y += char_height + 4; - render_centered_text(message, y, fb, WHITE_FG); - y += char_height + 30; - - // Registers if context provided - if (context) |ctx| { - render_registers(ctx, y, fb); - y += (char_height + 4) * 10; // Space for registers - - // Stack trace - render_centered_text("Stack Trace:", y, fb, WHITE_FG); - y += char_height + 4; - render_stack_trace(ctx.rbp, ctx.rip, y, fb); - } -} - -fn fill_screen_crimson(fb: boot.FramebufferInfo) void { - if (fb.bpp == 32) { - const pixels = @as([*]volatile u32, @ptrFromInt(fb.addr)); - const total_pixels = fb.height * (fb.pitch / 4); - - var i: u32 = 0; - while (i < total_pixels) : (i += 1) { - pixels[i] = CRIMSON_BG; - } - } else if (fb.bpp == 24) { - const pixels = @as([*]volatile u8, @ptrFromInt(fb.addr)); - - const r: u8 = @truncate((CRIMSON_BG >> 16) & 0xFF); - const g: u8 = @truncate((CRIMSON_BG >> 8) & 0xFF); - const b: u8 = @truncate(CRIMSON_BG & 0xFF); - - var y: u32 = 0; - while (y < fb.height) : (y += 1) { - var x: u32 = 0; - while (x < fb.width) : (x += 1) { - const offset = y * fb.pitch + x * 3; - pixels[offset] = b; - pixels[offset + 1] = g; - pixels[offset + 2] = r; - } - } - } -} - -fn render_centered_text(text: []const u8, y: u32, fb: boot.FramebufferInfo, color: u32) void { - const char_width: u32 = font.get_width(); - const text_width: u32 = @intCast(text.len * char_width); - - if (text_width > fb.width) { - // Text too long, left-align with margin - font.render_text(text, 20, y, fb, color); - } else { - const x: u32 = (fb.width - text_width) / 2; - font.render_text(text, x, y, fb, color); - } -} - -fn render_registers(ctx: *const Context, start_y: u32, fb: boot.FramebufferInfo) void { - const char_height = font.get_height(); - var y = start_y; - - var buffer: [100]u8 = undefined; - - // Two-column layout for registers - render_register_pair("RAX", ctx.rax, "RBX", ctx.rbx, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("RCX", ctx.rcx, "RDX", ctx.rdx, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("RSI", ctx.rsi, "RDI", ctx.rdi, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("RBP", ctx.rbp, "RSP", ctx.rsp, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("R8 ", ctx.r8, "R9 ", ctx.r9, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("R10", ctx.r10, "R11", ctx.r11, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("R12", ctx.r12, "R13", ctx.r13, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("R14", ctx.r14, "R15", ctx.r15, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("RIP", ctx.rip, "CR2", ctx.cr2, y, &buffer, fb); - y += char_height + 4; - - render_register_pair("CR3", ctx.cr3, "ERR", ctx.error_code, y, &buffer, fb); -} - -fn render_register_pair(label1: []const u8, val1: u64, label2: []const u8, val2: u64, y: u32, buffer: []u8, fb: boot.FramebufferInfo) void { - // Left column - const left_x: u32 = 100; - const right_x: u32 = 500; - - const text1 = format_register(label1, val1, buffer[0..49]); - font.render_text(text1, left_x, y, fb, WHITE_FG); - - const text2 = format_register(label2, val2, buffer[50..99]); - font.render_text(text2, right_x, y, fb, WHITE_FG); -} - -fn format_register(label: []const u8, value: u64, buffer: []u8) []const u8 { - var pos: usize = 0; - - // Label - for (label) |c| { - if (pos < buffer.len) { - buffer[pos] = c; - pos += 1; - } - } - - // Separator - if (pos < buffer.len) { - buffer[pos] = ':'; - pos += 1; - } - if (pos < buffer.len) { - buffer[pos] = ' '; - pos += 1; - } - - // Hex value - const hex_chars = "0123456789ABCDEF"; - var shift: u6 = 60; - var i: usize = 0; - while (i < 16 and pos < buffer.len) : (i += 1) { - const nibble = @as(u8, @truncate((value >> shift) & 0xF)); - buffer[pos] = hex_chars[nibble]; - pos += 1; - if (shift >= 4) { - shift -= 4; - } - } - - return buffer[0..pos]; -} - -fn render_stack_trace(rbp: u64, rip: u64, start_y: u32, fb: boot.FramebufferInfo) void { - const char_height = font.get_height(); - var y = start_y; - var buffer: [50]u8 = undefined; - - // First frame is current RIP - const text0 = format_stack_frame(0, rip, &buffer); - render_centered_text(text0, y, fb, WHITE_FG); - y += char_height + 2; - - // Walk stack - var frame_rbp = rbp; - var frame_num: usize = 1; - - while (frame_num < MAX_STACK_FRAMES) : (frame_num += 1) { - // Check if RBP looks valid (in higher half) - if (frame_rbp < 0xFFFF800000000000 or frame_rbp == 0) break; - - // Read return address (RBP+8) - const ret_addr_ptr = @as(*const u64, @ptrFromInt(frame_rbp + 8)); - const ret_addr = ret_addr_ptr.*; - - // Check if return address looks valid - if (ret_addr < 0xFFFF800000000000) break; - - const text = format_stack_frame(frame_num, ret_addr, &buffer); - render_centered_text(text, y, fb, WHITE_FG); - y += char_height + 2; - - // Get next frame - const next_rbp_ptr = @as(*const u64, @ptrFromInt(frame_rbp)); - frame_rbp = next_rbp_ptr.*; - - // Prevent infinite loops - if (frame_rbp == 0 or frame_rbp == rbp) break; - } -} - -fn format_stack_frame(num: usize, addr: u64, buffer: []u8) []const u8 { - var pos: usize = 0; - - // Frame number - if (pos < buffer.len) { - buffer[pos] = '#'; - pos += 1; - } - pos += format_u32(@truncate(num), buffer[pos..]); - - // Separator - if (pos < buffer.len) { - buffer[pos] = ' '; - pos += 1; - } - - // Address - const hex_chars = "0123456789ABCDEF"; - var shift: u6 = 60; - var i: usize = 0; - while (i < 16 and pos < buffer.len) : (i += 1) { - const nibble = @as(u8, @truncate((addr >> shift) & 0xF)); - buffer[pos] = hex_chars[nibble]; - pos += 1; - if (shift >= 4) { - shift -= 4; - } - } - - return buffer[0..pos]; -} - -fn dump_registers_serial(ctx: *const Context) void { +fn dump_registers(ctx: *const types.Context) void { serial.print("\nRegister Dump:\n"); - serial.print("RAX: "); - serial.print_hex(ctx.rax); - serial.print(" RBX: "); - serial.print_hex(ctx.rbx); - serial.print("\n"); - - serial.print("RCX: "); - serial.print_hex(ctx.rcx); - serial.print(" RDX: "); - serial.print_hex(ctx.rdx); - serial.print("\n"); - - serial.print("RSI: "); - serial.print_hex(ctx.rsi); - serial.print(" RDI: "); - serial.print_hex(ctx.rdi); - serial.print("\n"); - - serial.print("RBP: "); - serial.print_hex(ctx.rbp); - serial.print(" RSP: "); - serial.print_hex(ctx.rsp); - serial.print("\n"); - - serial.print("RIP: "); - serial.print_hex(ctx.rip); - serial.print(" CR2: "); - serial.print_hex(ctx.cr2); - serial.print("\n"); - - serial.print("CR3: "); - serial.print_hex(ctx.cr3); - serial.print(" ERR: "); - serial.print_hex(ctx.error_code); - serial.print("\n"); + serial.printf("RAX: {x} RBX: {x}\n", .{ ctx.rax, ctx.rbx }); + serial.printf("RCX: {x} RDX: {x}\n", .{ ctx.rcx, ctx.rdx }); + serial.printf("RSI: {x} RDI: {x}\n", .{ ctx.rsi, ctx.rdi }); + serial.printf("RBP: {x} RSP: {x}\n", .{ ctx.rbp, ctx.rsp }); + serial.printf("RIP: {x} CR2: {x}\n", .{ ctx.rip, ctx.cr2 }); + serial.printf("CR3: {x} ERR: {x}\n", .{ ctx.cr3, ctx.error_code }); - // Disassemble faulting instruction serial.print("\nFaulting instruction bytes at RIP:\n "); const rip_ptr = @as([*]const u8, @ptrFromInt(ctx.rip)); - var i: usize = 0; - while (i < 16) : (i += 1) { - serial.print_hex(rip_ptr[i]); - serial.print(" "); + for (0..16) |i| { + serial.printf("{x} ", .{rip_ptr[i]}); } serial.print("\n"); } diff --git a/mirai/crimson/render.zig b/mirai/crimson/render.zig new file mode 100644 index 0000000..5877aa5 --- /dev/null +++ b/mirai/crimson/render.zig @@ -0,0 +1,155 @@ +//! Crimson screen rendering + +const colors = @import("../common/constants/colors.zig"); +const crimson_limits = @import("../common/limits/crimson.zig"); +const font = @import("../graphics/fonts/psf.zig"); +const format = @import("format.zig"); +const multiboot = @import("../boot/multiboot/multiboot.zig"); +const types = @import("types.zig"); +const video_const = @import("../common/constants/video.zig"); + +pub fn screen(fb: multiboot.FramebufferInfo, message: []const u8, context: ?*const types.Context) void { + fill_crimson(fb); + + const char_height = font.get_height(); + var y: u32 = 60; + + const heading = "Hey! You finally met Crimson!"; + centered_text(heading, y, fb, colors.WHITE); + y += char_height + 20; + + const desc1 = "Mirai Kernel has encountered an error and the system"; + const desc2 = "will need to be restarted. Please reboot your machine."; + centered_text(desc1, y, fb, colors.WHITE); + y += char_height + 4; + centered_text(desc2, y, fb, colors.WHITE); + y += char_height + 30; + + centered_text("Error:", y, fb, colors.WHITE); + y += char_height + 4; + centered_text(message, y, fb, colors.WHITE); + y += char_height + 30; + + if (context) |ctx| { + registers(ctx, y, fb); + y += (char_height + 4) * 10; + + centered_text("Stack Trace:", y, fb, colors.WHITE); + y += char_height + 4; + stack_trace(ctx.rbp, ctx.rip, y, fb); + } +} + +fn fill_crimson(fb: multiboot.FramebufferInfo) void { + if (fb.bpp == video_const.BPP_32) { + const pixels = @as([*]volatile u32, @ptrFromInt(fb.addr)); + const total = fb.height * (fb.pitch / 4); + + for (0..total) |i| { + pixels[i] = colors.CRIMSON; + } + } else if (fb.bpp == video_const.BPP_24) { + const pixels = @as([*]volatile u8, @ptrFromInt(fb.addr)); + + const r: u8 = @truncate((colors.CRIMSON >> 16) & 0xFF); + const g: u8 = @truncate((colors.CRIMSON >> 8) & 0xFF); + const b: u8 = @truncate(colors.CRIMSON & 0xFF); + + for (0..fb.height) |y| { + for (0..fb.width) |x| { + const offset = y * fb.pitch + x * 3; + pixels[offset] = b; + pixels[offset + 1] = g; + pixels[offset + 2] = r; + } + } + } +} + +pub fn centered_text(text: []const u8, y: u32, fb: multiboot.FramebufferInfo, color: u32) void { + const char_width: u32 = font.get_width(); + const text_width: u32 = @intCast(text.len * char_width); + + if (text_width > fb.width) { + font.render_text(text, 20, y, fb, color); + } else { + const x: u32 = (fb.width - text_width) / 2; + font.render_text(text, x, y, fb, color); + } +} + +fn registers(ctx: *const types.Context, start_y: u32, fb: multiboot.FramebufferInfo) void { + const char_height = font.get_height(); + var y = start_y; + var buffer: [crimson_limits.REGISTER_BUFFER_SIZE]u8 = undefined; + + register_pair("RAX", ctx.rax, "RBX", ctx.rbx, y, &buffer, fb); + y += char_height + 4; + + register_pair("RCX", ctx.rcx, "RDX", ctx.rdx, y, &buffer, fb); + y += char_height + 4; + + register_pair("RSI", ctx.rsi, "RDI", ctx.rdi, y, &buffer, fb); + y += char_height + 4; + + register_pair("RBP", ctx.rbp, "RSP", ctx.rsp, y, &buffer, fb); + y += char_height + 4; + + register_pair("R8 ", ctx.r8, "R9 ", ctx.r9, y, &buffer, fb); + y += char_height + 4; + + register_pair("R10", ctx.r10, "R11", ctx.r11, y, &buffer, fb); + y += char_height + 4; + + register_pair("R12", ctx.r12, "R13", ctx.r13, y, &buffer, fb); + y += char_height + 4; + + register_pair("R14", ctx.r14, "R15", ctx.r15, y, &buffer, fb); + y += char_height + 4; + + register_pair("RIP", ctx.rip, "CR2", ctx.cr2, y, &buffer, fb); + y += char_height + 4; + + register_pair("CR3", ctx.cr3, "ERR", ctx.error_code, y, &buffer, fb); +} + +fn register_pair(label1: []const u8, val1: u64, label2: []const u8, val2: u64, y: u32, buffer: []u8, fb: multiboot.FramebufferInfo) void { + const left_x: u32 = 100; + const right_x: u32 = 500; + + const text1 = format.register(label1, val1, buffer[0..49]); + font.render_text(text1, left_x, y, fb, colors.WHITE); + + const text2 = format.register(label2, val2, buffer[50..99]); + font.render_text(text2, right_x, y, fb, colors.WHITE); +} + +fn stack_trace(rbp: u64, rip: u64, start_y: u32, fb: multiboot.FramebufferInfo) void { + const char_height = font.get_height(); + var y = start_y; + var buffer: [crimson_limits.STACK_FRAME_BUFFER_SIZE]u8 = undefined; + + const text0 = format.stack_frame(0, rip, &buffer); + centered_text(text0, y, fb, colors.WHITE); + y += char_height + 2; + + var frame_rbp = rbp; + var frame_num: usize = 1; + + while (frame_num < crimson_limits.MAX_STACK_FRAMES) : (frame_num += 1) { + if (frame_rbp < 0xFFFF800000000000 or frame_rbp == 0) break; + + const ret_addr = @as(*const u64, @ptrFromInt(frame_rbp + 8)).*; + + if (ret_addr < 0xFFFF800000000000) break; + + const text = format.stack_frame(frame_num, ret_addr, &buffer); + centered_text(text, y, fb, colors.WHITE); + y += char_height + 2; + + const next_rbp = @as(*const u64, @ptrFromInt(frame_rbp)).*; + + if (next_rbp == 0 or next_rbp == frame_rbp) break; + frame_rbp = next_rbp; + } +} diff --git a/mirai/crimson/types.zig b/mirai/crimson/types.zig new file mode 100644 index 0000000..6383c71 --- /dev/null +++ b/mirai/crimson/types.zig @@ -0,0 +1,50 @@ +//! Crimson type definitions + +pub const Context = struct { + rax: u64, + rbx: u64, + rcx: u64, + rdx: u64, + rsi: u64, + rdi: u64, + rbp: u64, + rsp: u64, + r8: u64, + r9: u64, + r10: u64, + r11: u64, + r12: u64, + r13: u64, + r14: u64, + r15: u64, + rip: u64, + rflags: u64, + error_code: u64, + cr2: u64, + cr3: u64, +}; + +pub const ExceptionFrame = packed struct { + r15: u64, + r14: u64, + r13: u64, + r12: u64, + r11: u64, + r10: u64, + r9: u64, + r8: u64, + rbp: u64, + rdi: u64, + rsi: u64, + rdx: u64, + rcx: u64, + rbx: u64, + rax: u64, + int_num: u64, + error_code: u64, + rip: u64, + cs: u64, + rflags: u64, + rsp: u64, + ss: u64, +}; diff --git a/mirai/interrupts/idt.zig b/mirai/interrupts/idt.zig index fb9ad2a..096d359 100644 --- a/mirai/interrupts/idt.zig +++ b/mirai/interrupts/idt.zig @@ -7,7 +7,7 @@ const sensei = @import("../kata/sensei.zig"); const serial = @import("../drivers/serial/serial.zig"); comptime { - _ = @import("../crimson/exceptions.zig"); + _ = @import("../crimson/exception.zig"); } const IDTEntry = packed struct { diff --git a/mirai/mirai.zig b/mirai/mirai.zig index f43c8e5..c3e2cfe 100644 --- a/mirai/mirai.zig +++ b/mirai/mirai.zig @@ -1,5 +1,5 @@ const cpu = @import("asm/cpu.zig"); -const crimson = @import("crimson/panic.zig"); +const crimson = @import("crimson/crimson.zig"); const sequence = @import("boot/sequence/sequence.zig"); const serial = @import("drivers/serial/serial.zig"); |
