diff options
-rw-r--r-- | src/lib/resources.zig | 114 |
1 files changed, 112 insertions, 2 deletions
diff --git a/src/lib/resources.zig b/src/lib/resources.zig index 92a28b6..769de4f 100644 --- a/src/lib/resources.zig +++ b/src/lib/resources.zig @@ -6,6 +6,7 @@ const std = @import("std"); const Console = @import("Console.zig"); const instructions = @import("instructions.zig"); +const mem = @import("mem.zig"); const paging = @import("paging.zig"); const process = @import("process.zig"); const syscall = @import("syscall.zig"); @@ -47,7 +48,7 @@ const iofs = struct { const processfs = struct { const self = struct { - fn terminate(pid: u16, thread_id: usize, _: usize) callconv(.C) sysexchange.Result(usize) { + fn terminate(pid: u16, thread_id: usize, _: usize) callconv(.C) Result(usize) { const proc = process.findThread(pid, thread_id).?; proc.terminate(); process.schedule() catch |err| { @@ -55,6 +56,100 @@ const processfs = struct { }; } }; + + const CreationContext = struct { + rd: vfs.ResourceDescriptor, + buffer: std.ArrayListAligned(u8, paging.page_size), + proc: *process.Info, + }; + + fn create(pid: u16, thread_id: usize, data: usize) callconv(.C) Result(usize) { + const result = doCreate(pid, thread_id, data); + return Result(usize).fromAnyTypeOrError(result); + } + + fn doCreate(pid: u16, thread_id: usize, data: usize) !usize { + const path_c: [*:0]const u8 = @ptrFromInt(data); + + const allocator = mem.page_allocator; + + const rd = try vfs.openNonHookZ(path_c); + defer rd.deinit(); + + if (rd.inode.resource.tag == .dir or rd.inode.resource.tag == .dir_hook) { + return vfs.Error.IsAContainer; + } + + const proc = process.findThread(pid, thread_id).?; + + var buffer = std.ArrayListAligned(u8, paging.page_size).init(allocator); + defer buffer.clearAndFree(); + + try buffer.ensureUnusedCapacity(4096); + + const ctx = try allocator.create(CreationContext); + defer allocator.destroy(ctx); + + ctx.* = .{ + .rd = rd, + .buffer = buffer, + .proc = proc, + }; + + defer proc.allowResume(); + while (try rd.readHooked(proc, ctx.buffer.items, .{ + .hookFn = loadExe, + .context = ctx, + }) > 0) {} + const new_proc = try process.create(allocator, ctx.buffer.items); + return new_proc.id; + } + + fn loadExe(context: *anyopaque, driver: *const process.Info) void { + const ctx: *CreationContext = @alignCast(@ptrCast(context)); + doLoadExe(ctx, driver) catch |err| { + sysexchange.frameReturn(usize, &ctx.proc.trap_frame, err); + }; + } + + fn doLoadExe(ctx: *CreationContext, driver: *const process.Info) !void { + const allocator = mem.page_allocator; + + defer ctx.proc.allowResume(); + + const result: Result(usize) = .{ + .value = driver.trap_frame.general_purpose_registers[12], + .status = @enumFromInt(driver.trap_frame.general_purpose_registers[13]), + }; + if (result.status != .success) { + defer allocator.destroy(ctx); + defer ctx.buffer.clearAndFree(); + defer ctx.rd.deinit(); + + sysexchange.frameReturnResult(usize, &ctx.proc.trap_frame, result); + return; + } + + const n = result.value; + if (n == 0) { + defer allocator.destroy(ctx); + defer ctx.buffer.clearAndFree(); + defer ctx.rd.deinit(); + + const new_proc = try process.create(allocator, ctx.buffer.items); + sysexchange.frameReturn(null, &ctx.proc.trap_frame, new_proc.id); + return; + } + + try ctx.buffer.ensureUnusedCapacity(4096); + + while (try ctx.rd.readHooked(ctx.proc, ctx.buffer.items[ctx.buffer.items.len..], .{ + .hookFn = loadExe, + .context = ctx, + }) > 0) {} + const new_proc = try process.create(allocator, ctx.buffer.items); + sysexchange.frameReturn(null, &ctx.proc.trap_frame, new_proc.id); + } }; pub const Error = error{ @@ -70,7 +165,7 @@ pub fn provideBuiltin() !void { try provideConsole(); try provideUserinit(); - try provideProcessSelf(); + try provideProcess(); } fn provideConsole() !void { @@ -110,6 +205,21 @@ fn provideUserinit() !void { } } +fn provideProcess() !void { + try vfs.provideResource("/process/create", .{ + .tag = .hook, + .data = .{ + .hook = .{ + .callback = processfs.create, + }, + }, + }, 0, .{ + .reclaimable = false, + }); + + try provideProcessSelf(); +} + fn provideProcessSelf() !void { try vfs.provideResource("/process/self/terminate", .{ .tag = .hook, |