aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/syscall.zig13
-rw-r--r--src/lib/vfs.zig108
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];