aboutsummaryrefslogtreecommitdiff
path: root/mirai/invocations
diff options
context:
space:
mode:
Diffstat (limited to 'mirai/invocations')
-rw-r--r--mirai/invocations/handler.zig2
-rw-r--r--mirai/invocations/kata/reap.zig62
-rw-r--r--mirai/invocations/kata/spawn.zig102
-rw-r--r--mirai/invocations/kata/wait.zig3
-rw-r--r--mirai/invocations/kata/yield.zig22
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);
}