aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-02-15 20:05:15 +0530
committerBobby <[email protected]>2026-02-15 20:05:15 +0530
commit90663e30db47e87f896245cc20ce0b0284fcdc5f (patch)
tree738687ecaaf338d396faea98c724523273159035
parent84d9abdb8f4a92ca99c75e4dd8948c1196f6260f (diff)
downloadakiba-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.zig2
-rw-r--r--mirai/common/constants/colors.zig5
-rw-r--r--mirai/common/limits/crimson.zig6
-rw-r--r--mirai/crimson/crimson.zig15
-rw-r--r--mirai/crimson/exception.zig102
-rw-r--r--mirai/crimson/exceptions.zig188
-rw-r--r--mirai/crimson/format.zig132
-rw-r--r--mirai/crimson/panic.zig423
-rw-r--r--mirai/crimson/render.zig155
-rw-r--r--mirai/crimson/types.zig50
-rw-r--r--mirai/interrupts/idt.zig2
-rw-r--r--mirai/mirai.zig2
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");