diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/syscall.zig | 13 | ||||
-rw-r--r-- | src/lib/vfs.zig | 108 |
2 files changed, 98 insertions, 23 deletions
diff --git a/src/lib/syscall.zig b/src/lib/syscall.zig index 4600a2d..a34ace4 100644 --- a/src/lib/syscall.zig +++ b/src/lib/syscall.zig @@ -32,6 +32,7 @@ pub fn handler(proc: *process.Info, trap_frame: *trap.Frame) !void { 100008 => remove(trap_frame), 100009 => read(proc, trap_frame), 100010 => write(proc, trap_frame), + 100011 => list(proc, trap_frame), else => return HandleError.UnknownSyscall, } } @@ -286,3 +287,15 @@ fn write(proc: *process.Info, trap_frame: *trap.Frame) void { }; sysexchange.frameReturn(usize, trap_frame, result); } + +// list(path_c: [*:0]const u8, entries: [*]vfs.DirEntry, len: usize) Result(usize) +fn list(proc: *process.Info, trap_frame: *trap.Frame) void { + // fixme: Kernel panic if null pointer + const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]); + // fixme: Kernel panic if null pointer + const entries: [*]vfs.DirEntry = @ptrFromInt(trap_frame.general_purpose_registers[11]); + const len = trap_frame.general_purpose_registers[12]; + + const result = vfs.listZ(proc, path_c, entries[0..len]); + sysexchange.frameReturn(null, trap_frame, result); +} diff --git a/src/lib/vfs.zig b/src/lib/vfs.zig index 1ce8ad7..ab07fcb 100644 --- a/src/lib/vfs.zig +++ b/src/lib/vfs.zig @@ -16,7 +16,8 @@ const TermHook = process.Info.TermHook; var root: Node = .{ .data = .{ - .name = "", + .name_ptr = "", + .name_len = 0, .inode = .{ .resource = .{ .tag = .dir, @@ -90,7 +91,7 @@ pub const DirHook = extern struct { pub const ProvideFn = *const fn (name_ptr: [*]const u8, name_len: usize, inode: Inode) callconv(.C) Result(void); pub const FindFn = *allowzero const fn (name_ptr: [*]const u8, name_len: usize) callconv(.C) ?*Inode; - pub const ListFn = *allowzero const fn (inodes_ptr: [*]Inode, inodes_len: usize) callconv(.C) Result(usize); + pub const ListFn = *allowzero const fn (entries_ptr: [*]DirEntry, entries_len: usize) callconv(.C) Result(usize); pub const RemoveFn = *const fn (name_ptr: [*]const u8, name_len: usize) callconv(.C) Result(void); }; @@ -134,9 +135,14 @@ pub const Flags = extern struct { detached: bool = false, }; -pub const DirEntry = struct { - name: []const u8, +pub const DirEntry = extern struct { + name_ptr: [*]const u8, + name_len: usize, inode: Inode, + + pub fn name(self: DirEntry) []const u8 { + return self.name_ptr[0..self.name_len]; + } }; pub const Node = std.DoublyLinkedList(DirEntry).Node; @@ -157,7 +163,7 @@ pub const Tree = struct { while (node) |current_node| { if (current_node.next == current_node) break; - if (std.mem.eql(u8, current_node.data.name, name)) return current_node; + if (std.mem.eql(u8, current_node.data.name(), name)) return current_node; node = current_node.next; } return null; @@ -325,19 +331,6 @@ pub const ResourceDescriptor = struct { proc.state = .suspended; try call(driver, writeFn, .{ self.context.?, copy.ptr, copy.len }, null, hook); } - - fn moveBack(driver: *const process.Info, buffer: []u8, copy: []const u8) void { - paging.setUserMemoryAccess(true); - defer paging.setUserMemoryAccess(false); - - @memcpy(buffer, copy); - - var addr = @intFromPtr(copy.ptr); - const limit = addr + copy.len; - while (addr < limit) : (addr += paging.page_size) { - driver.page_table.unmapEntry(addr); - } - } }; pub const UserInfo = union(enum) { @@ -391,13 +384,14 @@ fn reclaim(node: *Node, resource: Resource, pid: u16, options: Options) !void { } else return Error.AlreadyExists; } -fn provideInDir(dir: *Tree, basename: []const u8, resource: Resource, pid: u16, options: Options) !void { - if (dir.find(basename)) |node| { +fn provideInDir(dir: *Tree, name: []const u8, resource: Resource, pid: u16, options: Options) !void { + if (dir.find(name)) |node| { return reclaim(node, resource, pid, options); } return dir.provideResource(.{ - .name = basename, + .name_ptr = name.ptr, + .name_len = name.len, .inode = .{ .resource = resource, .pid = pid, @@ -407,12 +401,12 @@ fn provideInDir(dir: *Tree, basename: []const u8, resource: Resource, pid: u16, }); } -fn provideInDirHook(dir_hook: DirHook, basename: []const u8, resource: Resource, pid: u16, options: Options) !void { +fn provideInDirHook(dir_hook: DirHook, name: []const u8, resource: Resource, pid: u16, options: Options) !void { // fixme: Check for duplicate resources with the same path // fixme: Doesn't call into U-mode drivers correctly return if (dir_hook.provideFn) |provideFn| - provideFn(basename.ptr, basename.len, .{ + provideFn(name.ptr, name.len, .{ .resource = resource, .pid = pid, .options = options, @@ -479,11 +473,79 @@ pub fn openNonHookZ(path_c: [*:0]const u8) !ResourceDescriptor { return openNonHook(std.mem.sliceTo(path_c, 0)); } +fn listDir(dir: *Tree, entries: []DirEntry) !usize { + paging.setUserMemoryAccess(true); + defer paging.setUserMemoryAccess(false); + + var i: usize = 0; + var next_node = dir.nodes.first; + while (next_node) |node| : (next_node = node.next) { + if (i >= entries.len) break; + entries[i] = node.data; + i += 1; + } + + return @min(dir.nodes.len, entries.len); +} + +fn listDirHook(proc: *process.Info, dir_hook: DirHook, pid: u16, entries: []DirEntry) !usize { + return listDirHookHooked(proc, dir_hook, pid, entries, .{ + .hookFn = crossProcessReturn, + .context = proc, + }); +} + +fn listDirHookHooked(proc: *process.Info, dir_hook: DirHook, pid: u16, entries: []DirEntry, hook: TermHook) !usize { + if (pid == 0) { + return dir_hook.listFn(entries.ptr, entries.len).toErrorUnion(); + } + + const entries_ptr: [*]u8 = @ptrCast(entries.ptr); + const entries_bytes = entries_ptr[0 .. entries.len * @sizeOf(DirEntry)]; + + const driver = process.latestThread(pid).?; + paging.setUserMemoryAccess(true); + const copy = try driver.copyBuffer(entries_bytes); + paging.setUserMemoryAccess(false); + + proc.state = .suspended; + try call(driver, dir_hook.listFn, .{ copy.ptr, copy.len }, .{ + .cleanupFn = moveBack, + .buffer = entries_bytes, + .copy = copy, + }, hook); +} + +pub fn list(proc: *process.Info, path: []const u8, entries: []DirEntry) !usize { + const inode = find(path) orelse return Error.NotFound; + return switch (inode.resource.tag) { + .dir => listDir(inode.resource.data.dir, entries), + .dir_hook => listDirHook(proc, inode.resource.data.dir_hook, inode.pid, entries), + else => Error.NotADirectory, + }; +} + +pub fn listZ(proc: *process.Info, path_c: [*:0]const u8, entries: []DirEntry) !usize { + return list(proc, std.mem.sliceTo(path_c, 0), entries); +} + fn call(proc: *process.Info, function: *const anyopaque, args: anytype, cleanup_hook: ?process.Info.CleanupHook, term_hook: ?process.Info.TermHook) !noreturn { const callback_thread = try proc.createThread(null); callback_thread.call(@intFromPtr(function), args, cleanup_hook, term_hook); } +fn moveBack(driver: *const process.Info, buffer: []u8, copy: []const u8) void { + paging.setUserMemoryAccess(true); + @memcpy(buffer, copy); + paging.setUserMemoryAccess(false); + + var addr = @intFromPtr(copy.ptr); + const limit = addr + copy.len; + while (addr < limit) : (addr += paging.page_size) { + driver.page_table.unmapEntry(addr); + } +} + 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[12]; |