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;
}