diff options
-rw-r--r-- | src/lib/syscall.zig | 19 | ||||
-rw-r--r-- | src/lib/vfs.zig | 79 |
2 files changed, 61 insertions, 37 deletions
diff --git a/src/lib/syscall.zig b/src/lib/syscall.zig index 419938f..ae86af1 100644 --- a/src/lib/syscall.zig +++ b/src/lib/syscall.zig @@ -60,17 +60,12 @@ fn open(proc: *process.Info, trap_frame: *trap.Frame) void { const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]); const data = trap_frame.general_purpose_registers[11]; - const user_info = vfs.openZ(path_c, proc.id, data) catch |err| { + const rd = vfs.openZ(proc, path_c, proc.id, data) catch |err| { sysexchange.frameReturn(usize, trap_frame, err); return; }; - switch (user_info) { - .rd => |resource_descriptor| { - const maybe_handle = proc.createRdHandle(resource_descriptor); - sysexchange.frameReturn(null, trap_frame, maybe_handle); - }, - .value => |value| sysexchange.frameReturnResult(usize, trap_frame, value), - } + const maybe_handle = proc.createRdHandle(rd); + sysexchange.frameReturn(null, trap_frame, maybe_handle); } // close(handle: usize) void @@ -191,7 +186,7 @@ fn remove(trap_frame: *const trap.Frame) void { } // read(handle: usize, buffer: [*]u8, len: usize) Result(usize) -fn read(proc: *const process.Info, trap_frame: *trap.Frame) void { +fn read(proc: *process.Info, trap_frame: *trap.Frame) void { setUserMemoryAccess(true); defer setUserMemoryAccess(false); @@ -203,11 +198,11 @@ fn read(proc: *const process.Info, trap_frame: *trap.Frame) void { sysexchange.frameReturn(usize, trap_frame, process.Error.BadRdHandle); return; }; - sysexchange.frameReturnResult(usize, trap_frame, rd.read(buffer[0..len])); + sysexchange.frameReturn(usize, trap_frame, rd.read(proc, buffer[0..len])); } // write(handle: usize, bytes: [*]const u8, len: usize) Result(usize) -fn write(proc: *const process.Info, trap_frame: *trap.Frame) void { +fn write(proc: *process.Info, trap_frame: *trap.Frame) void { setUserMemoryAccess(true); defer setUserMemoryAccess(false); @@ -219,7 +214,7 @@ fn write(proc: *const process.Info, trap_frame: *trap.Frame) void { sysexchange.frameReturn(usize, trap_frame, process.Error.BadRdHandle); return; }; - sysexchange.frameReturnResult(usize, trap_frame, rd.write(bytes[0..len])); + sysexchange.frameReturn(usize, trap_frame, rd.write(proc, bytes[0..len])); } // terminate() noreturn diff --git a/src/lib/vfs.zig b/src/lib/vfs.zig index ebd879f..22cba72 100644 --- a/src/lib/vfs.zig +++ b/src/lib/vfs.zig @@ -4,11 +4,12 @@ const std = @import("std"); +const process = @import("process.zig"); const sysexchange = @import("sysexchange.zig"); const mem = std.mem; -var root: Node = .{ .data = .{ .name = "", .resource = .{ .dir = undefined } } }; +var root: Node = .{ .data = .{ .name = "", .resource = .{ .dir = undefined }, .pid = 0 } }; pub const Error = error{ NotFound, @@ -77,6 +78,7 @@ pub const Inode = struct { name: []const u8, resource: Resource, refs: usize = 0, + pid: u16, }; pub const Node = std.DoublyLinkedList(Inode).Node; @@ -130,29 +132,33 @@ pub const ResourceDescriptor = struct { self.inode.refs -|= 1; } - pub fn read(self: ResourceDescriptor, buffer: []u8) sysexchange.Result(usize) { - const err_unsupported = sysexchange.Result(usize).fromAnyTypeOrError(Error.ReadNotSupported); - + pub fn read(self: ResourceDescriptor, proc: *process.Info, buffer: []u8) !noreturn { return switch (self.inode.resource) { - .stream => |stream| blk: { - const readFn = stream.readFn orelse return err_unsupported; - break :blk readFn(buffer); + .stream => |stream| { + const readFn = stream.readFn orelse return Error.ReadNotSupported; + proc.state = .suspended; + try call(self.inode.pid, readFn, .{buffer}, .{ + .hookFn = crossProcessReturn, + .context = proc, + }); }, - .hook => err_unsupported, - else => err_unsupported, + .hook => Error.ReadNotSupported, + else => Error.ReadNotSupported, }; } - pub fn write(self: ResourceDescriptor, bytes: []const u8) sysexchange.Result(usize) { - const err_unsupported = sysexchange.Result(usize).fromAnyTypeOrError(Error.WriteNotSupported); - + pub fn write(self: ResourceDescriptor, proc: *process.Info, bytes: []const u8) !noreturn { return switch (self.inode.resource) { - .stream => |stream| blk: { - const writeFn = stream.writeFn orelse return err_unsupported; - break :blk writeFn(bytes); + .stream => |stream| { + const writeFn = stream.writeFn orelse return Error.WriteNotSupported; + proc.state = .suspended; + try call(self.inode.pid, writeFn, .{bytes}, .{ + .hookFn = crossProcessReturn, + .context = proc, + }); }, - .hook => err_unsupported, - else => err_unsupported, + .hook => Error.WriteNotSupported, + else => Error.WriteNotSupported, }; } }; @@ -188,7 +194,7 @@ pub fn find(path: []const u8) ?*Node { return &root; } -pub fn provideResource(path: []const u8, resource: Resource) !void { +pub fn provideResource(path: []const u8, resource: Resource, pid: u16) !void { if (!std.fs.path.isAbsolutePosix(path)) return Error.RelativePathNotAllowed; const dirname = std.fs.path.dirnamePosix(path) orelse return Error.NoAbsoluteContainingDirectory; @@ -197,24 +203,47 @@ pub fn provideResource(path: []const u8, resource: Resource) !void { .dir => |*dir| dir.provideResource(.{ .name = std.fs.path.basenamePosix(path), .resource = resource, + .pid = pid, }), else => Error.NotADirectory, }; } else return Error.NotFound; } -pub fn provideResourceZ(path_c: [*:0]const u8, resource: Resource) !void { - return provideResource(mem.sliceTo(path_c, 0), resource); +pub fn provideResourceZ(path_c: [*:0]const u8, resource: Resource, pid: u16) !void { + return provideResource(mem.sliceTo(path_c, 0), resource, pid); } -pub fn open(path: []const u8, pid: u16, data: usize) !UserInfo { +pub fn open(proc: *process.Info, path: []const u8, pid: u16, data: usize) !ResourceDescriptor { const node = find(path) orelse return Error.NotFound; return switch (node.data.resource) { - .hook => |hook| .{ .value = hook.callback(pid, data) }, - else => .{ .rd = try ResourceDescriptor.init(&node.data) }, + .hook => |hook| { + proc.state = .suspended; + try call(node.data.pid, hook.callback, .{ pid, data }, .{ + .hookFn = crossProcessReturn, + .context = proc, + }); + }, + else => ResourceDescriptor.init(&node.data), }; } -pub fn openZ(path_c: [*:0]const u8, pid: u16, data: usize) !UserInfo { - return open(mem.sliceTo(path_c, 0), pid, data); +pub fn openZ(proc: *process.Info, path_c: [*:0]const u8, pid: u16, data: usize) !ResourceDescriptor { + return open(proc, mem.sliceTo(path_c, 0), pid, data); +} + +fn call(pid: u16, function: *const anyopaque, args: anytype, termHook: ?process.Info.TermHook) !noreturn { + const proc = process.latestThread(pid).?; + const callback_thread = try proc.createThread(null); + + callback_thread.call(@intFromPtr(function), args, termHook); +} + +fn crossProcessReturn(context: *anyopaque, driver: *const process.Info) void { + const proc: *process.Info = @alignCast(@ptrCast(context)); + proc.trap_frame.general_purpose_registers[10] = driver.trap_frame.general_purpose_registers[10]; + proc.trap_frame.general_purpose_registers[11] = driver.trap_frame.general_purpose_registers[11]; + proc.pc += 4; // Skip ecall instruction + proc.state = .waiting; + // Scheduler is called by the "terminate" syscall after two layers of returning. } |