diff options
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; |
