diff options
Diffstat (limited to 'mirai/invocations')
| -rw-r--r-- | mirai/invocations/handler.zig | 2 | ||||
| -rw-r--r-- | mirai/invocations/kata/reap.zig | 62 | ||||
| -rw-r--r-- | mirai/invocations/kata/spawn.zig | 102 | ||||
| -rw-r--r-- | mirai/invocations/kata/wait.zig | 3 | ||||
| -rw-r--r-- | mirai/invocations/kata/yield.zig | 22 |
5 files changed, 190 insertions, 1 deletions
diff --git a/mirai/invocations/handler.zig b/mirai/invocations/handler.zig index 0855c72..bf3fa47 100644 --- a/mirai/invocations/handler.zig +++ b/mirai/invocations/handler.zig @@ -19,6 +19,7 @@ const viewstack = @import("fs/viewstack.zig"); const exit = @import("kata/exit.zig"); const postman = @import("kata/postman.zig"); +const reap = @import("kata/reap.zig"); const spawn = @import("kata/spawn.zig"); const wait = @import("kata/wait.zig"); const yield = @import("kata/yield.zig"); @@ -85,6 +86,7 @@ pub fn handle(ctx: *InvocationContext) void { invocations.UPTIME => uptime.invoke(ctx), invocations.GETTIME => gettime.invoke(ctx), invocations.DISKINFO => diskinfo.invoke(ctx), + invocations.REAP => reap.invoke(ctx), else => result.set_error(ctx), } } diff --git a/mirai/invocations/kata/reap.zig b/mirai/invocations/kata/reap.zig new file mode 100644 index 0000000..fd47794 --- /dev/null +++ b/mirai/invocations/kata/reap.zig @@ -0,0 +1,62 @@ +//! Reap invocation - Shinigami cleans up zombie katas + +const handler = @import("../handler.zig"); +const memory = @import("../../kata/memory.zig"); +const paging_const = @import("../../common/constants/paging.zig"); +const pool = @import("../../kata/pool.zig"); +const serial = @import("../../drivers/serial/serial.zig"); +const types = @import("../../kata/types.zig"); + +const HIGHER_HALF: u64 = 0xFFFF800000000000; + +fn check_ash_pd256() u64 { + for (&pool.pool, 0..) |*k, i| { + if (pool.used[i] and k.id == 3 and k.page_table != 0) { + const pml4: [*]volatile u64 = @ptrFromInt(k.page_table + HIGHER_HALF); + if ((pml4[0] & 1) == 0) return 0xDEAD0001; + const pdpt: [*]volatile u64 = @ptrFromInt((pml4[0] & paging_const.PTE_MASK) + HIGHER_HALF); + if ((pdpt[0] & 1) == 0) return 0xDEAD0002; + const pd: [*]volatile u64 = @ptrFromInt((pdpt[0] & paging_const.PTE_MASK) + HIGHER_HALF); + return pd[256]; + } + } + return 0xDEAD0000; +} + +/// Reap zombie katas - called by Shinigami +/// Returns the number of zombies reaped +pub fn invoke(ctx: *handler.InvocationContext) void { + var reaped: u64 = 0; + + for (&pool.pool, 0..) |*kata, i| { + if (!pool.used[i]) continue; + if (kata.state != .Zombie) continue; + + // Found a zombie - reap it + const kata_id = kata.id; + const pt = kata.page_table; + + const pd256_before = check_ash_pd256(); + serial.printf("Shinigami: reaping kata {d} pt={x} ash_pd256={x}\n", .{ kata_id, pt, pd256_before }); + + // Destroy the page table + if (kata.page_table != 0) { + memory.destroy_zombie_page_table(kata.page_table); + kata.page_table = 0; + } + + const pd256_after = check_ash_pd256(); + if (pd256_after != pd256_before) { + serial.printf("Shinigami: CORRUPTION during reap! pd256: {x} -> {x}\n", .{ pd256_before, pd256_after }); + } + + // Mark as dissolved and free the slot + kata.state = .Dissolved; + pool.used[i] = false; + + serial.printf("Shinigami: reaped kata {d}\n", .{kata_id}); + reaped += 1; + } + + ctx.rax = reaped; +} diff --git a/mirai/invocations/kata/spawn.zig b/mirai/invocations/kata/spawn.zig index 051810d..83ae61d 100644 --- a/mirai/invocations/kata/spawn.zig +++ b/mirai/invocations/kata/spawn.zig @@ -8,15 +8,86 @@ const handler = @import("../handler.zig"); const hikari = @import("../../hikari/loader.zig"); const kata_limits = @import("../../common/limits/kata.zig"); const memory_limits = @import("../../common/limits/memory.zig"); +const paging_const = @import("../../common/constants/paging.zig"); +const pmm = @import("../../memory/pmm.zig"); +const pool = @import("../../kata/pool.zig"); const result = @import("../../utils/types/result.zig"); +const serial = @import("../../drivers/serial/serial.zig"); const slice = @import("../../utils/mem/slice.zig"); +const HIGHER_HALF: u64 = 0xFFFF800000000000; + var afs_instance: ?*afs.AFS(ahci.BlockDevice) = null; pub fn set_afs_instance(fs: *afs.AFS(ahci.BlockDevice)) void { afs_instance = fs; } +fn check_ash_pd256() u64 { + for (&pool.pool, 0..) |*k, i| { + if (pool.used[i] and k.id == 3 and k.page_table != 0) { + const pml4: [*]volatile u64 = @ptrFromInt(k.page_table + HIGHER_HALF); + if ((pml4[0] & 1) == 0) return 0xDEAD0001; + const pdpt: [*]volatile u64 = @ptrFromInt((pml4[0] & paging_const.PTE_MASK) + HIGHER_HALF); + if ((pdpt[0] & 1) == 0) return 0xDEAD0002; + const pd: [*]volatile u64 = @ptrFromInt((pdpt[0] & paging_const.PTE_MASK) + HIGHER_HALF); + return pd[256]; + } + } + return 0xDEAD0000; +} + +fn verify_kernel_mapping(phys: u64) bool { + // Check if physical address is correctly mapped via higher half + const virt = phys + HIGHER_HALF; + + // Read from that address and write back - if mapping is wrong, we'd write to wrong place + const ptr: [*]volatile u64 = @ptrFromInt(virt); + const val = ptr[0]; + _ = val; + + // Check kernel's CR3 mapping of this address + const asm_memory = @import("../../asm/memory.zig"); + const kernel_cr3 = asm_memory.read_page_table_base() & ~@as(u64, 0xFFF); + + const pml4_idx = (virt >> 39) & 0x1FF; + const pdpt_idx = (virt >> 30) & 0x1FF; + const pd_idx = (virt >> 21) & 0x1FF; + const pt_idx = (virt >> 12) & 0x1FF; + + const pml4: [*]volatile u64 = @ptrFromInt(kernel_cr3 + HIGHER_HALF); + if ((pml4[pml4_idx] & 1) == 0) { + serial.printf("VERIFY: pml4[{d}] not present for phys {x}\n", .{ pml4_idx, phys }); + return false; + } + + const pdpt: [*]volatile u64 = @ptrFromInt((pml4[pml4_idx] & paging_const.PTE_MASK) + HIGHER_HALF); + if ((pdpt[pdpt_idx] & 1) == 0) { + serial.printf("VERIFY: pdpt[{d}] not present for phys {x}\n", .{ pdpt_idx, phys }); + return false; + } + + const pd: [*]volatile u64 = @ptrFromInt((pdpt[pdpt_idx] & paging_const.PTE_MASK) + HIGHER_HALF); + if ((pd[pd_idx] & 1) == 0) { + serial.printf("VERIFY: pd[{d}] not present for phys {x}\n", .{ pd_idx, phys }); + return false; + } + + const pt: [*]volatile u64 = @ptrFromInt((pd[pd_idx] & paging_const.PTE_MASK) + HIGHER_HALF); + if ((pt[pt_idx] & 1) == 0) { + serial.printf("VERIFY: pt[{d}] not present for phys {x}\n", .{ pt_idx, phys }); + return false; + } + + const mapped_phys = pt[pt_idx] & paging_const.PTE_MASK; + if (mapped_phys != phys) { + serial.printf("VERIFY: phys {x} maps to {x} instead!\n", .{ phys, mapped_phys }); + return false; + } + + return true; +} + pub fn invoke(ctx: *handler.InvocationContext) void { const fs = afs_instance orelse return result.set_error(ctx); @@ -53,9 +124,40 @@ pub fn invoke(ctx: *handler.InvocationContext) void { } } + const pd256_before = check_ash_pd256(); + + // Verify kernel can correctly access Ash's PD + if (pmm.ash_pd_phys != 0) { + if (!verify_kernel_mapping(pmm.ash_pd_phys)) { + serial.printf("spawn: Kernel mapping of Ash's PD is WRONG!\n", .{}); + } + } + const kata_id = hikari.load_with_args(fs, location, params[0..param_count]) catch { return result.set_error(ctx); }; + const pd256_after = check_ash_pd256(); + + // Track Ash's PD page (kata 3 is Ash) + if (kata_id == 3) { + if (pool.get(kata_id)) |kata| { + if (kata.page_table != 0) { + const pml4: [*]volatile u64 = @ptrFromInt(kata.page_table + HIGHER_HALF); + if ((pml4[0] & 1) != 0) { + const pdpt: [*]volatile u64 = @ptrFromInt((pml4[0] & paging_const.PTE_MASK) + HIGHER_HALF); + if ((pdpt[0] & 1) != 0) { + const pd_phys = pdpt[0] & paging_const.PTE_MASK; + pmm.set_ash_pd(pd_phys); + } + } + } + } + } else if (pd256_after != pd256_before and pd256_before != 0xDEAD0000) { + serial.printf("spawn: CORRUPTION during spawn of kata {d}! pd256: {x} -> {x}\n", .{ kata_id, pd256_before, pd256_after }); + } + + serial.printf("spawn: created kata {d}\n", .{kata_id}); + result.set_value(ctx, kata_id); } diff --git a/mirai/invocations/kata/wait.zig b/mirai/invocations/kata/wait.zig index e46b08b..e657e90 100644 --- a/mirai/invocations/kata/wait.zig +++ b/mirai/invocations/kata/wait.zig @@ -11,7 +11,8 @@ pub fn invoke(ctx: *handler.InvocationContext) void { const target = kata_mod.get_kata(target_id) orelse return result.set_error(ctx); - if (target.state == .Dissolved) { + // Zombie or Dissolved means the child has exited + if (target.state == .Zombie or target.state == .Dissolved) { return result.set_value(ctx, target.exit_code); } diff --git a/mirai/invocations/kata/yield.zig b/mirai/invocations/kata/yield.zig index bc4028a..0da91af 100644 --- a/mirai/invocations/kata/yield.zig +++ b/mirai/invocations/kata/yield.zig @@ -10,6 +10,28 @@ pub fn invoke(ctx: *handler.InvocationContext) void { kata.state = kata_mod.State.Alive; + // Save context before switching - schedule() may not return + kata.context.rax = 0; // Return value for yield + kata.context.rbx = ctx.rbx; + kata.context.rcx = ctx.rcx; + kata.context.rdx = ctx.rdx; + kata.context.rsi = ctx.rsi; + kata.context.rdi = ctx.rdi; + kata.context.rbp = ctx.rbp; + kata.context.rsp = ctx.rsp; + kata.context.r8 = ctx.r8; + kata.context.r9 = ctx.r9; + kata.context.r10 = ctx.r10; + kata.context.r11 = ctx.r11; + kata.context.r12 = ctx.r12; + kata.context.r13 = ctx.r13; + kata.context.r14 = ctx.r14; + kata.context.r15 = ctx.r15; + kata.context.rip = ctx.rip; + kata.context.rflags = ctx.rflags; + kata.context.cs = ctx.cs; + kata.context.ss = ctx.ss; + if (!sensei.is_in_queue(kata)) { sensei.enqueue_kata(kata); } |
