ajhahn.de
← FlashOS
Zig 89 lines
// Stubs for fork host tests.
const std = @import("std");
const layout = @import("task_layout");
const TaskStruct = layout.TaskStruct;
const KeRegs = layout.KeRegs;

export var current: ?*TaskStruct = null;
export var task: [64]?*TaskStruct = [_]?*TaskStruct{null} ** 64;
export var nr_tasks: i32 = 0;
export var next_pid: i32 = 1;

var pool: [1024 * 1024]u8 align(4096) = [_]u8{0} ** (1024 * 1024);
var pool_idx: usize = 0;

export fn get_kernel_page() u64 {
    if (pool_idx + 4096 > pool.len) return 0;
    const addr = @intFromPtr(&pool[pool_idx]);
    pool_idx += 4096;
    @memset(@as([*]u8, @ptrFromInt(addr))[0..4096], 0);
    return addr;
}

export fn free_kernel_page(_: u64) void {}

// release_user_mm lives in sched.zig (not linked into the fork test
// target); the real page-freeing it does is covered by sched.zig's own
// host tests. Here it is inert — the fork tests assert the failure paths
// return -1 cleanly, not the freeing.
export fn release_user_mm(_: *TaskStruct) void {}

export fn allocate_user_page(_: *TaskStruct, _: u64, _: u64) u64 {
    return get_kernel_page();
}

// copy_virt_memory is fail-controllable so the copy_virt_memory-failure
// path in copy_process_impl can be exercised.
var fail_copy_virt: bool = false;
export fn set_fail_copy_virt(v: bool) void {
    fail_copy_virt = v;
}
export fn copy_virt_memory(_: *TaskStruct) i32 {
    return if (fail_copy_virt) -1 else 0;
}

export fn memzero(start: u64, size: u64) void {
    @memset(@as([*]u8, @ptrFromInt(start))[0..size], 0);
}

export fn memcpy(dst: *anyopaque, src: *const anyopaque, bytes: u64) *anyopaque {
    const d: [*]u8 = @ptrCast(dst);
    const s: [*]const u8 = @ptrCast(src);
    var i: usize = 0;
    while (i < bytes) : (i += 1) d[i] = s[i];
    return dst;
}

export fn copy_ke_regs(to: *KeRegs, from: *KeRegs) void {
    var i: usize = 0;
    while (i < 31) : (i += 1) to.regs[i] = from.regs[i];
    to.sp = from.sp;
    to.elr = from.elr;
    to.pstate = from.pstate;
}

export fn set_pgd(_: u64) void {}
export fn preempt_disable() void {}
export fn preempt_enable() void {}
export fn ret_from_fork() void {}
export fn main_output(_: i32, _: [*:0]const u8) void {}
export fn main_output_u64(_: i32, _: u64) void {}
export fn main_output_char(_: i32, _: u8) void {}

// Mock for pipe_mod and file_mod
pub const pipe_mod = struct {
    pub export fn dupAll(_: *TaskStruct, _: *TaskStruct) void {}
};
pub const file_mod = struct {
    pub export fn dupAll(_: *TaskStruct, _: *TaskStruct) void {}
};

export fn reset_fork_test() void {
    pool_idx = 0;
    @memset(&pool, 0);
    @memset(std.mem.asBytes(&task), 0);
    nr_tasks = 0;
    next_pid = 1;
    fail_copy_virt = false;
}