aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mirai/asm/asm.zig2
-rw-r--r--mirai/asm/cpu/cpu.zig10
-rw-r--r--mirai/asm/cpu/state.zig67
-rw-r--r--mirai/asm/debug/debug.zig95
-rw-r--r--mirai/asm/fpu/fpu.zig41
-rw-r--r--mirai/crimson/classify/analyze.zig26
-rw-r--r--mirai/crimson/classify/classify.zig11
-rw-r--r--mirai/crimson/classify/vector.zig10
-rw-r--r--mirai/crimson/constants/behaviors.zig39
-rw-r--r--mirai/crimson/constants/codes.zig12
-rw-r--r--mirai/crimson/constants/constants.zig24
-rw-r--r--mirai/crimson/constants/flavors.zig11
-rw-r--r--mirai/crimson/constants/types.zig51
-rw-r--r--mirai/crimson/constants/vectors.zig42
-rw-r--r--mirai/crimson/context/capture.zig25
-rw-r--r--mirai/crimson/context/context.zig14
-rw-r--r--mirai/crimson/context/debug.zig25
-rw-r--r--mirai/crimson/context/dump.zig14
-rw-r--r--mirai/crimson/context/float.zig17
-rw-r--r--mirai/crimson/corpse/corpse.zig20
-rw-r--r--mirai/crimson/corpse/generate.zig78
-rw-r--r--mirai/crimson/corpse/inspect.zig59
-rw-r--r--mirai/crimson/corpse/release.zig56
-rw-r--r--mirai/crimson/crimson.zig42
-rw-r--r--mirai/crimson/handlers/breach.zig21
-rw-r--r--mirai/crimson/handlers/collapse.zig12
-rw-r--r--mirai/crimson/handlers/entry.zig44
-rw-r--r--mirai/crimson/handlers/forbidden.zig15
-rw-r--r--mirai/crimson/handlers/handlers.zig32
-rw-r--r--mirai/crimson/handlers/missing.zig13
-rw-r--r--mirai/crimson/handlers/overflow.zig15
-rw-r--r--mirai/crimson/handlers/shatter.zig11
-rw-r--r--mirai/crimson/panic/collapse.zig76
-rw-r--r--mirai/crimson/panic/gather.zig39
-rw-r--r--mirai/crimson/panic/halt.zig21
-rw-r--r--mirai/crimson/panic/panic.zig18
-rw-r--r--mirai/crimson/ports/array.zig18
-rw-r--r--mirai/crimson/ports/host.zig42
-rw-r--r--mirai/crimson/ports/kata.zig79
-rw-r--r--mirai/crimson/ports/lookup.zig54
-rw-r--r--mirai/crimson/ports/masks.zig42
-rw-r--r--mirai/crimson/ports/port.zig17
-rw-r--r--mirai/crimson/ports/ports.zig22
-rw-r--r--mirai/crimson/ports/thread.zig79
-rw-r--r--mirai/crimson/propagate/chain.zig64
-rw-r--r--mirai/crimson/propagate/deliver.zig58
-rw-r--r--mirai/crimson/propagate/propagate.zig15
-rw-r--r--mirai/crimson/propagate/triage.zig35
-rw-r--r--mirai/crimson/propagate/wait.zig48
-rw-r--r--mirai/crimson/raise/guard.zig45
-rw-r--r--mirai/crimson/raise/hardware.zig33
-rw-r--r--mirai/crimson/raise/raise.zig21
-rw-r--r--mirai/crimson/raise/resource.zig45
-rw-r--r--mirai/crimson/raise/software.zig46
-rw-r--r--mirai/crimson/receive/actions.zig49
-rw-r--r--mirai/crimson/receive/catch.zig60
-rw-r--r--mirai/crimson/receive/receive.zig25
-rw-r--r--mirai/crimson/receive/reply.zig49
-rw-r--r--mirai/crimson/recover/recover.zig16
-rw-r--r--mirai/crimson/recover/resume.zig29
-rw-r--r--mirai/crimson/recover/skip.zig32
-rw-r--r--mirai/crimson/recover/terminate.zig44
-rw-r--r--mirai/crimson/render/banner.zig23
-rw-r--r--mirai/crimson/render/context.zig37
-rw-r--r--mirai/crimson/render/exception.zig61
-rw-r--r--mirai/crimson/render/memory.zig56
-rw-r--r--mirai/crimson/render/modules.zig69
-rw-r--r--mirai/crimson/render/render.zig29
-rw-r--r--mirai/crimson/render/stack.zig47
-rw-r--r--mirai/crimson/state.zig45
-rw-r--r--mirai/crimson/types/context.zig20
-rw-r--r--mirai/crimson/types/corpse.zig18
-rw-r--r--mirai/crimson/types/exception.zig17
-rw-r--r--mirai/crimson/types/flavor.zig64
-rw-r--r--mirai/crimson/types/frame.zig11
-rw-r--r--mirai/crimson/types/identity.zig8
-rw-r--r--mirai/crimson/types/port.zig17
-rw-r--r--mirai/crimson/types/types.zig22
78 files changed, 2719 insertions, 0 deletions
diff --git a/mirai/asm/asm.zig b/mirai/asm/asm.zig
index 520ea9e..1a12c31 100644
--- a/mirai/asm/asm.zig
+++ b/mirai/asm/asm.zig
@@ -3,3 +3,5 @@
pub const cpu = @import("cpu/cpu.zig");
pub const io = @import("io/io.zig");
pub const gdt = @import("gdt/gdt.zig");
+pub const debug = @import("debug/debug.zig");
+pub const fpu = @import("fpu/fpu.zig");
diff --git a/mirai/asm/cpu/cpu.zig b/mirai/asm/cpu/cpu.zig
index a2c6a78..0834f03 100644
--- a/mirai/asm/cpu/cpu.zig
+++ b/mirai/asm/cpu/cpu.zig
@@ -2,6 +2,7 @@
pub const control = @import("control.zig");
pub const halt = @import("halt.zig");
+pub const state = @import("state.zig");
pub const read_cr0 = control.read_cr0;
pub const write_cr0 = control.write_cr0;
@@ -20,3 +21,12 @@ pub const disable_interrupts = halt.disable_interrupts;
pub const are_interrupts_enabled = halt.are_interrupts_enabled;
pub const read_flags = halt.read_flags;
pub const pause = halt.pause;
+
+pub const read_rsp = state.read_rsp;
+pub const read_rbp = state.read_rbp;
+pub const rdtsc = state.rdtsc;
+pub const read_ds = state.read_ds;
+pub const read_es = state.read_es;
+pub const read_fs = state.read_fs;
+pub const read_gs = state.read_gs;
+pub const clear_task_switched = state.clear_task_switched;
diff --git a/mirai/asm/cpu/state.zig b/mirai/asm/cpu/state.zig
new file mode 100644
index 0000000..4b20a11
--- /dev/null
+++ b/mirai/asm/cpu/state.zig
@@ -0,0 +1,67 @@
+//! CPU State Operations
+
+pub fn read_rsp() u64 {
+ var rsp: u64 = undefined;
+ asm volatile ("mov %%rsp, %[rsp]"
+ : [rsp] "=r" (rsp),
+ );
+ return rsp;
+}
+
+pub fn read_rbp() u64 {
+ var rbp: u64 = undefined;
+ asm volatile ("mov %%rbp, %[rbp]"
+ : [rbp] "=r" (rbp),
+ );
+ return rbp;
+}
+
+pub fn rdtsc() u64 {
+ var low: u32 = undefined;
+ var high: u32 = undefined;
+ asm volatile ("rdtsc"
+ : [low] "={eax}" (low),
+ [high] "={edx}" (high),
+ );
+ return (@as(u64, high) << 32) | low;
+}
+
+pub fn read_ds() u16 {
+ var ds: u16 = undefined;
+ asm volatile ("mov %%ds, %[ds]"
+ : [ds] "=r" (ds),
+ );
+ return ds;
+}
+
+pub fn read_es() u16 {
+ var es: u16 = undefined;
+ asm volatile ("mov %%es, %[es]"
+ : [es] "=r" (es),
+ );
+ return es;
+}
+
+pub fn read_fs() u16 {
+ var fs: u16 = undefined;
+ asm volatile ("mov %%fs, %[fs]"
+ : [fs] "=r" (fs),
+ );
+ return fs;
+}
+
+pub fn read_gs() u16 {
+ var gs: u16 = undefined;
+ asm volatile ("mov %%gs, %[gs]"
+ : [gs] "=r" (gs),
+ );
+ return gs;
+}
+
+pub fn clear_task_switched() void {
+ asm volatile (
+ \\mov %%cr0, %%rax
+ \\and $~8, %%rax
+ \\mov %%rax, %%cr0
+ ::: .{ .rax = true });
+}
diff --git a/mirai/asm/debug/debug.zig b/mirai/asm/debug/debug.zig
new file mode 100644
index 0000000..9110202
--- /dev/null
+++ b/mirai/asm/debug/debug.zig
@@ -0,0 +1,95 @@
+//! Debug Register Operations
+
+pub fn read_dr0() u64 {
+ var value: u64 = undefined;
+ asm volatile ("mov %%dr0, %[value]"
+ : [value] "=r" (value),
+ );
+ return value;
+}
+
+pub fn read_dr1() u64 {
+ var value: u64 = undefined;
+ asm volatile ("mov %%dr1, %[value]"
+ : [value] "=r" (value),
+ );
+ return value;
+}
+
+pub fn read_dr2() u64 {
+ var value: u64 = undefined;
+ asm volatile ("mov %%dr2, %[value]"
+ : [value] "=r" (value),
+ );
+ return value;
+}
+
+pub fn read_dr3() u64 {
+ var value: u64 = undefined;
+ asm volatile ("mov %%dr3, %[value]"
+ : [value] "=r" (value),
+ );
+ return value;
+}
+
+pub fn read_dr6() u64 {
+ var value: u64 = undefined;
+ asm volatile ("mov %%dr6, %[value]"
+ : [value] "=r" (value),
+ );
+ return value;
+}
+
+pub fn read_dr7() u64 {
+ var value: u64 = undefined;
+ asm volatile ("mov %%dr7, %[value]"
+ : [value] "=r" (value),
+ );
+ return value;
+}
+
+pub fn write_dr0(value: u64) void {
+ asm volatile ("mov %[value], %%dr0"
+ :
+ : [value] "r" (value),
+ );
+}
+
+pub fn write_dr1(value: u64) void {
+ asm volatile ("mov %[value], %%dr1"
+ :
+ : [value] "r" (value),
+ );
+}
+
+pub fn write_dr2(value: u64) void {
+ asm volatile ("mov %[value], %%dr2"
+ :
+ : [value] "r" (value),
+ );
+}
+
+pub fn write_dr3(value: u64) void {
+ asm volatile ("mov %[value], %%dr3"
+ :
+ : [value] "r" (value),
+ );
+}
+
+pub fn write_dr6(value: u64) void {
+ asm volatile ("mov %[value], %%dr6"
+ :
+ : [value] "r" (value),
+ );
+}
+
+pub fn write_dr7(value: u64) void {
+ asm volatile ("mov %[value], %%dr7"
+ :
+ : [value] "r" (value),
+ );
+}
+
+pub fn clear_dr6() void {
+ write_dr6(0);
+}
diff --git a/mirai/asm/fpu/fpu.zig b/mirai/asm/fpu/fpu.zig
new file mode 100644
index 0000000..4f5e5db
--- /dev/null
+++ b/mirai/asm/fpu/fpu.zig
@@ -0,0 +1,41 @@
+//! FPU/SSE Operations
+
+pub fn fxsave(addr: u64) void {
+ asm volatile ("fxsave (%[addr])"
+ :
+ : [addr] "r" (addr),
+ : .{ .memory = true }
+ );
+}
+
+pub fn fxrstor(addr: u64) void {
+ asm volatile ("fxrstor (%[addr])"
+ :
+ : [addr] "r" (addr),
+ : .{ .memory = true }
+ );
+}
+
+pub fn fninit() void {
+ asm volatile ("fninit");
+}
+
+pub fn fnclex() void {
+ asm volatile ("fnclex");
+}
+
+pub fn stmxcsr(addr: *u32) void {
+ asm volatile ("stmxcsr (%[addr])"
+ :
+ : [addr] "r" (addr),
+ : .{ .memory = true }
+ );
+}
+
+pub fn ldmxcsr(addr: *const u32) void {
+ asm volatile ("ldmxcsr (%[addr])"
+ :
+ : [addr] "r" (addr),
+ : .{ .memory = true }
+ );
+}
diff --git a/mirai/crimson/classify/analyze.zig b/mirai/crimson/classify/analyze.zig
new file mode 100644
index 0000000..e4287a4
--- /dev/null
+++ b/mirai/crimson/classify/analyze.zig
@@ -0,0 +1,26 @@
+//! Analyze Error Codes
+
+pub const PageFaultError = struct {
+ present: bool, write: bool, user: bool, reserved_write: bool, instruction_fetch: bool,
+ pub fn from_error_code(code: u64) PageFaultError {
+ return PageFaultError{
+ .present = (code & 1) != 0, .write = (code & 2) != 0, .user = (code & 4) != 0,
+ .reserved_write = (code & 8) != 0, .instruction_fetch = (code & 16) != 0,
+ };
+ }
+ pub fn is_not_present(self: PageFaultError) bool { return !self.present; }
+ pub fn is_write_access(self: PageFaultError) bool { return self.write; }
+ pub fn is_execute_access(self: PageFaultError) bool { return self.instruction_fetch; }
+ pub fn description(self: PageFaultError) []const u8 {
+ if (self.instruction_fetch) return if (self.present) "Execute on non-executable page" else "Execute on non-present page";
+ if (self.write) return if (self.present) "Write to read-only page" else "Write to non-present page";
+ return if (self.present) "Read from protected page" else "Read from non-present page";
+ }
+};
+
+pub const SelectorError = struct {
+ external: bool, table: u2, index: u13,
+ pub fn from_error_code(code: u64) SelectorError {
+ return SelectorError{ .external = (code & 1) != 0, .table = @truncate((code >> 1) & 0x3), .index = @truncate((code >> 3) & 0x1FFF) };
+ }
+};
diff --git a/mirai/crimson/classify/classify.zig b/mirai/crimson/classify/classify.zig
new file mode 100644
index 0000000..1ae14d3
--- /dev/null
+++ b/mirai/crimson/classify/classify.zig
@@ -0,0 +1,11 @@
+//! Exception Classification
+
+pub const vector = @import("vector.zig");
+pub const analyze = @import("analyze.zig");
+
+pub const classify_vector = vector.classify_vector;
+pub const get_vector_name = vector.get_vector_name;
+pub const vector_has_error_code = vector.vector_has_error_code;
+pub const is_exception_vector = vector.is_exception_vector;
+pub const PageFaultError = analyze.PageFaultError;
+pub const SelectorError = analyze.SelectorError;
diff --git a/mirai/crimson/classify/vector.zig b/mirai/crimson/classify/vector.zig
new file mode 100644
index 0000000..213b1ee
--- /dev/null
+++ b/mirai/crimson/classify/vector.zig
@@ -0,0 +1,10 @@
+//! Vector Classification
+
+const constants = @import("../constants/constants.zig");
+const ExceptionType = constants.ExceptionType;
+const vectors = constants.vectors;
+
+pub fn classify_vector(vector_number: u8) ExceptionType { return vectors.get_exception_type(vector_number); }
+pub fn get_vector_name(vector_number: u8) []const u8 { return vectors.get_name(vector_number); }
+pub fn vector_has_error_code(vector_number: u8) bool { return vectors.has_error_code(vector_number); }
+pub fn is_exception_vector(vector_number: u8) bool { return vector_number < 32; }
diff --git a/mirai/crimson/constants/behaviors.zig b/mirai/crimson/constants/behaviors.zig
new file mode 100644
index 0000000..606cc95
--- /dev/null
+++ b/mirai/crimson/constants/behaviors.zig
@@ -0,0 +1,39 @@
+//! Exception Behaviors
+
+pub const Behavior = enum(u8) {
+ default = 0,
+ state = 1,
+ state_identity = 2,
+
+ pub fn includes_state(self: Behavior) bool {
+ return self == .state or self == .state_identity;
+ }
+
+ pub fn includes_identity(self: Behavior) bool {
+ return self == .state_identity;
+ }
+};
+
+pub const Action = enum(u8) {
+ @"resume" = 0,
+ skip = 1,
+ terminate = 2,
+ terminate_corpse = 3,
+ collapse = 4,
+ debug = 5,
+
+ pub fn is_fatal(self: Action) bool {
+ return self == .terminate or self == .terminate_corpse or self == .collapse;
+ }
+
+ pub fn name(self: Action) []const u8 {
+ return switch (self) {
+ .@"resume" => "Resume",
+ .skip => "Skip",
+ .terminate => "Terminate",
+ .terminate_corpse => "Terminate with Corpse",
+ .collapse => "Collapse",
+ .debug => "Debug",
+ };
+ }
+};
diff --git a/mirai/crimson/constants/codes.zig b/mirai/crimson/constants/codes.zig
new file mode 100644
index 0000000..87d5fc1
--- /dev/null
+++ b/mirai/crimson/constants/codes.zig
@@ -0,0 +1,12 @@
+//! Exception Codes
+
+pub const BreachCode = enum(u8) { page_not_present = 0, page_protection = 1, page_write = 2, page_execute = 3, page_user = 4, segment_not_present = 5, stack_fault = 6, stack_overflow = 7 };
+pub const ForbiddenCode = enum(u8) { invalid_opcode = 0, general_protection = 1, privilege_violation = 2, alignment_check = 3, bound_range = 4 };
+pub const OverflowCode = enum(u8) { divide_by_zero = 0, integer_overflow = 1, fpu_error = 2, simd_error = 3 };
+pub const ShatterCode = enum(u8) { breakpoint = 0, single_step = 1, watchpoint = 2, debug_exception = 3 };
+pub const MissingCode = enum(u8) { fpu_not_available = 0, device_not_available = 1 };
+pub const CriticalCode = enum(u8) { nmi = 0, machine_check = 1 };
+pub const SoftwareCode = enum(u8) { assertion = 0, abort = 1, user_defined = 2 };
+pub const ResourceCode = enum(u8) { memory_limit = 0, cpu_limit = 1, file_limit = 2 };
+pub const GuardCode = enum(u8) { port_guard = 0, file_guard = 1, memory_guard = 2 };
+pub const CollapseCode = enum(u8) { double_fault = 0, triple_fault = 1, machine_check = 2, kernel_panic = 3, invalid_tss = 4 };
diff --git a/mirai/crimson/constants/constants.zig b/mirai/crimson/constants/constants.zig
new file mode 100644
index 0000000..5b0be4d
--- /dev/null
+++ b/mirai/crimson/constants/constants.zig
@@ -0,0 +1,24 @@
+//! Crimson Constants
+
+pub const types = @import("types.zig");
+pub const codes = @import("codes.zig");
+pub const vectors = @import("vectors.zig");
+pub const behaviors = @import("behaviors.zig");
+pub const flavors = @import("flavors.zig");
+
+pub const ExceptionType = types.ExceptionType;
+pub const Behavior = behaviors.Behavior;
+pub const Action = behaviors.Action;
+pub const Flavor = flavors.Flavor;
+pub const Vector = vectors.Vector;
+
+pub const BreachCode = codes.BreachCode;
+pub const ForbiddenCode = codes.ForbiddenCode;
+pub const OverflowCode = codes.OverflowCode;
+pub const ShatterCode = codes.ShatterCode;
+pub const MissingCode = codes.MissingCode;
+pub const CriticalCode = codes.CriticalCode;
+pub const SoftwareCode = codes.SoftwareCode;
+pub const ResourceCode = codes.ResourceCode;
+pub const GuardCode = codes.GuardCode;
+pub const CollapseCode = codes.CollapseCode;
diff --git a/mirai/crimson/constants/flavors.zig b/mirai/crimson/constants/flavors.zig
new file mode 100644
index 0000000..4639522
--- /dev/null
+++ b/mirai/crimson/constants/flavors.zig
@@ -0,0 +1,11 @@
+//! State Flavors
+
+pub const Flavor = enum(u8) {
+ none = 0, general = 1, float = 2, debug = 3, avx = 4, full = 5,
+ pub fn includes_general(self: Flavor) bool { return self == .general or self == .full; }
+ pub fn includes_float(self: Flavor) bool { return self == .float or self == .full; }
+ pub fn includes_debug(self: Flavor) bool { return self == .debug or self == .full; }
+ pub fn name(self: Flavor) []const u8 {
+ return switch (self) { .none => "None", .general => "General", .float => "Float", .debug => "Debug", .avx => "AVX", .full => "Full" };
+ }
+};
diff --git a/mirai/crimson/constants/types.zig b/mirai/crimson/constants/types.zig
new file mode 100644
index 0000000..d0ffdf2
--- /dev/null
+++ b/mirai/crimson/constants/types.zig
@@ -0,0 +1,51 @@
+//! Exception Types
+
+pub const ExceptionType = enum(u8) {
+ breach = 0,
+ forbidden = 1,
+ overflow = 2,
+ shatter = 3,
+ missing = 4,
+ critical = 5,
+ software = 6,
+ resource = 7,
+ guard = 8,
+ collapse = 9,
+
+ pub fn is_recoverable(self: ExceptionType) bool {
+ return switch (self) {
+ .breach, .forbidden, .overflow, .shatter, .missing, .software, .resource, .guard => true,
+ .critical, .collapse => false,
+ };
+ }
+
+ pub fn name(self: ExceptionType) []const u8 {
+ return switch (self) {
+ .breach => "Breach",
+ .forbidden => "Forbidden",
+ .overflow => "Overflow",
+ .shatter => "Shatter",
+ .missing => "Missing",
+ .critical => "Critical",
+ .software => "Software",
+ .resource => "Resource",
+ .guard => "Guard",
+ .collapse => "Collapse",
+ };
+ }
+
+ pub fn description(self: ExceptionType) []const u8 {
+ return switch (self) {
+ .breach => "Memory access failure",
+ .forbidden => "Illegal operation",
+ .overflow => "Arithmetic exception",
+ .shatter => "Debug or breakpoint",
+ .missing => "Resource not available",
+ .critical => "System-level interrupt",
+ .software => "Software-raised exception",
+ .resource => "Resource limit exceeded",
+ .guard => "Guarded resource violation",
+ .collapse => "Unrecoverable error",
+ };
+ }
+};
diff --git a/mirai/crimson/constants/vectors.zig b/mirai/crimson/constants/vectors.zig
new file mode 100644
index 0000000..92d903b
--- /dev/null
+++ b/mirai/crimson/constants/vectors.zig
@@ -0,0 +1,42 @@
+//! CPU Vector Mapping
+
+const types = @import("types.zig");
+const ExceptionType = types.ExceptionType;
+
+pub const Vector = struct { number: u8, exception_type: ExceptionType, has_error_code: bool, name: []const u8 };
+
+pub const vectors = [_]Vector{
+ .{ .number = 0, .exception_type = .overflow, .has_error_code = false, .name = "Divide Error" },
+ .{ .number = 1, .exception_type = .shatter, .has_error_code = false, .name = "Debug" },
+ .{ .number = 2, .exception_type = .critical, .has_error_code = false, .name = "NMI" },
+ .{ .number = 3, .exception_type = .shatter, .has_error_code = false, .name = "Breakpoint" },
+ .{ .number = 4, .exception_type = .overflow, .has_error_code = false, .name = "Overflow" },
+ .{ .number = 5, .exception_type = .forbidden, .has_error_code = false, .name = "Bound Range" },
+ .{ .number = 6, .exception_type = .forbidden, .has_error_code = false, .name = "Invalid Opcode" },
+ .{ .number = 7, .exception_type = .missing, .has_error_code = false, .name = "Device Not Available" },
+ .{ .number = 8, .exception_type = .collapse, .has_error_code = true, .name = "Double Fault" },
+ .{ .number = 10, .exception_type = .collapse, .has_error_code = true, .name = "Invalid TSS" },
+ .{ .number = 11, .exception_type = .breach, .has_error_code = true, .name = "Segment Not Present" },
+ .{ .number = 12, .exception_type = .breach, .has_error_code = true, .name = "Stack Fault" },
+ .{ .number = 13, .exception_type = .forbidden, .has_error_code = true, .name = "General Protection" },
+ .{ .number = 14, .exception_type = .breach, .has_error_code = true, .name = "Page Fault" },
+ .{ .number = 16, .exception_type = .overflow, .has_error_code = false, .name = "x87 FPU Error" },
+ .{ .number = 17, .exception_type = .forbidden, .has_error_code = true, .name = "Alignment Check" },
+ .{ .number = 18, .exception_type = .collapse, .has_error_code = false, .name = "Machine Check" },
+ .{ .number = 19, .exception_type = .overflow, .has_error_code = false, .name = "SIMD Error" },
+};
+
+pub fn get_exception_type(vector_number: u8) ExceptionType {
+ for (vectors) |v| { if (v.number == vector_number) return v.exception_type; }
+ return .forbidden;
+}
+
+pub fn has_error_code(vector_number: u8) bool {
+ for (vectors) |v| { if (v.number == vector_number) return v.has_error_code; }
+ return false;
+}
+
+pub fn get_name(vector_number: u8) []const u8 {
+ for (vectors) |v| { if (v.number == vector_number) return v.name; }
+ return "Unknown";
+}
diff --git a/mirai/crimson/context/capture.zig b/mirai/crimson/context/capture.zig
new file mode 100644
index 0000000..896d1a6
--- /dev/null
+++ b/mirai/crimson/context/capture.zig
@@ -0,0 +1,25 @@
+//! Capture CPU Context
+
+const asm_cpu = @import("../../asm/cpu/cpu.zig");
+const types = @import("../types/types.zig");
+const Context = types.Context;
+const Frame = types.Frame;
+
+pub fn capture_from_frame(context: *Context, frame: *const Frame) void {
+ context.rip = frame.rip;
+ context.cs = @truncate(frame.cs);
+ context.rflags = frame.rflags;
+ context.rsp = frame.rsp;
+ context.ss = @truncate(frame.ss);
+ context.cr0 = asm_cpu.read_cr0();
+ context.cr2 = asm_cpu.read_cr2();
+ context.cr3 = asm_cpu.read_cr3();
+ context.cr4 = asm_cpu.read_cr4();
+}
+
+pub fn capture_segments(context: *Context) void {
+ context.ds = asm_cpu.read_ds();
+ context.es = asm_cpu.read_es();
+ context.fs = asm_cpu.read_fs();
+ context.gs = asm_cpu.read_gs();
+}
diff --git a/mirai/crimson/context/context.zig b/mirai/crimson/context/context.zig
new file mode 100644
index 0000000..cc6351c
--- /dev/null
+++ b/mirai/crimson/context/context.zig
@@ -0,0 +1,14 @@
+//! Context Operations
+
+pub const capture = @import("capture.zig");
+pub const float = @import("float.zig");
+pub const debug = @import("debug.zig");
+pub const dump = @import("dump.zig");
+
+pub const capture_from_frame = capture.capture_from_frame;
+pub const capture_segments = capture.capture_segments;
+pub const capture_float = float.capture;
+pub const restore_float = float.restore;
+pub const capture_debug = debug.capture;
+pub const restore_debug = debug.restore;
+pub const dump_context = dump.dump_context;
diff --git a/mirai/crimson/context/debug.zig b/mirai/crimson/context/debug.zig
new file mode 100644
index 0000000..13b4fc0
--- /dev/null
+++ b/mirai/crimson/context/debug.zig
@@ -0,0 +1,25 @@
+//! Capture Debug Registers
+
+const asm_debug = @import("../../asm/debug/debug.zig");
+const types = @import("../types/types.zig");
+const DebugState = types.DebugState;
+
+pub fn capture(state: *DebugState) void {
+ state.dr0 = asm_debug.read_dr0();
+ state.dr1 = asm_debug.read_dr1();
+ state.dr2 = asm_debug.read_dr2();
+ state.dr3 = asm_debug.read_dr3();
+ state.dr6 = asm_debug.read_dr6();
+ state.dr7 = asm_debug.read_dr7();
+ state.dr4 = 0;
+ state.dr5 = 0;
+}
+
+pub fn restore(state: *const DebugState) void {
+ asm_debug.write_dr0(state.dr0);
+ asm_debug.write_dr1(state.dr1);
+ asm_debug.write_dr2(state.dr2);
+ asm_debug.write_dr3(state.dr3);
+ asm_debug.write_dr6(state.dr6);
+ asm_debug.write_dr7(state.dr7);
+}
diff --git a/mirai/crimson/context/dump.zig b/mirai/crimson/context/dump.zig
new file mode 100644
index 0000000..ce8e1ac
--- /dev/null
+++ b/mirai/crimson/context/dump.zig
@@ -0,0 +1,14 @@
+//! Dump Context for Debugging
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const Context = types.Context;
+
+pub fn dump_context(ctx: *const Context) void {
+ serial.printf("RAX: %x RBX: %x RCX: %x RDX: %x\n", .{ ctx.rax, ctx.rbx, ctx.rcx, ctx.rdx });
+ serial.printf("RSI: %x RDI: %x RBP: %x RSP: %x\n", .{ ctx.rsi, ctx.rdi, ctx.rbp, ctx.rsp });
+ serial.printf("R8: %x R9: %x R10: %x R11: %x\n", .{ ctx.r8, ctx.r9, ctx.r10, ctx.r11 });
+ serial.printf("R12: %x R13: %x R14: %x R15: %x\n", .{ ctx.r12, ctx.r13, ctx.r14, ctx.r15 });
+ serial.printf("RIP: %x RFLAGS: %x\n", .{ ctx.rip, ctx.rflags });
+ serial.printf("CR0: %x CR2: %x CR3: %x CR4: %x\n", .{ ctx.cr0, ctx.cr2, ctx.cr3, ctx.cr4 });
+}
diff --git a/mirai/crimson/context/float.zig b/mirai/crimson/context/float.zig
new file mode 100644
index 0000000..5451f09
--- /dev/null
+++ b/mirai/crimson/context/float.zig
@@ -0,0 +1,17 @@
+//! Capture Floating Point State
+
+const asm_fpu = @import("../../asm/fpu/fpu.zig");
+const types = @import("../types/types.zig");
+const FloatState = types.FloatState;
+
+pub fn capture(state: *FloatState) void {
+ asm_fpu.fxsave(@intFromPtr(state));
+}
+
+pub fn restore(state: *const FloatState) void {
+ asm_fpu.fxrstor(@intFromPtr(state));
+}
+
+pub fn init_fpu() void {
+ asm_fpu.fninit();
+}
diff --git a/mirai/crimson/corpse/corpse.zig b/mirai/crimson/corpse/corpse.zig
new file mode 100644
index 0000000..4e91f3e
--- /dev/null
+++ b/mirai/crimson/corpse/corpse.zig
@@ -0,0 +1,20 @@
+//! Corpse Operations
+
+pub const generate_module = @import("generate.zig");
+pub const inspect = @import("inspect.zig");
+pub const release = @import("release.zig");
+
+pub const generate = generate_module.generate;
+
+pub const inspect_corpse = inspect.inspect;
+pub const get_context = inspect.get_context;
+pub const get_stack_snapshot = inspect.get_stack_snapshot;
+pub const get_memory_snapshot = inspect.get_memory_snapshot;
+pub const get_memory_snapshot_address = inspect.get_memory_snapshot_address;
+pub const get_fault_address = inspect.get_fault_address;
+pub const get_timestamp = inspect.get_timestamp;
+
+pub const allocate = release.allocate;
+pub const release_corpse = release.release;
+pub const release_all_for_kata = release.release_all_for_kata;
+pub const get_active_count = release.get_active_count;
diff --git a/mirai/crimson/corpse/generate.zig b/mirai/crimson/corpse/generate.zig
new file mode 100644
index 0000000..c859c15
--- /dev/null
+++ b/mirai/crimson/corpse/generate.zig
@@ -0,0 +1,78 @@
+//! Generate Corpse
+
+const asm_cpu = @import("../../asm/cpu/cpu.zig");
+const types = @import("../types/types.zig");
+const context_ops = @import("../context/context.zig");
+
+const Corpse = types.Corpse;
+const Exception = types.Exception;
+const Context = types.Context;
+const FloatState = types.FloatState;
+const DebugState = types.DebugState;
+const Identity = types.Identity;
+
+pub fn generate(exception: *const Exception) Corpse {
+ var corpse: Corpse = undefined;
+ corpse.clear();
+
+ corpse.kata_id = exception.kata_id;
+ corpse.thread_id = exception.thread_id;
+ corpse.exception_type = exception.exception_type;
+ corpse.exception_code = exception.code;
+ corpse.exception_subcode = exception.subcode;
+ corpse.fault_address = exception.address;
+
+ corpse.context = exception.context.*;
+
+ capture_float_state(&corpse.float_state);
+ capture_debug_state(&corpse.debug_state);
+
+ capture_stack_snapshot(&corpse, exception.context.rsp);
+
+ if (exception.address != 0) {
+ capture_memory_snapshot(&corpse, exception.address);
+ }
+
+ corpse.timestamp = asm_cpu.rdtsc();
+ corpse.mark_valid();
+
+ return corpse;
+}
+
+fn capture_float_state(state: *FloatState) void {
+ context_ops.capture_float(state);
+}
+
+fn capture_debug_state(state: *DebugState) void {
+ context_ops.capture_debug(state);
+}
+
+fn capture_stack_snapshot(corpse: *Corpse, rsp: u64) void {
+ if (rsp == 0) {
+ corpse.stack_snapshot_size = 0;
+ return;
+ }
+
+ const stack_ptr: [*]const u8 = @ptrFromInt(rsp);
+ const copy_size: usize = 4096;
+
+ for (0..copy_size) |i| {
+ corpse.stack_snapshot[i] = stack_ptr[i];
+ }
+ corpse.stack_snapshot_size = copy_size;
+}
+
+fn capture_memory_snapshot(corpse: *Corpse, address: u64) void {
+ const page_start = address & ~@as(u64, 0xFFF);
+ const offset = address - page_start;
+
+ const start = if (offset >= 2048) address - 2048 else page_start;
+ const copy_size: usize = 4096;
+
+ const mem_ptr: [*]const u8 = @ptrFromInt(start);
+ for (0..copy_size) |i| {
+ corpse.memory_snapshot[i] = mem_ptr[i];
+ }
+ corpse.memory_snapshot_address = start;
+ corpse.memory_snapshot_size = copy_size;
+}
diff --git a/mirai/crimson/corpse/inspect.zig b/mirai/crimson/corpse/inspect.zig
new file mode 100644
index 0000000..c2bd456
--- /dev/null
+++ b/mirai/crimson/corpse/inspect.zig
@@ -0,0 +1,59 @@
+//! Inspect Corpse
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const context_ops = @import("../context/context.zig");
+
+const Corpse = types.Corpse;
+const Context = types.Context;
+
+pub fn inspect(corpse: *const Corpse) void {
+ if (!corpse.is_valid()) {
+ serial.printf("Invalid corpse\n", .{});
+ return;
+ }
+
+ serial.printf("Corpse for Kata %d, Thread %d\n", .{ corpse.kata_id, corpse.thread_id });
+ serial.printf("Exception: %s (code=%x, subcode=%x)\n", .{
+ corpse.exception_type.name(),
+ corpse.exception_code,
+ corpse.exception_subcode,
+ });
+
+ if (corpse.fault_address != 0) {
+ serial.printf("Fault address: %x\n", .{corpse.fault_address});
+ }
+
+ serial.printf("\n", .{});
+ context_ops.dump_context(&corpse.context);
+}
+
+pub fn get_context(corpse: *const Corpse) *const Context {
+ return &corpse.context;
+}
+
+pub fn get_stack_snapshot(corpse: *const Corpse) []const u8 {
+ if (corpse.stack_snapshot_size == 0) {
+ return &[_]u8{};
+ }
+ return corpse.stack_snapshot[0..corpse.stack_snapshot_size];
+}
+
+pub fn get_memory_snapshot(corpse: *const Corpse) []const u8 {
+ if (corpse.memory_snapshot_size == 0) {
+ return &[_]u8{};
+ }
+ return corpse.memory_snapshot[0..corpse.memory_snapshot_size];
+}
+
+pub fn get_memory_snapshot_address(corpse: *const Corpse) u64 {
+ return corpse.memory_snapshot_address;
+}
+
+pub fn get_fault_address(corpse: *const Corpse) u64 {
+ return corpse.fault_address;
+}
+
+pub fn get_timestamp(corpse: *const Corpse) u64 {
+ return corpse.timestamp;
+}
diff --git a/mirai/crimson/corpse/release.zig b/mirai/crimson/corpse/release.zig
new file mode 100644
index 0000000..337578a
--- /dev/null
+++ b/mirai/crimson/corpse/release.zig
@@ -0,0 +1,56 @@
+//! Release Corpse Resources
+
+const types = @import("../types/types.zig");
+
+const Corpse = types.Corpse;
+
+pub const max_corpses = 16;
+
+var corpse_pool: [max_corpses]Corpse = init_pool();
+var corpse_in_use: [max_corpses]bool = [_]bool{false} ** max_corpses;
+
+fn init_pool() [max_corpses]Corpse {
+ var pool: [max_corpses]Corpse = undefined;
+ for (&pool) |*c| {
+ c.clear();
+ }
+ return pool;
+}
+
+pub fn allocate() ?*Corpse {
+ for (&corpse_pool, 0..) |*corpse, i| {
+ if (!corpse_in_use[i]) {
+ corpse_in_use[i] = true;
+ corpse.clear();
+ return corpse;
+ }
+ }
+ return null;
+}
+
+pub fn release(corpse: *Corpse) void {
+ for (&corpse_pool, 0..) |*pool_corpse, i| {
+ if (pool_corpse == corpse) {
+ corpse_in_use[i] = false;
+ corpse.clear();
+ return;
+ }
+ }
+}
+
+pub fn release_all_for_kata(kata_id: u64) void {
+ for (&corpse_pool, 0..) |*corpse, i| {
+ if (corpse_in_use[i] and corpse.kata_id == kata_id) {
+ corpse_in_use[i] = false;
+ corpse.clear();
+ }
+ }
+}
+
+pub fn get_active_count() usize {
+ var count: usize = 0;
+ for (corpse_in_use) |in_use| {
+ if (in_use) count += 1;
+ }
+ return count;
+}
diff --git a/mirai/crimson/crimson.zig b/mirai/crimson/crimson.zig
new file mode 100644
index 0000000..1d4b42e
--- /dev/null
+++ b/mirai/crimson/crimson.zig
@@ -0,0 +1,42 @@
+//! Crimson - Akiba Exception Handling System
+
+pub const constants = @import("constants/constants.zig");
+pub const types = @import("types/types.zig");
+pub const context = @import("context/context.zig");
+pub const classify = @import("classify/classify.zig");
+pub const handlers = @import("handlers/handlers.zig");
+pub const ports = @import("ports/ports.zig");
+pub const raise = @import("raise/raise.zig");
+pub const propagate = @import("propagate/propagate.zig");
+pub const receive = @import("receive/receive.zig");
+pub const corpse = @import("corpse/corpse.zig");
+pub const panic = @import("panic/panic.zig");
+pub const render = @import("render/render.zig");
+pub const recover = @import("recover/recover.zig");
+pub const state = @import("state.zig");
+
+pub const ExceptionType = constants.ExceptionType;
+pub const Behavior = constants.Behavior;
+pub const Action = constants.Action;
+pub const Flavor = constants.Flavor;
+
+pub const Exception = types.Exception;
+pub const Context = types.Context;
+pub const Frame = types.Frame;
+pub const Port = types.Port;
+pub const Corpse = types.Corpse;
+pub const Identity = types.Identity;
+
+pub const collapse = panic.collapse;
+pub const dispatch = handlers.dispatch;
+pub const triage = propagate.triage;
+
+pub fn initialize() void {
+ state.initialize();
+}
+
+pub fn handle_exception(vector: u8, frame: *types.Frame, regs: *types.Context) Action {
+ var exception = handlers.create_exception(vector, frame, regs);
+ state.record_exception(exception.exception_type, exception.address);
+ return propagate.triage(&exception);
+}
diff --git a/mirai/crimson/handlers/breach.zig b/mirai/crimson/handlers/breach.zig
new file mode 100644
index 0000000..128bd09
--- /dev/null
+++ b/mirai/crimson/handlers/breach.zig
@@ -0,0 +1,21 @@
+//! Breach Handler (Page Fault, Segment Fault)
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const classify = @import("../classify/classify.zig");
+const Exception = types.Exception;
+const Action = constants.Action;
+const PageFaultError = classify.PageFaultError;
+
+pub fn handle(exception: *Exception) Action {
+ if (exception.vector == 14) {
+ const err = PageFaultError.from_error_code(exception.code);
+ if (exception.context.is_kernel_mode()) {
+ serial.printf("Kernel page fault at %x: %s\n", .{ exception.address, err.description() });
+ return .collapse;
+ }
+ return .@"resume";
+ }
+ return if (exception.context.is_kernel_mode()) .collapse else .terminate;
+}
diff --git a/mirai/crimson/handlers/collapse.zig b/mirai/crimson/handlers/collapse.zig
new file mode 100644
index 0000000..0ea6d7a
--- /dev/null
+++ b/mirai/crimson/handlers/collapse.zig
@@ -0,0 +1,12 @@
+//! Collapse Handler (Double Fault, Machine Check)
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const Exception = types.Exception;
+const Action = constants.Action;
+
+pub fn handle(exception: *Exception) Action {
+ serial.printf("FATAL: Unrecoverable exception (vector %d) at %x\n", .{ exception.vector, exception.context.rip });
+ return .collapse;
+}
diff --git a/mirai/crimson/handlers/entry.zig b/mirai/crimson/handlers/entry.zig
new file mode 100644
index 0000000..a7995e0
--- /dev/null
+++ b/mirai/crimson/handlers/entry.zig
@@ -0,0 +1,44 @@
+//! Common Handler Entry
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const classify = @import("../classify/classify.zig");
+const context_ops = @import("../context/context.zig");
+
+const Exception = types.Exception;
+const Context = types.Context;
+const Frame = types.Frame;
+const ExceptionType = constants.ExceptionType;
+const Action = constants.Action;
+
+var exception_context: Context = undefined;
+
+pub fn create_exception(vector: u8, frame: *Frame, regs: *Context) Exception {
+ context_ops.capture_from_frame(regs, frame);
+ const exception_type = classify.classify_vector(vector);
+ return Exception{
+ .exception_type = exception_type,
+ .code = frame.error_code,
+ .subcode = 0,
+ .vector = vector,
+ .address = regs.cr2,
+ .context = regs,
+ .frame = frame,
+ .kata_id = 0,
+ .thread_id = 0,
+ .recoverable = exception_type.is_recoverable(),
+ };
+}
+
+pub fn get_exception_context() *Context {
+ return &exception_context;
+}
+
+pub fn default_action(exception_type: ExceptionType) Action {
+ return switch (exception_type) {
+ .breach => .@"resume",
+ .shatter => .debug,
+ .critical, .collapse => .collapse,
+ else => .terminate,
+ };
+}
diff --git a/mirai/crimson/handlers/forbidden.zig b/mirai/crimson/handlers/forbidden.zig
new file mode 100644
index 0000000..36f102d
--- /dev/null
+++ b/mirai/crimson/handlers/forbidden.zig
@@ -0,0 +1,15 @@
+//! Forbidden Handler (Invalid Opcode, GPF)
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const Exception = types.Exception;
+const Action = constants.Action;
+
+pub fn handle(exception: *Exception) Action {
+ if (exception.context.is_kernel_mode()) {
+ serial.printf("Kernel forbidden exception at %x (vector %d, error %x)\n", .{ exception.context.rip, exception.vector, exception.code });
+ return .collapse;
+ }
+ return .terminate;
+}
diff --git a/mirai/crimson/handlers/handlers.zig b/mirai/crimson/handlers/handlers.zig
new file mode 100644
index 0000000..3c45c49
--- /dev/null
+++ b/mirai/crimson/handlers/handlers.zig
@@ -0,0 +1,32 @@
+//! Exception Handlers
+
+const constants = @import("../constants/constants.zig");
+const types = @import("../types/types.zig");
+pub const entry = @import("entry.zig");
+pub const breach = @import("breach.zig");
+pub const forbidden = @import("forbidden.zig");
+pub const overflow = @import("overflow.zig");
+pub const shatter = @import("shatter.zig");
+pub const missing = @import("missing.zig");
+pub const collapse = @import("collapse.zig");
+
+const Exception = types.Exception;
+const ExceptionType = constants.ExceptionType;
+const Action = constants.Action;
+
+pub const create_exception = entry.create_exception;
+pub const get_exception_context = entry.get_exception_context;
+pub const default_action = entry.default_action;
+
+pub fn dispatch(exception: *Exception) Action {
+ return switch (exception.exception_type) {
+ .breach => breach.handle(exception),
+ .forbidden => forbidden.handle(exception),
+ .overflow => overflow.handle(exception),
+ .shatter => shatter.handle(exception),
+ .missing => missing.handle(exception),
+ .collapse => collapse.handle(exception),
+ .critical => .collapse,
+ else => .terminate,
+ };
+}
diff --git a/mirai/crimson/handlers/missing.zig b/mirai/crimson/handlers/missing.zig
new file mode 100644
index 0000000..9a6bc9b
--- /dev/null
+++ b/mirai/crimson/handlers/missing.zig
@@ -0,0 +1,13 @@
+//! Missing Handler (Device Not Available)
+
+const asm_cpu = @import("../../asm/cpu/cpu.zig");
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const Exception = types.Exception;
+const Action = constants.Action;
+
+pub fn handle(exception: *Exception) Action {
+ _ = exception;
+ asm_cpu.clear_task_switched();
+ return .@"resume";
+}
diff --git a/mirai/crimson/handlers/overflow.zig b/mirai/crimson/handlers/overflow.zig
new file mode 100644
index 0000000..5e98faa
--- /dev/null
+++ b/mirai/crimson/handlers/overflow.zig
@@ -0,0 +1,15 @@
+//! Overflow Handler (Arithmetic Exceptions)
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const Exception = types.Exception;
+const Action = constants.Action;
+
+pub fn handle(exception: *Exception) Action {
+ if (exception.context.is_kernel_mode()) {
+ serial.printf("Kernel arithmetic exception at %x\n", .{exception.context.rip});
+ return .collapse;
+ }
+ return .terminate;
+}
diff --git a/mirai/crimson/handlers/shatter.zig b/mirai/crimson/handlers/shatter.zig
new file mode 100644
index 0000000..e6ff1f8
--- /dev/null
+++ b/mirai/crimson/handlers/shatter.zig
@@ -0,0 +1,11 @@
+//! Shatter Handler (Debug, Breakpoint)
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const Exception = types.Exception;
+const Action = constants.Action;
+
+pub fn handle(exception: *Exception) Action {
+ _ = exception;
+ return .debug;
+}
diff --git a/mirai/crimson/panic/collapse.zig b/mirai/crimson/panic/collapse.zig
new file mode 100644
index 0000000..fd2a0c6
--- /dev/null
+++ b/mirai/crimson/panic/collapse.zig
@@ -0,0 +1,76 @@
+//! Trigger Collapse (Panic)
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const render = @import("../render/render.zig");
+const gather = @import("gather.zig");
+const halt_module = @import("halt.zig");
+
+const Exception = types.Exception;
+const Context = types.Context;
+
+var collapse_in_progress: bool = false;
+var collapse_message: [256]u8 = undefined;
+var collapse_message_len: usize = 0;
+
+pub fn collapse(message: []const u8, exception: ?*const Exception) noreturn {
+ if (collapse_in_progress) {
+ serial.printf("\nDouble collapse detected, halting immediately\n", .{});
+ halt_module.halt_all();
+ }
+
+ collapse_in_progress = true;
+
+ set_message(message);
+
+ render.render_collapse_banner();
+ render.render_message(get_message());
+
+ if (exception) |exc| {
+ render.render_exception(exc);
+ render.render_context(exc.context);
+ } else {
+ var context: Context = undefined;
+ gather.capture_current_context(&context);
+ render.render_context(&context);
+ }
+
+ render.render_halt_message();
+
+ halt_module.halt_all();
+}
+
+pub fn collapse_with_context(message: []const u8, context: *const Context) noreturn {
+ if (collapse_in_progress) {
+ serial.printf("\nDouble collapse detected, halting immediately\n", .{});
+ halt_module.halt_all();
+ }
+
+ collapse_in_progress = true;
+
+ set_message(message);
+
+ render.render_collapse_banner();
+ render.render_message(get_message());
+ render.render_context(context);
+ render.render_halt_message();
+
+ halt_module.halt_all();
+}
+
+fn set_message(message: []const u8) void {
+ const len = @min(message.len, 255);
+ for (message[0..len], 0..) |c, i| {
+ collapse_message[i] = c;
+ }
+ collapse_message[len] = 0;
+ collapse_message_len = len;
+}
+
+fn get_message() []const u8 {
+ return collapse_message[0..collapse_message_len];
+}
+
+pub fn is_collapsing() bool {
+ return collapse_in_progress;
+}
diff --git a/mirai/crimson/panic/gather.zig b/mirai/crimson/panic/gather.zig
new file mode 100644
index 0000000..dfdc658
--- /dev/null
+++ b/mirai/crimson/panic/gather.zig
@@ -0,0 +1,39 @@
+//! Gather System State
+
+const asm_cpu = @import("../../asm/cpu/cpu.zig");
+const types = @import("../types/types.zig");
+const context_ops = @import("../context/context.zig");
+
+const Context = types.Context;
+const FloatState = types.FloatState;
+const DebugState = types.DebugState;
+
+pub fn capture_current_context(context: *Context) void {
+ context.clear();
+
+ context.cr0 = asm_cpu.read_cr0();
+ context.cr2 = asm_cpu.read_cr2();
+ context.cr3 = asm_cpu.read_cr3();
+ context.cr4 = asm_cpu.read_cr4();
+
+ context.rflags = asm_cpu.read_flags();
+ context.rsp = asm_cpu.read_rsp();
+
+ context_ops.capture_segments(context);
+}
+
+pub fn capture_float_state(state: *FloatState) void {
+ context_ops.capture_float(state);
+}
+
+pub fn capture_debug_state(state: *DebugState) void {
+ context_ops.capture_debug(state);
+}
+
+pub fn get_current_cpu() u32 {
+ return 0;
+}
+
+pub fn get_uptime_ticks() u64 {
+ return asm_cpu.rdtsc();
+}
diff --git a/mirai/crimson/panic/halt.zig b/mirai/crimson/panic/halt.zig
new file mode 100644
index 0000000..55d7966
--- /dev/null
+++ b/mirai/crimson/panic/halt.zig
@@ -0,0 +1,21 @@
+//! Halt All CPUs
+
+const asm_cpu = @import("../../asm/cpu/cpu.zig");
+
+pub fn halt_all() noreturn {
+ asm_cpu.disable_interrupts();
+ asm_cpu.halt_loop();
+}
+
+pub fn halt_current() noreturn {
+ asm_cpu.disable_interrupts();
+ asm_cpu.halt_loop();
+}
+
+pub fn send_halt_ipi() void {
+ // TODO: Send IPI to all other cores to halt them
+}
+
+pub fn wait_for_other_cpus() void {
+ // TODO: Wait for all other CPUs to acknowledge halt
+}
diff --git a/mirai/crimson/panic/panic.zig b/mirai/crimson/panic/panic.zig
new file mode 100644
index 0000000..ba16280
--- /dev/null
+++ b/mirai/crimson/panic/panic.zig
@@ -0,0 +1,18 @@
+//! Panic Operations
+
+pub const collapse_module = @import("collapse.zig");
+pub const gather = @import("gather.zig");
+pub const halt = @import("halt.zig");
+
+pub const collapse = collapse_module.collapse;
+pub const collapse_with_context = collapse_module.collapse_with_context;
+pub const is_collapsing = collapse_module.is_collapsing;
+
+pub const capture_current_context = gather.capture_current_context;
+pub const capture_float_state = gather.capture_float_state;
+pub const capture_debug_state = gather.capture_debug_state;
+pub const get_current_cpu = gather.get_current_cpu;
+pub const get_uptime_ticks = gather.get_uptime_ticks;
+
+pub const halt_all = halt.halt_all;
+pub const halt_current = halt.halt_current;
diff --git a/mirai/crimson/ports/array.zig b/mirai/crimson/ports/array.zig
new file mode 100644
index 0000000..6157fc8
--- /dev/null
+++ b/mirai/crimson/ports/array.zig
@@ -0,0 +1,18 @@
+//! Port Array (Per Exception Type)
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const Port = types.Port;
+const ExceptionType = constants.ExceptionType;
+
+pub const exception_type_count = 10;
+
+pub const PortArray = struct {
+ ports: [exception_type_count]Port,
+ pub fn init() PortArray { var a = PortArray{ .ports = undefined }; for (&a.ports) |*p| p.clear(); return a; }
+ pub fn get(self: *PortArray, t: ExceptionType) *Port { return &self.ports[@intFromEnum(t)]; }
+ pub fn get_const(self: *const PortArray, t: ExceptionType) *const Port { return &self.ports[@intFromEnum(t)]; }
+ pub fn set(self: *PortArray, t: ExceptionType, port: Port) void { self.ports[@intFromEnum(t)] = port; }
+ pub fn clear_all(self: *PortArray) void { for (&self.ports) |*p| p.clear(); }
+ pub fn has_port(self: *const PortArray, t: ExceptionType) bool { return self.get_const(t).is_valid(); }
+};
diff --git a/mirai/crimson/ports/host.zig b/mirai/crimson/ports/host.zig
new file mode 100644
index 0000000..fef797b
--- /dev/null
+++ b/mirai/crimson/ports/host.zig
@@ -0,0 +1,42 @@
+//! Host Exception Port
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const array_module = @import("array.zig");
+
+const Port = types.Port;
+const PortOwner = types.PortOwner;
+const PortArray = array_module.PortArray;
+const ExceptionType = constants.ExceptionType;
+const Behavior = constants.Behavior;
+const Flavor = constants.Flavor;
+
+var host_ports: PortArray = PortArray.init();
+
+pub fn get_port(exception_type: ExceptionType) *const Port {
+ return host_ports.get_const(exception_type);
+}
+
+pub fn set_port(exception_type: ExceptionType, port_id: u64, behavior: Behavior, flavor: Flavor) void {
+ const port = Port{
+ .port_id = port_id,
+ .behavior = behavior,
+ .flavor = flavor,
+ .owner = .host,
+ .owner_id = 0,
+ .active = true,
+ };
+ host_ports.set(exception_type, port);
+}
+
+pub fn clear_port(exception_type: ExceptionType) void {
+ host_ports.get(exception_type).clear();
+}
+
+pub fn has_port(exception_type: ExceptionType) bool {
+ return host_ports.has_port(exception_type);
+}
+
+pub fn clear_all() void {
+ host_ports.clear_all();
+}
diff --git a/mirai/crimson/ports/kata.zig b/mirai/crimson/ports/kata.zig
new file mode 100644
index 0000000..d9dc455
--- /dev/null
+++ b/mirai/crimson/ports/kata.zig
@@ -0,0 +1,79 @@
+//! Kata Exception Ports
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const array_module = @import("array.zig");
+
+const Port = types.Port;
+const PortOwner = types.PortOwner;
+const PortArray = array_module.PortArray;
+const ExceptionType = constants.ExceptionType;
+const Behavior = constants.Behavior;
+const Flavor = constants.Flavor;
+
+pub const max_katas = 256;
+
+var kata_ports: [max_katas]PortArray = init_all();
+
+fn init_all() [max_katas]PortArray {
+ var arrays: [max_katas]PortArray = undefined;
+ for (&arrays) |*a| {
+ a.* = PortArray.init();
+ }
+ return arrays;
+}
+
+pub fn get_port(kata_id: u64, exception_type: ExceptionType) *const Port {
+ if (kata_id >= max_katas) {
+ return &empty_port;
+ }
+ return kata_ports[kata_id].get_const(exception_type);
+}
+
+pub fn set_port(kata_id: u64, exception_type: ExceptionType, port_id: u64, behavior: Behavior, flavor: Flavor) bool {
+ if (kata_id >= max_katas) {
+ return false;
+ }
+ const port = Port{
+ .port_id = port_id,
+ .behavior = behavior,
+ .flavor = flavor,
+ .owner = .kata,
+ .owner_id = kata_id,
+ .active = true,
+ };
+ kata_ports[kata_id].set(exception_type, port);
+ return true;
+}
+
+pub fn clear_port(kata_id: u64, exception_type: ExceptionType) bool {
+ if (kata_id >= max_katas) {
+ return false;
+ }
+ kata_ports[kata_id].get(exception_type).clear();
+ return true;
+}
+
+pub fn has_port(kata_id: u64, exception_type: ExceptionType) bool {
+ if (kata_id >= max_katas) {
+ return false;
+ }
+ return kata_ports[kata_id].has_port(exception_type);
+}
+
+pub fn clear_all_for_kata(kata_id: u64) bool {
+ if (kata_id >= max_katas) {
+ return false;
+ }
+ kata_ports[kata_id].clear_all();
+ return true;
+}
+
+var empty_port: Port = Port{
+ .port_id = 0,
+ .behavior = .default,
+ .flavor = .none,
+ .owner = .none,
+ .owner_id = 0,
+ .active = false,
+};
diff --git a/mirai/crimson/ports/lookup.zig b/mirai/crimson/ports/lookup.zig
new file mode 100644
index 0000000..a6ff69a
--- /dev/null
+++ b/mirai/crimson/ports/lookup.zig
@@ -0,0 +1,54 @@
+//! Port Lookup (Thread → Kata → Host Chain)
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const thread = @import("thread.zig");
+const kata = @import("kata.zig");
+const host = @import("host.zig");
+
+const Port = types.Port;
+const Exception = types.Exception;
+const ExceptionType = constants.ExceptionType;
+
+pub const LookupResult = struct {
+ port: *const Port,
+ found: bool,
+};
+
+pub fn find_port(exception: *const Exception) LookupResult {
+ return find_port_for(exception.thread_id, exception.kata_id, exception.exception_type);
+}
+
+pub fn find_port_for(thread_id: u64, kata_id: u64, exception_type: ExceptionType) LookupResult {
+ if (thread.has_port(thread_id, exception_type)) {
+ return LookupResult{
+ .port = thread.get_port(thread_id, exception_type),
+ .found = true,
+ };
+ }
+
+ if (kata.has_port(kata_id, exception_type)) {
+ return LookupResult{
+ .port = kata.get_port(kata_id, exception_type),
+ .found = true,
+ };
+ }
+
+ if (host.has_port(exception_type)) {
+ return LookupResult{
+ .port = host.get_port(exception_type),
+ .found = true,
+ };
+ }
+
+ return LookupResult{
+ .port = undefined,
+ .found = false,
+ };
+}
+
+pub fn has_any_port(thread_id: u64, kata_id: u64, exception_type: ExceptionType) bool {
+ return thread.has_port(thread_id, exception_type) or
+ kata.has_port(kata_id, exception_type) or
+ host.has_port(exception_type);
+}
diff --git a/mirai/crimson/ports/masks.zig b/mirai/crimson/ports/masks.zig
new file mode 100644
index 0000000..fb7453f
--- /dev/null
+++ b/mirai/crimson/ports/masks.zig
@@ -0,0 +1,42 @@
+//! Exception Masks
+
+const constants = @import("../constants/constants.zig");
+
+const ExceptionType = constants.ExceptionType;
+
+pub const Mask = u16;
+
+pub const mask_none: Mask = 0;
+pub const mask_breach: Mask = 1 << @intFromEnum(ExceptionType.breach);
+pub const mask_forbidden: Mask = 1 << @intFromEnum(ExceptionType.forbidden);
+pub const mask_overflow: Mask = 1 << @intFromEnum(ExceptionType.overflow);
+pub const mask_shatter: Mask = 1 << @intFromEnum(ExceptionType.shatter);
+pub const mask_missing: Mask = 1 << @intFromEnum(ExceptionType.missing);
+pub const mask_critical: Mask = 1 << @intFromEnum(ExceptionType.critical);
+pub const mask_software: Mask = 1 << @intFromEnum(ExceptionType.software);
+pub const mask_resource: Mask = 1 << @intFromEnum(ExceptionType.resource);
+pub const mask_guard: Mask = 1 << @intFromEnum(ExceptionType.guard);
+pub const mask_collapse: Mask = 1 << @intFromEnum(ExceptionType.collapse);
+
+pub const mask_all: Mask = 0x3FF;
+pub const mask_recoverable: Mask = mask_breach | mask_forbidden | mask_overflow | mask_shatter | mask_missing | mask_software | mask_resource | mask_guard;
+pub const mask_fatal: Mask = mask_critical | mask_collapse;
+
+pub fn includes(mask: Mask, exception_type: ExceptionType) bool {
+ const bit: Mask = 1 << @intFromEnum(exception_type);
+ return (mask & bit) != 0;
+}
+
+pub fn add(mask: Mask, exception_type: ExceptionType) Mask {
+ const bit: Mask = 1 << @intFromEnum(exception_type);
+ return mask | bit;
+}
+
+pub fn remove(mask: Mask, exception_type: ExceptionType) Mask {
+ const bit: Mask = 1 << @intFromEnum(exception_type);
+ return mask & ~bit;
+}
+
+pub fn from_type(exception_type: ExceptionType) Mask {
+ return @as(Mask, 1) << @intFromEnum(exception_type);
+}
diff --git a/mirai/crimson/ports/port.zig b/mirai/crimson/ports/port.zig
new file mode 100644
index 0000000..79d9844
--- /dev/null
+++ b/mirai/crimson/ports/port.zig
@@ -0,0 +1,17 @@
+//! Single Port Operations
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const Port = types.Port;
+const PortOwner = types.PortOwner;
+const Behavior = constants.Behavior;
+const Flavor = constants.Flavor;
+
+pub fn create(port_id: u64, owner: PortOwner, owner_id: u64) Port {
+ return Port{ .port_id = port_id, .behavior = .default, .flavor = .general, .owner = owner, .owner_id = owner_id, .active = true };
+}
+
+pub fn set_behavior(port: *Port, behavior: Behavior) void { port.behavior = behavior; }
+pub fn set_flavor(port: *Port, flavor: Flavor) void { port.flavor = flavor; }
+pub fn activate(port: *Port) void { port.active = true; }
+pub fn deactivate(port: *Port) void { port.active = false; }
diff --git a/mirai/crimson/ports/ports.zig b/mirai/crimson/ports/ports.zig
new file mode 100644
index 0000000..c145491
--- /dev/null
+++ b/mirai/crimson/ports/ports.zig
@@ -0,0 +1,22 @@
+//! Exception Ports
+
+pub const port = @import("port.zig");
+pub const array = @import("array.zig");
+pub const masks = @import("masks.zig");
+pub const host = @import("host.zig");
+pub const kata = @import("kata.zig");
+pub const thread = @import("thread.zig");
+pub const lookup = @import("lookup.zig");
+
+pub const PortArray = array.PortArray;
+pub const Mask = masks.Mask;
+pub const LookupResult = lookup.LookupResult;
+
+pub const find_port = lookup.find_port;
+pub const find_port_for = lookup.find_port_for;
+pub const has_any_port = lookup.has_any_port;
+
+pub const mask_none = masks.mask_none;
+pub const mask_all = masks.mask_all;
+pub const mask_recoverable = masks.mask_recoverable;
+pub const mask_fatal = masks.mask_fatal;
diff --git a/mirai/crimson/ports/thread.zig b/mirai/crimson/ports/thread.zig
new file mode 100644
index 0000000..3b3c6d1
--- /dev/null
+++ b/mirai/crimson/ports/thread.zig
@@ -0,0 +1,79 @@
+//! Thread Exception Ports
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const array_module = @import("array.zig");
+
+const Port = types.Port;
+const PortOwner = types.PortOwner;
+const PortArray = array_module.PortArray;
+const ExceptionType = constants.ExceptionType;
+const Behavior = constants.Behavior;
+const Flavor = constants.Flavor;
+
+pub const max_threads = 1024;
+
+var thread_ports: [max_threads]PortArray = init_all();
+
+fn init_all() [max_threads]PortArray {
+ var arrays: [max_threads]PortArray = undefined;
+ for (&arrays) |*a| {
+ a.* = PortArray.init();
+ }
+ return arrays;
+}
+
+pub fn get_port(thread_id: u64, exception_type: ExceptionType) *const Port {
+ if (thread_id >= max_threads) {
+ return &empty_port;
+ }
+ return thread_ports[thread_id].get_const(exception_type);
+}
+
+pub fn set_port(thread_id: u64, exception_type: ExceptionType, port_id: u64, behavior: Behavior, flavor: Flavor) bool {
+ if (thread_id >= max_threads) {
+ return false;
+ }
+ const port = Port{
+ .port_id = port_id,
+ .behavior = behavior,
+ .flavor = flavor,
+ .owner = .thread,
+ .owner_id = thread_id,
+ .active = true,
+ };
+ thread_ports[thread_id].set(exception_type, port);
+ return true;
+}
+
+pub fn clear_port(thread_id: u64, exception_type: ExceptionType) bool {
+ if (thread_id >= max_threads) {
+ return false;
+ }
+ thread_ports[thread_id].get(exception_type).clear();
+ return true;
+}
+
+pub fn has_port(thread_id: u64, exception_type: ExceptionType) bool {
+ if (thread_id >= max_threads) {
+ return false;
+ }
+ return thread_ports[thread_id].has_port(exception_type);
+}
+
+pub fn clear_all_for_thread(thread_id: u64) bool {
+ if (thread_id >= max_threads) {
+ return false;
+ }
+ thread_ports[thread_id].clear_all();
+ return true;
+}
+
+var empty_port: Port = Port{
+ .port_id = 0,
+ .behavior = .default,
+ .flavor = .none,
+ .owner = .none,
+ .owner_id = 0,
+ .active = false,
+};
diff --git a/mirai/crimson/propagate/chain.zig b/mirai/crimson/propagate/chain.zig
new file mode 100644
index 0000000..5f8f526
--- /dev/null
+++ b/mirai/crimson/propagate/chain.zig
@@ -0,0 +1,64 @@
+//! Exception Chain (Thread → Kata → Host)
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const handlers = @import("../handlers/handlers.zig");
+const ports = @import("../ports/ports.zig");
+const deliver = @import("deliver.zig");
+const wait = @import("wait.zig");
+
+const Exception = types.Exception;
+const Port = types.Port;
+const Action = constants.Action;
+const ExceptionType = constants.ExceptionType;
+
+pub fn propagate_through_chain(exception: *Exception) Action {
+ if (try_thread_port(exception)) |action| {
+ return action;
+ }
+
+ if (try_kata_port(exception)) |action| {
+ return action;
+ }
+
+ if (try_host_port(exception)) |action| {
+ return action;
+ }
+
+ return handlers.default_action(exception.exception_type);
+}
+
+fn try_thread_port(exception: *Exception) ?Action {
+ if (!ports.thread.has_port(exception.thread_id, exception.exception_type)) {
+ return null;
+ }
+
+ const port = ports.thread.get_port(exception.thread_id, exception.exception_type);
+ return deliver_and_wait(exception, port);
+}
+
+fn try_kata_port(exception: *Exception) ?Action {
+ if (!ports.kata.has_port(exception.kata_id, exception.exception_type)) {
+ return null;
+ }
+
+ const port = ports.kata.get_port(exception.kata_id, exception.exception_type);
+ return deliver_and_wait(exception, port);
+}
+
+fn try_host_port(exception: *Exception) ?Action {
+ if (!ports.host.has_port(exception.exception_type)) {
+ return null;
+ }
+
+ const port = ports.host.get_port(exception.exception_type);
+ return deliver_and_wait(exception, port);
+}
+
+fn deliver_and_wait(exception: *Exception, port: *const Port) Action {
+ if (!deliver.send_exception(exception, port)) {
+ return handlers.default_action(exception.exception_type);
+ }
+
+ return wait.wait_for_reply(exception, port);
+}
diff --git a/mirai/crimson/propagate/deliver.zig b/mirai/crimson/propagate/deliver.zig
new file mode 100644
index 0000000..7cf4d43
--- /dev/null
+++ b/mirai/crimson/propagate/deliver.zig
@@ -0,0 +1,58 @@
+//! Exception Delivery
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const context_ops = @import("../context/context.zig");
+
+const Exception = types.Exception;
+const Port = types.Port;
+const Context = types.Context;
+const FloatState = types.FloatState;
+const Identity = types.Identity;
+const Behavior = constants.Behavior;
+const Flavor = constants.Flavor;
+
+pub const ExceptionMessage = struct {
+ exception_type: u8,
+ code: u64,
+ subcode: u64,
+ thread_id: u64,
+ kata_id: u64,
+ context: ?*Context,
+ identity: ?*Identity,
+};
+
+pub fn send_exception(exception: *Exception, port: *const Port) bool {
+ if (!port.is_valid()) {
+ return false;
+ }
+
+ var message = build_message(exception, port.behavior, port.flavor);
+ return send_to_port(port.port_id, &message);
+}
+
+fn build_message(exception: *Exception, behavior: Behavior, flavor: Flavor) ExceptionMessage {
+ var message = ExceptionMessage{
+ .exception_type = @intFromEnum(exception.exception_type),
+ .code = exception.code,
+ .subcode = exception.subcode,
+ .thread_id = exception.thread_id,
+ .kata_id = exception.kata_id,
+ .context = null,
+ .identity = null,
+ };
+
+ if (behavior.includes_state()) {
+ if (flavor.includes_general()) {
+ message.context = exception.context;
+ }
+ }
+
+ return message;
+}
+
+fn send_to_port(port_id: u64, message: *const ExceptionMessage) bool {
+ _ = port_id;
+ _ = message;
+ return true;
+}
diff --git a/mirai/crimson/propagate/propagate.zig b/mirai/crimson/propagate/propagate.zig
new file mode 100644
index 0000000..a38c161
--- /dev/null
+++ b/mirai/crimson/propagate/propagate.zig
@@ -0,0 +1,15 @@
+//! Exception Propagation
+
+pub const triage_module = @import("triage.zig");
+pub const chain = @import("chain.zig");
+pub const deliver = @import("deliver.zig");
+pub const wait = @import("wait.zig");
+
+pub const ExceptionMessage = deliver.ExceptionMessage;
+pub const Reply = wait.Reply;
+
+pub const triage = triage_module.triage;
+pub const propagate_through_chain = chain.propagate_through_chain;
+pub const send_exception = deliver.send_exception;
+pub const wait_for_reply = wait.wait_for_reply;
+pub const wait_with_timeout = wait.wait_with_timeout;
diff --git a/mirai/crimson/propagate/triage.zig b/mirai/crimson/propagate/triage.zig
new file mode 100644
index 0000000..dc0d3b4
--- /dev/null
+++ b/mirai/crimson/propagate/triage.zig
@@ -0,0 +1,35 @@
+//! Exception Triage
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const handlers = @import("../handlers/handlers.zig");
+const ports = @import("../ports/ports.zig");
+const chain = @import("chain.zig");
+const deliver = @import("deliver.zig");
+
+const Exception = types.Exception;
+const Action = constants.Action;
+
+pub fn triage(exception: *Exception) Action {
+ const handler_action = handlers.dispatch(exception);
+
+ if (handler_action == .collapse) {
+ return .collapse;
+ }
+
+ if (handler_action == .@"resume") {
+ return .@"resume";
+ }
+
+ const lookup_result = ports.find_port(exception);
+ if (!lookup_result.found) {
+ return handlers.default_action(exception.exception_type);
+ }
+
+ const port = lookup_result.port;
+ if (!port.is_valid()) {
+ return handlers.default_action(exception.exception_type);
+ }
+
+ return chain.propagate_through_chain(exception);
+}
diff --git a/mirai/crimson/propagate/wait.zig b/mirai/crimson/propagate/wait.zig
new file mode 100644
index 0000000..6370e20
--- /dev/null
+++ b/mirai/crimson/propagate/wait.zig
@@ -0,0 +1,48 @@
+//! Wait for Exception Reply
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const handlers = @import("../handlers/handlers.zig");
+
+const Exception = types.Exception;
+const Port = types.Port;
+const Action = constants.Action;
+
+pub const Reply = struct {
+ action: Action,
+ new_state: bool,
+ valid: bool,
+};
+
+pub fn wait_for_reply(exception: *Exception, port: *const Port) Action {
+ _ = port;
+
+ const reply = receive_reply();
+
+ if (!reply.valid) {
+ return handlers.default_action(exception.exception_type);
+ }
+
+ if (reply.new_state) {
+ apply_new_state(exception);
+ }
+
+ return reply.action;
+}
+
+fn receive_reply() Reply {
+ return Reply{
+ .action = .terminate,
+ .new_state = false,
+ .valid = true,
+ };
+}
+
+fn apply_new_state(exception: *Exception) void {
+ _ = exception;
+}
+
+pub fn wait_with_timeout(exception: *Exception, port: *const Port, timeout_ms: u64) Action {
+ _ = timeout_ms;
+ return wait_for_reply(exception, port);
+}
diff --git a/mirai/crimson/raise/guard.zig b/mirai/crimson/raise/guard.zig
new file mode 100644
index 0000000..be0955b
--- /dev/null
+++ b/mirai/crimson/raise/guard.zig
@@ -0,0 +1,45 @@
+//! Raise Guard Exception
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const handlers = @import("../handlers/handlers.zig");
+const propagate = @import("../propagate/propagate.zig");
+
+const Exception = types.Exception;
+const ExceptionType = constants.ExceptionType;
+const GuardCode = constants.GuardCode;
+const Action = constants.Action;
+
+pub fn raise_port_guard(kata_id: u64, thread_id: u64, port_id: u64, operation: u64) Action {
+ return raise_guard(.port_guard, kata_id, thread_id, port_id, operation);
+}
+
+pub fn raise_file_guard(kata_id: u64, thread_id: u64, file_id: u64, operation: u64) Action {
+ return raise_guard(.file_guard, kata_id, thread_id, file_id, operation);
+}
+
+pub fn raise_memory_guard(kata_id: u64, thread_id: u64, address: u64, operation: u64) Action {
+ return raise_guard(.memory_guard, kata_id, thread_id, address, operation);
+}
+
+fn raise_guard(guard_code: GuardCode, kata_id: u64, thread_id: u64, code: u64, subcode: u64) Action {
+ var context = handlers.get_exception_context();
+ context.clear();
+
+ var exception = Exception{
+ .exception_type = .guard,
+ .code = code,
+ .subcode = subcode,
+ .vector = 0,
+ .address = code,
+ .context = context,
+ .frame = undefined,
+ .kata_id = kata_id,
+ .thread_id = thread_id,
+ .recoverable = true,
+ };
+
+ _ = guard_code;
+
+ return propagate.triage(&exception);
+}
diff --git a/mirai/crimson/raise/hardware.zig b/mirai/crimson/raise/hardware.zig
new file mode 100644
index 0000000..50e4b7c
--- /dev/null
+++ b/mirai/crimson/raise/hardware.zig
@@ -0,0 +1,33 @@
+//! Raise Hardware Exception
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const handlers = @import("../handlers/handlers.zig");
+
+const Exception = types.Exception;
+const Context = types.Context;
+const Frame = types.Frame;
+const Action = constants.Action;
+
+pub fn raise_from_vector(vector: u8, frame: *Frame, context: *Context) Action {
+ var exception = handlers.create_exception(vector, frame, context);
+ return handlers.dispatch(&exception);
+}
+
+pub fn raise_from_interrupt(vector: u8, error_code: u64, rip: u64, rsp: u64) Action {
+ var context = handlers.get_exception_context();
+ context.rip = rip;
+ context.rsp = rsp;
+
+ var frame = Frame{
+ .error_code = error_code,
+ .rip = rip,
+ .cs = 0x08,
+ .rflags = 0,
+ .rsp = rsp,
+ .ss = 0x10,
+ };
+
+ var exception = handlers.create_exception(vector, &frame, context);
+ return handlers.dispatch(&exception);
+}
diff --git a/mirai/crimson/raise/raise.zig b/mirai/crimson/raise/raise.zig
new file mode 100644
index 0000000..6e45b70
--- /dev/null
+++ b/mirai/crimson/raise/raise.zig
@@ -0,0 +1,21 @@
+//! Exception Raise
+
+pub const hardware = @import("hardware.zig");
+pub const software = @import("software.zig");
+pub const resource = @import("resource.zig");
+pub const guard = @import("guard.zig");
+
+pub const raise_from_vector = hardware.raise_from_vector;
+pub const raise_from_interrupt = hardware.raise_from_interrupt;
+
+pub const raise_assertion = software.raise_assertion;
+pub const raise_abort = software.raise_abort;
+pub const raise_user_defined = software.raise_user_defined;
+
+pub const raise_memory_limit = resource.raise_memory_limit;
+pub const raise_cpu_limit = resource.raise_cpu_limit;
+pub const raise_file_limit = resource.raise_file_limit;
+
+pub const raise_port_guard = guard.raise_port_guard;
+pub const raise_file_guard = guard.raise_file_guard;
+pub const raise_memory_guard = guard.raise_memory_guard;
diff --git a/mirai/crimson/raise/resource.zig b/mirai/crimson/raise/resource.zig
new file mode 100644
index 0000000..6fadc81
--- /dev/null
+++ b/mirai/crimson/raise/resource.zig
@@ -0,0 +1,45 @@
+//! Raise Resource Exception
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const handlers = @import("../handlers/handlers.zig");
+const propagate = @import("../propagate/propagate.zig");
+
+const Exception = types.Exception;
+const ExceptionType = constants.ExceptionType;
+const ResourceCode = constants.ResourceCode;
+const Action = constants.Action;
+
+pub fn raise_memory_limit(kata_id: u64, thread_id: u64, requested: u64, limit: u64) Action {
+ return raise_resource(.memory_limit, kata_id, thread_id, requested, limit);
+}
+
+pub fn raise_cpu_limit(kata_id: u64, thread_id: u64, used: u64, limit: u64) Action {
+ return raise_resource(.cpu_limit, kata_id, thread_id, used, limit);
+}
+
+pub fn raise_file_limit(kata_id: u64, thread_id: u64, count: u64, limit: u64) Action {
+ return raise_resource(.file_limit, kata_id, thread_id, count, limit);
+}
+
+fn raise_resource(resource_code: ResourceCode, kata_id: u64, thread_id: u64, code: u64, subcode: u64) Action {
+ var context = handlers.get_exception_context();
+ context.clear();
+
+ var exception = Exception{
+ .exception_type = .resource,
+ .code = code,
+ .subcode = subcode,
+ .vector = 0,
+ .address = 0,
+ .context = context,
+ .frame = undefined,
+ .kata_id = kata_id,
+ .thread_id = thread_id,
+ .recoverable = true,
+ };
+
+ _ = resource_code;
+
+ return propagate.triage(&exception);
+}
diff --git a/mirai/crimson/raise/software.zig b/mirai/crimson/raise/software.zig
new file mode 100644
index 0000000..ff8e94a
--- /dev/null
+++ b/mirai/crimson/raise/software.zig
@@ -0,0 +1,46 @@
+//! Raise Software Exception
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const handlers = @import("../handlers/handlers.zig");
+const propagate = @import("../propagate/propagate.zig");
+
+const Exception = types.Exception;
+const Context = types.Context;
+const ExceptionType = constants.ExceptionType;
+const SoftwareCode = constants.SoftwareCode;
+const Action = constants.Action;
+
+pub fn raise_assertion(kata_id: u64, thread_id: u64, address: u64) Action {
+ return raise_software(.assertion, kata_id, thread_id, address, 0);
+}
+
+pub fn raise_abort(kata_id: u64, thread_id: u64) Action {
+ return raise_software(.abort, kata_id, thread_id, 0, 0);
+}
+
+pub fn raise_user_defined(kata_id: u64, thread_id: u64, code: u64, subcode: u64) Action {
+ return raise_software(.user_defined, kata_id, thread_id, code, subcode);
+}
+
+fn raise_software(software_code: SoftwareCode, kata_id: u64, thread_id: u64, code: u64, subcode: u64) Action {
+ var context = handlers.get_exception_context();
+ context.clear();
+
+ var exception = Exception{
+ .exception_type = .software,
+ .code = code,
+ .subcode = subcode,
+ .vector = 0,
+ .address = 0,
+ .context = context,
+ .frame = undefined,
+ .kata_id = kata_id,
+ .thread_id = thread_id,
+ .recoverable = true,
+ };
+
+ _ = software_code;
+
+ return propagate.triage(&exception);
+}
diff --git a/mirai/crimson/receive/actions.zig b/mirai/crimson/receive/actions.zig
new file mode 100644
index 0000000..c6a52e3
--- /dev/null
+++ b/mirai/crimson/receive/actions.zig
@@ -0,0 +1,49 @@
+//! Parse Reply Actions
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+
+const Context = types.Context;
+const Action = constants.Action;
+
+pub const ParsedAction = struct {
+ action: Action,
+ modify_state: bool,
+ new_context: ?*Context,
+ valid: bool,
+};
+
+pub fn parse_action_code(code: u64) ParsedAction {
+ const action_value: u8 = @truncate(code & 0xFF);
+ const flags: u8 = @truncate((code >> 8) & 0xFF);
+
+ const action: Action = switch (action_value) {
+ 0 => .@"resume",
+ 1 => .skip,
+ 2 => .terminate,
+ 3 => .terminate_corpse,
+ 4 => .collapse,
+ 5 => .debug,
+ else => return ParsedAction{
+ .action = .terminate,
+ .modify_state = false,
+ .new_context = null,
+ .valid = false,
+ },
+ };
+
+ return ParsedAction{
+ .action = action,
+ .modify_state = (flags & 1) != 0,
+ .new_context = null,
+ .valid = true,
+ };
+}
+
+pub fn encode_action(action: Action, modify_state: bool) u64 {
+ var code: u64 = @intFromEnum(action);
+ if (modify_state) {
+ code |= (1 << 8);
+ }
+ return code;
+}
diff --git a/mirai/crimson/receive/catch.zig b/mirai/crimson/receive/catch.zig
new file mode 100644
index 0000000..f786872
--- /dev/null
+++ b/mirai/crimson/receive/catch.zig
@@ -0,0 +1,60 @@
+//! Catch Exception (Receive Side)
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+const propagate = @import("../propagate/propagate.zig");
+
+const Context = types.Context;
+const Identity = types.Identity;
+const ExceptionType = constants.ExceptionType;
+const Behavior = constants.Behavior;
+
+pub const ReceivedExceptionDefault = struct {
+ port_id: u64,
+ thread_id: u64,
+ kata_id: u64,
+ exception_type: ExceptionType,
+ code: u64,
+ subcode: u64,
+};
+
+pub const ReceivedExceptionState = struct {
+ base: ReceivedExceptionDefault,
+ context: *Context,
+};
+
+pub const ReceivedExceptionStateIdentity = struct {
+ base: ReceivedExceptionDefault,
+ context: *Context,
+ identity: *Identity,
+ thread_port: u64,
+ kata_port: u64,
+};
+
+pub fn catch_exception_raise(port_id: u64, thread_id: u64, kata_id: u64, exception_type: ExceptionType, code: u64, subcode: u64) ReceivedExceptionDefault {
+ return ReceivedExceptionDefault{
+ .port_id = port_id,
+ .thread_id = thread_id,
+ .kata_id = kata_id,
+ .exception_type = exception_type,
+ .code = code,
+ .subcode = subcode,
+ };
+}
+
+pub fn catch_exception_raise_state(port_id: u64, thread_id: u64, kata_id: u64, exception_type: ExceptionType, code: u64, subcode: u64, context: *Context) ReceivedExceptionState {
+ return ReceivedExceptionState{
+ .base = catch_exception_raise(port_id, thread_id, kata_id, exception_type, code, subcode),
+ .context = context,
+ };
+}
+
+pub fn catch_exception_raise_state_identity(port_id: u64, thread_id: u64, kata_id: u64, exception_type: ExceptionType, code: u64, subcode: u64, context: *Context, identity: *Identity, thread_port: u64, kata_port: u64) ReceivedExceptionStateIdentity {
+ return ReceivedExceptionStateIdentity{
+ .base = catch_exception_raise(port_id, thread_id, kata_id, exception_type, code, subcode),
+ .context = context,
+ .identity = identity,
+ .thread_port = thread_port,
+ .kata_port = kata_port,
+ };
+}
diff --git a/mirai/crimson/receive/receive.zig b/mirai/crimson/receive/receive.zig
new file mode 100644
index 0000000..12e912e
--- /dev/null
+++ b/mirai/crimson/receive/receive.zig
@@ -0,0 +1,25 @@
+//! Exception Receive
+
+pub const catch_module = @import("catch.zig");
+pub const reply = @import("reply.zig");
+pub const actions = @import("actions.zig");
+
+pub const ReceivedExceptionDefault = catch_module.ReceivedExceptionDefault;
+pub const ReceivedExceptionState = catch_module.ReceivedExceptionState;
+pub const ReceivedExceptionStateIdentity = catch_module.ReceivedExceptionStateIdentity;
+pub const ExceptionReply = reply.ExceptionReply;
+pub const ParsedAction = actions.ParsedAction;
+
+pub const catch_exception_raise = catch_module.catch_exception_raise;
+pub const catch_exception_raise_state = catch_module.catch_exception_raise_state;
+pub const catch_exception_raise_state_identity = catch_module.catch_exception_raise_state_identity;
+
+pub const create_reply = reply.create_reply;
+pub const create_reply_with_state = reply.create_reply_with_state;
+pub const send_reply = reply.send_reply;
+pub const reply_resume = reply.reply_resume;
+pub const reply_terminate = reply.reply_terminate;
+pub const reply_terminate_corpse = reply.reply_terminate_corpse;
+
+pub const parse_action_code = actions.parse_action_code;
+pub const encode_action = actions.encode_action;
diff --git a/mirai/crimson/receive/reply.zig b/mirai/crimson/receive/reply.zig
new file mode 100644
index 0000000..9e7f14e
--- /dev/null
+++ b/mirai/crimson/receive/reply.zig
@@ -0,0 +1,49 @@
+//! Exception Reply
+
+const types = @import("../types/types.zig");
+const constants = @import("../constants/constants.zig");
+
+const Context = types.Context;
+const Action = constants.Action;
+
+pub const ExceptionReply = struct {
+ reply_port: u64,
+ action: Action,
+ new_context: ?*Context,
+};
+
+pub fn create_reply(reply_port: u64, action: Action) ExceptionReply {
+ return ExceptionReply{
+ .reply_port = reply_port,
+ .action = action,
+ .new_context = null,
+ };
+}
+
+pub fn create_reply_with_state(reply_port: u64, action: Action, context: *Context) ExceptionReply {
+ return ExceptionReply{
+ .reply_port = reply_port,
+ .action = action,
+ .new_context = context,
+ };
+}
+
+pub fn send_reply(reply: *const ExceptionReply) bool {
+ _ = reply;
+ return true;
+}
+
+pub fn reply_resume(reply_port: u64) bool {
+ const reply = create_reply(reply_port, .@"resume");
+ return send_reply(&reply);
+}
+
+pub fn reply_terminate(reply_port: u64) bool {
+ const reply = create_reply(reply_port, .terminate);
+ return send_reply(&reply);
+}
+
+pub fn reply_terminate_corpse(reply_port: u64) bool {
+ const reply = create_reply(reply_port, .terminate_corpse);
+ return send_reply(&reply);
+}
diff --git a/mirai/crimson/recover/recover.zig b/mirai/crimson/recover/recover.zig
new file mode 100644
index 0000000..310a5d2
--- /dev/null
+++ b/mirai/crimson/recover/recover.zig
@@ -0,0 +1,16 @@
+//! Recovery Operations
+
+pub const resume_mod = @import("resume.zig");
+pub const skip = @import("skip.zig");
+pub const terminate = @import("terminate.zig");
+
+pub const resume_execution = resume_mod.resume_execution;
+pub const resume_with_new_context = resume_mod.resume_with_new_context;
+pub const can_resume = resume_mod.can_resume;
+
+pub const skip_instruction = skip.skip_instruction;
+pub const can_skip = skip.can_skip;
+
+pub const terminate_kata = terminate.terminate;
+pub const terminate_with_corpse = terminate.terminate_with_corpse;
+pub const is_last_thread = terminate.is_last_thread;
diff --git a/mirai/crimson/recover/resume.zig b/mirai/crimson/recover/resume.zig
new file mode 100644
index 0000000..f66d242
--- /dev/null
+++ b/mirai/crimson/recover/resume.zig
@@ -0,0 +1,29 @@
+//! Resume Execution
+
+const types = @import("../types/types.zig");
+
+const Exception = types.Exception;
+const Context = types.Context;
+const Frame = types.Frame;
+
+pub fn resume_execution(exception: *Exception) void {
+ restore_context(exception.context);
+ restore_frame(exception.frame);
+}
+
+pub fn resume_with_new_context(exception: *Exception, new_context: *const Context) void {
+ exception.context.* = new_context.*;
+ resume_execution(exception);
+}
+
+fn restore_context(context: *Context) void {
+ _ = context;
+}
+
+fn restore_frame(frame: *Frame) void {
+ _ = frame;
+}
+
+pub fn can_resume(exception: *const Exception) bool {
+ return exception.recoverable;
+}
diff --git a/mirai/crimson/recover/skip.zig b/mirai/crimson/recover/skip.zig
new file mode 100644
index 0000000..2b3363c
--- /dev/null
+++ b/mirai/crimson/recover/skip.zig
@@ -0,0 +1,32 @@
+//! Skip Faulting Instruction
+
+const types = @import("../types/types.zig");
+
+const Exception = types.Exception;
+const Frame = types.Frame;
+
+pub fn skip_instruction(exception: *Exception) bool {
+ const instruction_length = get_instruction_length(exception.frame.rip);
+ if (instruction_length == 0) {
+ return false;
+ }
+
+ exception.frame.rip += instruction_length;
+ return true;
+}
+
+fn get_instruction_length(rip: u64) u64 {
+ const code_ptr: [*]const u8 = @ptrFromInt(rip);
+ const first_byte = code_ptr[0];
+
+ if (first_byte == 0xCC) return 1;
+ if (first_byte == 0xCD) return 2;
+ if (first_byte == 0xF4) return 1;
+ if (first_byte == 0x90) return 1;
+
+ return 1;
+}
+
+pub fn can_skip(exception: *const Exception) bool {
+ return exception.recoverable and exception.frame.rip != 0;
+}
diff --git a/mirai/crimson/recover/terminate.zig b/mirai/crimson/recover/terminate.zig
new file mode 100644
index 0000000..e1aa4bf
--- /dev/null
+++ b/mirai/crimson/recover/terminate.zig
@@ -0,0 +1,44 @@
+//! Terminate Kata
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const corpse_ops = @import("../corpse/corpse.zig");
+
+const Exception = types.Exception;
+const Corpse = types.Corpse;
+
+pub fn terminate(exception: *const Exception) void {
+ serial.printf("Terminating kata %d, thread %d due to unhandled exception\n", .{
+ exception.kata_id,
+ exception.thread_id,
+ });
+
+ cleanup_thread(exception.thread_id);
+ cleanup_kata_if_last(exception.kata_id);
+}
+
+pub fn terminate_with_corpse(exception: *const Exception) ?*Corpse {
+ serial.printf("Terminating kata %d with corpse generation\n", .{exception.kata_id});
+
+ const corpse = corpse_ops.allocate();
+ if (corpse) |c| {
+ c.* = corpse_ops.generate(exception);
+ }
+
+ terminate(exception);
+
+ return corpse;
+}
+
+fn cleanup_thread(thread_id: u64) void {
+ _ = thread_id;
+}
+
+fn cleanup_kata_if_last(kata_id: u64) void {
+ _ = kata_id;
+}
+
+pub fn is_last_thread(kata_id: u64) bool {
+ _ = kata_id;
+ return true;
+}
diff --git a/mirai/crimson/render/banner.zig b/mirai/crimson/render/banner.zig
new file mode 100644
index 0000000..802c804
--- /dev/null
+++ b/mirai/crimson/render/banner.zig
@@ -0,0 +1,23 @@
+//! Collapse Banner
+
+const serial = @import("../../drivers/serial/serial.zig");
+
+pub fn render() void {
+ serial.printf("\n", .{});
+ serial.printf("================================================================================\n", .{});
+ serial.printf(" AKIBA HAS COLLAPSED \n", .{});
+ serial.printf("================================================================================\n", .{});
+ serial.printf("\n", .{});
+}
+
+pub fn render_message(message: []const u8) void {
+ serial.printf("Reason: %s\n", .{message});
+ serial.printf("\n", .{});
+}
+
+pub fn render_halt() void {
+ serial.printf("\n", .{});
+ serial.printf("================================================================================\n", .{});
+ serial.printf("System halted. Please restart your computer.\n", .{});
+ serial.printf("================================================================================\n", .{});
+}
diff --git a/mirai/crimson/render/context.zig b/mirai/crimson/render/context.zig
new file mode 100644
index 0000000..944f2cc
--- /dev/null
+++ b/mirai/crimson/render/context.zig
@@ -0,0 +1,37 @@
+//! Render CPU Context
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+
+const Context = types.Context;
+
+pub fn render(context: *const Context) void {
+ serial.printf("CPU Context:\n", .{});
+ serial.printf(" RAX: %x RBX: %x\n", .{ context.rax, context.rbx });
+ serial.printf(" RCX: %x RDX: %x\n", .{ context.rcx, context.rdx });
+ serial.printf(" RSI: %x RDI: %x\n", .{ context.rsi, context.rdi });
+ serial.printf(" RBP: %x RSP: %x\n", .{ context.rbp, context.rsp });
+ serial.printf(" R8: %x R9: %x\n", .{ context.r8, context.r9 });
+ serial.printf(" R10: %x R11: %x\n", .{ context.r10, context.r11 });
+ serial.printf(" R12: %x R13: %x\n", .{ context.r12, context.r13 });
+ serial.printf(" R14: %x R15: %x\n", .{ context.r14, context.r15 });
+ serial.printf(" RIP: %x RFLAGS: %x\n", .{ context.rip, context.rflags });
+ serial.printf("\n", .{});
+
+ render_control_registers(context);
+ render_segment_registers(context);
+}
+
+fn render_control_registers(context: *const Context) void {
+ serial.printf("Control Registers:\n", .{});
+ serial.printf(" CR0: %x CR2: %x\n", .{ context.cr0, context.cr2 });
+ serial.printf(" CR3: %x CR4: %x\n", .{ context.cr3, context.cr4 });
+ serial.printf("\n", .{});
+}
+
+fn render_segment_registers(context: *const Context) void {
+ serial.printf("Segment Registers:\n", .{});
+ serial.printf(" CS: %x DS: %x ES: %x\n", .{ context.cs, context.ds, context.es });
+ serial.printf(" FS: %x GS: %x SS: %x\n", .{ context.fs, context.gs, context.ss });
+ serial.printf("\n", .{});
+}
diff --git a/mirai/crimson/render/exception.zig b/mirai/crimson/render/exception.zig
new file mode 100644
index 0000000..edc8dd3
--- /dev/null
+++ b/mirai/crimson/render/exception.zig
@@ -0,0 +1,61 @@
+//! Render Exception Info
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+const classify = @import("../classify/classify.zig");
+
+const Exception = types.Exception;
+const PageFaultError = classify.PageFaultError;
+
+pub fn render(exception: *const Exception) void {
+ serial.printf("Exception: %s (%s)\n", .{
+ exception.exception_type.name(),
+ classify.get_vector_name(exception.vector),
+ });
+
+ serial.printf(" Vector: %d\n", .{exception.vector});
+ serial.printf(" Code: %x\n", .{exception.code});
+ serial.printf(" Subcode: %x\n", .{exception.subcode});
+
+ if (exception.address != 0) {
+ serial.printf(" Fault Address: %x\n", .{exception.address});
+ }
+
+ if (exception.vector == 14) {
+ render_page_fault_details(exception.code);
+ }
+
+ serial.printf(" Location: %s mode\n", .{
+ if (exception.context.is_kernel_mode()) "kernel" else "user",
+ });
+
+ if (exception.kata_id != 0) {
+ serial.printf(" Kata: %d, Thread: %d\n", .{ exception.kata_id, exception.thread_id });
+ }
+
+ serial.printf("\n", .{});
+}
+
+fn render_page_fault_details(error_code: u64) void {
+ const pf_error = PageFaultError.from_error_code(error_code);
+
+ serial.printf(" Access: %s\n", .{pf_error.description()});
+
+ if (pf_error.user) {
+ serial.printf(" Mode: User\n", .{});
+ } else {
+ serial.printf(" Mode: Kernel\n", .{});
+ }
+}
+
+pub fn render_faulting_instruction(rip: u64) void {
+ serial.printf("Faulting Instruction:\n", .{});
+ serial.printf(" Address: %x\n", .{rip});
+
+ const code_ptr: [*]const u8 = @ptrFromInt(rip);
+ serial.printf(" Bytes: ", .{});
+ for (0..8) |i| {
+ serial.printf("%x ", .{code_ptr[i]});
+ }
+ serial.printf("\n\n", .{});
+}
diff --git a/mirai/crimson/render/memory.zig b/mirai/crimson/render/memory.zig
new file mode 100644
index 0000000..efef69c
--- /dev/null
+++ b/mirai/crimson/render/memory.zig
@@ -0,0 +1,56 @@
+//! Render Memory Around Fault
+
+const serial = @import("../../drivers/serial/serial.zig");
+
+pub fn render_around_address(address: u64, bytes_before: usize, bytes_after: usize) void {
+ if (address == 0) return;
+
+ const start = if (address >= bytes_before) address - bytes_before else 0;
+ const total_bytes = bytes_before + bytes_after;
+
+ serial.printf("Memory around %x:\n", .{address});
+
+ const mem_ptr: [*]const u8 = @ptrFromInt(start);
+
+ var offset: usize = 0;
+ while (offset < total_bytes) {
+ serial.printf(" %x: ", .{start + offset});
+
+ for (0..16) |i| {
+ if (offset + i < total_bytes) {
+ serial.printf("%x ", .{mem_ptr[offset + i]});
+ } else {
+ serial.printf(" ", .{});
+ }
+ }
+
+ serial.printf(" |", .{});
+ for (0..16) |i| {
+ if (offset + i < total_bytes) {
+ const c = mem_ptr[offset + i];
+ if (c >= 0x20 and c < 0x7F) {
+ serial.printf("%s", .{&[_]u8{c}});
+ } else {
+ serial.printf(".", .{});
+ }
+ }
+ }
+ serial.printf("|\n", .{});
+
+ offset += 16;
+ }
+
+ serial.printf("\n", .{});
+}
+
+pub fn render_instruction_bytes(rip: u64, count: usize) void {
+ serial.printf("Instruction bytes at %x:\n ", .{rip});
+
+ const code_ptr: [*]const u8 = @ptrFromInt(rip);
+
+ for (0..count) |i| {
+ serial.printf("%x ", .{code_ptr[i]});
+ }
+
+ serial.printf("\n\n", .{});
+}
diff --git a/mirai/crimson/render/modules.zig b/mirai/crimson/render/modules.zig
new file mode 100644
index 0000000..8520fb1
--- /dev/null
+++ b/mirai/crimson/render/modules.zig
@@ -0,0 +1,69 @@
+//! Render Loaded Modules
+
+const serial = @import("../../drivers/serial/serial.zig");
+
+pub const ModuleInfo = struct {
+ name: [64]u8,
+ name_len: usize,
+ base_address: u64,
+ size: u64,
+};
+
+pub const max_modules = 32;
+
+var loaded_modules: [max_modules]ModuleInfo = undefined;
+var module_count: usize = 0;
+
+pub fn register_module(name: []const u8, base_address: u64, size: u64) bool {
+ if (module_count >= max_modules) {
+ return false;
+ }
+
+ var module = &loaded_modules[module_count];
+ const len = @min(name.len, 63);
+ for (name[0..len], 0..) |c, i| {
+ module.name[i] = c;
+ }
+ module.name[len] = 0;
+ module.name_len = len;
+ module.base_address = base_address;
+ module.size = size;
+
+ module_count += 1;
+ return true;
+}
+
+pub fn render() void {
+ if (module_count == 0) {
+ serial.printf("Loaded Modules: (none registered)\n\n", .{});
+ return;
+ }
+
+ serial.printf("Loaded Modules:\n", .{});
+
+ for (0..module_count) |i| {
+ const module = &loaded_modules[i];
+ serial.printf(" %s: %x - %x (%d bytes)\n", .{
+ module.name[0..module.name_len],
+ module.base_address,
+ module.base_address + module.size,
+ module.size,
+ });
+ }
+
+ serial.printf("\n", .{});
+}
+
+pub fn find_module_for_address(address: u64) ?*const ModuleInfo {
+ for (0..module_count) |i| {
+ const module = &loaded_modules[i];
+ if (address >= module.base_address and address < module.base_address + module.size) {
+ return module;
+ }
+ }
+ return null;
+}
+
+pub fn clear_modules() void {
+ module_count = 0;
+}
diff --git a/mirai/crimson/render/render.zig b/mirai/crimson/render/render.zig
new file mode 100644
index 0000000..016bf42
--- /dev/null
+++ b/mirai/crimson/render/render.zig
@@ -0,0 +1,29 @@
+//! Render Operations
+
+pub const banner = @import("banner.zig");
+pub const exception = @import("exception.zig");
+pub const context = @import("context.zig");
+pub const stack = @import("stack.zig");
+pub const memory = @import("memory.zig");
+pub const modules = @import("modules.zig");
+
+pub const ModuleInfo = modules.ModuleInfo;
+
+pub const render_collapse_banner = banner.render;
+pub const render_message = banner.render_message;
+pub const render_halt_message = banner.render_halt;
+
+pub const render_exception = exception.render;
+pub const render_faulting_instruction = exception.render_faulting_instruction;
+
+pub const render_context = context.render;
+
+pub const render_stack_trace = stack.render;
+pub const render_raw_stack = stack.render_raw_stack;
+
+pub const render_memory = memory.render_around_address;
+pub const render_instruction_bytes = memory.render_instruction_bytes;
+
+pub const render_modules = modules.render;
+pub const register_module = modules.register_module;
+pub const find_module_for_address = modules.find_module_for_address;
diff --git a/mirai/crimson/render/stack.zig b/mirai/crimson/render/stack.zig
new file mode 100644
index 0000000..a00f0c7
--- /dev/null
+++ b/mirai/crimson/render/stack.zig
@@ -0,0 +1,47 @@
+//! Render Stack Trace
+
+const serial = @import("../../drivers/serial/serial.zig");
+const types = @import("../types/types.zig");
+
+const Context = types.Context;
+
+pub fn render(context: *const Context) void {
+ serial.printf("Stack Trace:\n", .{});
+
+ var rbp = context.rbp;
+ var depth: usize = 0;
+ const max_depth: usize = 20;
+
+ while (rbp != 0 and depth < max_depth) {
+ const frame_ptr: [*]const u64 = @ptrFromInt(rbp);
+
+ const return_address = frame_ptr[1];
+ if (return_address == 0) break;
+
+ serial.printf(" [%d] %x\n", .{ depth, return_address });
+
+ const next_rbp = frame_ptr[0];
+ if (next_rbp <= rbp) break;
+
+ rbp = next_rbp;
+ depth += 1;
+ }
+
+ if (depth == 0) {
+ serial.printf(" (no stack frames available)\n", .{});
+ }
+
+ serial.printf("\n", .{});
+}
+
+pub fn render_raw_stack(rsp: u64, count: usize) void {
+ serial.printf("Raw Stack (from %x):\n", .{rsp});
+
+ const stack_ptr: [*]const u64 = @ptrFromInt(rsp);
+
+ for (0..count) |i| {
+ serial.printf(" [%x]: %x\n", .{ rsp + i * 8, stack_ptr[i] });
+ }
+
+ serial.printf("\n", .{});
+}
diff --git a/mirai/crimson/state.zig b/mirai/crimson/state.zig
new file mode 100644
index 0000000..8de80d2
--- /dev/null
+++ b/mirai/crimson/state.zig
@@ -0,0 +1,45 @@
+//! Crimson Global State
+
+const types = @import("types/types.zig");
+const constants = @import("constants/constants.zig");
+
+const Context = types.Context;
+const ExceptionType = constants.ExceptionType;
+
+var initialized: bool = false;
+var exception_count: u64 = 0;
+var last_exception_type: ExceptionType = .collapse;
+var last_exception_address: u64 = 0;
+
+pub fn initialize() void {
+ exception_count = 0;
+ last_exception_type = .collapse;
+ last_exception_address = 0;
+ initialized = true;
+}
+
+pub fn is_initialized() bool {
+ return initialized;
+}
+
+pub fn record_exception(exception_type: ExceptionType, address: u64) void {
+ exception_count += 1;
+ last_exception_type = exception_type;
+ last_exception_address = address;
+}
+
+pub fn get_exception_count() u64 {
+ return exception_count;
+}
+
+pub fn get_last_exception_type() ExceptionType {
+ return last_exception_type;
+}
+
+pub fn get_last_exception_address() u64 {
+ return last_exception_address;
+}
+
+pub fn reset_statistics() void {
+ exception_count = 0;
+}
diff --git a/mirai/crimson/types/context.zig b/mirai/crimson/types/context.zig
new file mode 100644
index 0000000..710e25f
--- /dev/null
+++ b/mirai/crimson/types/context.zig
@@ -0,0 +1,20 @@
+//! CPU Context
+
+pub const Context = extern struct {
+ rax: u64 = 0, rbx: u64 = 0, rcx: u64 = 0, rdx: u64 = 0,
+ rsi: u64 = 0, rdi: u64 = 0, rbp: u64 = 0, rsp: u64 = 0,
+ r8: u64 = 0, r9: u64 = 0, r10: u64 = 0, r11: u64 = 0,
+ r12: u64 = 0, r13: u64 = 0, r14: u64 = 0, r15: u64 = 0,
+ rip: u64 = 0, rflags: u64 = 0,
+ cs: u16 = 0, ds: u16 = 0, es: u16 = 0, fs: u16 = 0, gs: u16 = 0, ss: u16 = 0,
+ padding: u32 = 0,
+ cr0: u64 = 0, cr2: u64 = 0, cr3: u64 = 0, cr4: u64 = 0,
+
+ pub fn clear(self: *Context) void {
+ self.* = Context{};
+ }
+
+ pub fn is_user_mode(self: *const Context) bool { return (self.cs & 0x3) == 3; }
+ pub fn is_kernel_mode(self: *const Context) bool { return (self.cs & 0x3) == 0; }
+ pub fn get_fault_address(self: *const Context) u64 { return self.cr2; }
+};
diff --git a/mirai/crimson/types/corpse.zig b/mirai/crimson/types/corpse.zig
new file mode 100644
index 0000000..4e3479c
--- /dev/null
+++ b/mirai/crimson/types/corpse.zig
@@ -0,0 +1,18 @@
+//! Corpse Structure
+
+const Context = @import("context.zig").Context;
+const FloatState = @import("flavor.zig").FloatState;
+const DebugState = @import("flavor.zig").DebugState;
+const Identity = @import("identity.zig").Identity;
+const constants = @import("../constants/constants.zig");
+const ExceptionType = constants.ExceptionType;
+
+pub const Corpse = struct {
+ kata_id: u64, thread_id: u64, exception_type: ExceptionType, exception_code: u64, exception_subcode: u64,
+ fault_address: u64, identity: Identity, context: Context, float_state: FloatState, debug_state: DebugState,
+ stack_snapshot: [4096]u8, stack_snapshot_size: u64, memory_snapshot: [4096]u8,
+ memory_snapshot_address: u64, memory_snapshot_size: u64, timestamp: u64, valid: bool,
+ pub fn clear(self: *Corpse) void { self.valid = false; self.stack_snapshot_size = 0; self.memory_snapshot_size = 0; }
+ pub fn is_valid(self: *const Corpse) bool { return self.valid; }
+ pub fn mark_valid(self: *Corpse) void { self.valid = true; }
+};
diff --git a/mirai/crimson/types/exception.zig b/mirai/crimson/types/exception.zig
new file mode 100644
index 0000000..47723e5
--- /dev/null
+++ b/mirai/crimson/types/exception.zig
@@ -0,0 +1,17 @@
+//! Exception Structure
+
+const constants = @import("../constants/constants.zig");
+const Context = @import("context.zig").Context;
+const Frame = @import("frame.zig").Frame;
+const ExceptionType = constants.ExceptionType;
+
+pub const Exception = struct {
+ exception_type: ExceptionType, code: u64, subcode: u64, vector: u8, address: u64,
+ context: *Context, frame: *Frame, kata_id: u64, thread_id: u64, recoverable: bool,
+
+ pub fn is_kernel(self: *const Exception) bool { return self.kata_id == 0; }
+ pub fn is_user(self: *const Exception) bool { return self.kata_id != 0; }
+ pub fn is_page_fault(self: *const Exception) bool { return self.vector == 14; }
+ pub fn is_fatal(self: *const Exception) bool { return !self.recoverable; }
+ pub fn get_type_name(self: *const Exception) []const u8 { return self.exception_type.name(); }
+};
diff --git a/mirai/crimson/types/flavor.zig b/mirai/crimson/types/flavor.zig
new file mode 100644
index 0000000..a321abc
--- /dev/null
+++ b/mirai/crimson/types/flavor.zig
@@ -0,0 +1,64 @@
+//! Flavor State Structures
+
+pub const FloatState = extern struct {
+ fcw: u16,
+ fsw: u16,
+ ftw: u8,
+ reserved1: u8,
+ fop: u16,
+ fip: u64,
+ fdp: u64,
+ mxcsr: u32,
+ mxcsr_mask: u32,
+ st: [8][16]u8,
+ xmm: [16][16]u8,
+ reserved2: [96]u8,
+
+ pub fn clear(self: *FloatState) void {
+ const bytes: *[512]u8 = @ptrCast(self);
+ for (bytes) |*b| {
+ b.* = 0;
+ }
+ }
+};
+
+pub const DebugState = extern struct {
+ dr0: u64,
+ dr1: u64,
+ dr2: u64,
+ dr3: u64,
+ dr4: u64,
+ dr5: u64,
+ dr6: u64,
+ dr7: u64,
+
+ pub fn clear(self: *DebugState) void {
+ self.* = DebugState{
+ .dr0 = 0,
+ .dr1 = 0,
+ .dr2 = 0,
+ .dr3 = 0,
+ .dr4 = 0,
+ .dr5 = 0,
+ .dr6 = 0,
+ .dr7 = 0,
+ };
+ }
+};
+
+pub const AvxState = extern struct {
+ ymm_high: [16][16]u8,
+ zmm: [32][64]u8,
+ opmask: [8]u64,
+
+ pub fn clear(self: *AvxState) void {
+ for (&self.ymm_high) |*r| {
+ for (r) |*b| {
+ b.* = 0;
+ }
+ }
+ for (&self.opmask) |*m| {
+ m.* = 0;
+ }
+ }
+};
diff --git a/mirai/crimson/types/frame.zig b/mirai/crimson/types/frame.zig
new file mode 100644
index 0000000..5960654
--- /dev/null
+++ b/mirai/crimson/types/frame.zig
@@ -0,0 +1,11 @@
+//! Interrupt Stack Frame
+
+pub const Frame = extern struct {
+ error_code: u64, rip: u64, cs: u64, rflags: u64, rsp: u64, ss: u64,
+ pub fn is_user_mode(self: *const Frame) bool { return (self.cs & 0x3) == 3; }
+ pub fn is_kernel_mode(self: *const Frame) bool { return (self.cs & 0x3) == 0; }
+};
+
+pub const FrameNoError = extern struct {
+ rip: u64, cs: u64, rflags: u64, rsp: u64, ss: u64,
+};
diff --git a/mirai/crimson/types/identity.zig b/mirai/crimson/types/identity.zig
new file mode 100644
index 0000000..197ca22
--- /dev/null
+++ b/mirai/crimson/types/identity.zig
@@ -0,0 +1,8 @@
+//! Exception Identity
+
+pub const Identity = struct {
+ thread_id: u64, kata_id: u64, thread_port: u64, kata_port: u64,
+ thread_name: [32]u8, kata_name: [32]u8,
+ pub fn clear(self: *Identity) void { self.* = Identity{ .thread_id = 0, .kata_id = 0, .thread_port = 0, .kata_port = 0, .thread_name = [_]u8{0} ** 32, .kata_name = [_]u8{0} ** 32 }; }
+ pub fn is_kernel(self: *const Identity) bool { return self.kata_id == 0; }
+};
diff --git a/mirai/crimson/types/port.zig b/mirai/crimson/types/port.zig
new file mode 100644
index 0000000..dd01851
--- /dev/null
+++ b/mirai/crimson/types/port.zig
@@ -0,0 +1,17 @@
+//! Exception Port
+
+const constants = @import("../constants/constants.zig");
+const Behavior = constants.Behavior;
+const Flavor = constants.Flavor;
+
+pub const PortOwner = enum(u8) { none = 0, thread = 1, kata = 2, host = 3 };
+
+pub const Port = struct {
+ port_id: u64, behavior: Behavior, flavor: Flavor, owner: PortOwner, owner_id: u64, active: bool,
+ pub fn is_valid(self: *const Port) bool { return self.port_id != 0 and self.active; }
+ pub fn clear(self: *Port) void { self.* = Port{ .port_id = 0, .behavior = .default, .flavor = .none, .owner = .none, .owner_id = 0, .active = false }; }
+};
+
+pub fn create_port(port_id: u64, owner: PortOwner, owner_id: u64) Port {
+ return Port{ .port_id = port_id, .behavior = .default, .flavor = .general, .owner = owner, .owner_id = owner_id, .active = true };
+}
diff --git a/mirai/crimson/types/types.zig b/mirai/crimson/types/types.zig
new file mode 100644
index 0000000..b0d7a2c
--- /dev/null
+++ b/mirai/crimson/types/types.zig
@@ -0,0 +1,22 @@
+//! Crimson Types
+
+pub const exception = @import("exception.zig");
+pub const context = @import("context.zig");
+pub const frame = @import("frame.zig");
+pub const port = @import("port.zig");
+pub const flavor = @import("flavor.zig");
+pub const identity = @import("identity.zig");
+pub const corpse = @import("corpse.zig");
+
+pub const Exception = exception.Exception;
+pub const Context = context.Context;
+pub const Frame = frame.Frame;
+pub const FrameNoError = frame.FrameNoError;
+pub const Port = port.Port;
+pub const PortOwner = port.PortOwner;
+pub const FloatState = flavor.FloatState;
+pub const DebugState = flavor.DebugState;
+pub const AvxState = flavor.AvxState;
+pub const Identity = identity.Identity;
+pub const Corpse = corpse.Corpse;
+pub const create_port = port.create_port;