aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-07-20 18:43:34 +0200
committerHimbeer <himbeer@disroot.org>2024-07-20 18:43:34 +0200
commit40b8a20b0e522cd75f9bb7e54c326a6e9e92f23d (patch)
tree1300fc5e903c35cf2375ca312705da2743004e49
parent45c1a898d1147a387e0cd8c2dcf4691ebcba7c00 (diff)
resources: Add /process/create VFS hook
-rw-r--r--src/lib/resources.zig114
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,