aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kernel.zig4
-rw-r--r--src/lib/process.zig76
-rw-r--r--src/lib/syscall.zig262
-rw-r--r--src/lib/vfs.zig556
4 files changed, 1 insertions, 897 deletions
diff --git a/src/kernel.zig b/src/kernel.zig
index ff04f89..ea64a43 100644
--- a/src/kernel.zig
+++ b/src/kernel.zig
@@ -13,7 +13,6 @@ const paging = @import("lib/paging.zig");
const plic = @import("lib/plic.zig");
const process = @import("lib/process.zig");
const userinit = @import("lib/userinit.zig");
-const vfs = @import("lib/vfs.zig");
const Error = error{
HartIdOutOfRange,
@@ -176,9 +175,6 @@ fn pagedRun() !noreturn {
try w.print("\r\n", .{});
- try vfs.init(allocator);
- try w.print("Initialize VFS\r\n", .{});
-
try w.print("Start init process\r\n", .{});
var userinit_stream = std.io.fixedBufferStream(userinit.tarball);
try process.runInit(allocator, userinit_stream.reader());
diff --git a/src/lib/process.zig b/src/lib/process.zig
index c7eddf6..2fbab11 100644
--- a/src/lib/process.zig
+++ b/src/lib/process.zig
@@ -11,7 +11,6 @@ const rethooks = @import("rethooks.zig");
const sysexchange = @import("sysexchange.zig");
const time = @import("sbi/time.zig");
const trap = @import("trap.zig");
-const vfs = @import("vfs.zig");
const elf = std.elf;
@@ -61,49 +60,13 @@ pub const Info = struct {
pages: []align(paging.page_size) u8,
stack: []align(paging.page_size) u8,
pc: usize,
- cleanup_hook: ?CleanupHook,
- term_hook: ?TermHook,
page_table: *paging.Table,
state: State,
- rds: std.AutoArrayHashMap(usize, vfs.ResourceDescriptor),
-
- pub const CleanupHook = struct {
- pub const CleanupFn = *const fn (proc: *const Info, buffer: []u8, copy: []const u8) void;
-
- cleanupFn: CleanupFn,
- buffer: []u8,
- copy: []const u8,
- };
-
- pub const TermHook = struct {
- pub const HookFn = *const fn (context: *anyopaque, proc: *const Info) void;
-
- hookFn: HookFn,
- context: *anyopaque,
- };
pub fn satp(self: *const Info) paging.Satp {
return self.page_table.satp(self.id);
}
- pub fn createRdHandle(self: *Info, rd: vfs.ResourceDescriptor) !usize {
- if (self.rds.count() == std.math.maxInt(usize)) {
- return Error.TooManyResourceDescriptors;
- }
-
- var handle = self.rds.count() + 1;
- while (self.rds.contains(handle)) : (handle +%= 1) {}
-
- try self.rds.put(handle, rd);
- return handle;
- }
-
- pub fn destroyRdHandle(self: *Info, handle: usize) void {
- if (self.rds.fetchSwapRemove(handle)) |kv| {
- kv.value.deinit();
- }
- }
-
pub fn createThread(self: *const Info, allocator: ?std.mem.Allocator) !*Info {
const alloc = allocator orelse self.allocator;
@@ -121,7 +84,7 @@ pub const Info = struct {
return Error.TooManyThreads;
};
- const proc = .{
+ const proc = Info{
.allocator = alloc,
.id = self.id,
.thread_id = thread_id,
@@ -130,10 +93,8 @@ pub const Info = struct {
.stack = stack,
.pc = self.pc,
.cleanup_hook = null,
- .term_hook = null,
.page_table = self.page_table,
.state = .suspended,
- .rds = self.rds,
};
const proc_node = try alloc.create(std.DoublyLinkedList(Info).Node);
@@ -143,24 +104,6 @@ pub const Info = struct {
return &proc_node.data;
}
- pub fn call(self: *Info, function: usize, args: anytype, cleanup_hook: ?CleanupHook, term_hook: ?TermHook) noreturn {
- self.pc = function;
- self.cleanup_hook = cleanup_hook;
- self.term_hook = term_hook;
- self.trap_frame.general_purpose_registers[1] = @intFromPtr(&rethooks.terminate);
- inline for (args, 0..) |arg, i| {
- if (i >= 6) break;
-
- const value = usizeFromArg(arg);
- self.trap_frame.general_purpose_registers[10 + i] = value;
- }
-
- self.state = .waiting;
- schedule() catch |err| {
- std.debug.panic("schedule error: {}", .{err});
- };
- }
-
pub fn terminate(
self: *Info,
) void {
@@ -185,21 +128,7 @@ pub const Info = struct {
if (self.thread_id == 0) {
self.page_table.unmap();
paging.free(self.page_table);
-
paging.free(self.pages);
-
- for (self.rds.values()) |rd| {
- rd.deinit();
- }
- self.rds.clearAndFree();
- }
-
- if (self.cleanup_hook) |cleanup_hook| {
- cleanup_hook.cleanupFn(self, cleanup_hook.buffer, cleanup_hook.copy);
- }
- if (self.term_hook) |term_hook| {
- sysexchange.frameReturn(void, &self.trap_frame, vfs.Error.Detached);
- term_hook.hookFn(term_hook.context, self);
}
}
@@ -408,11 +337,8 @@ pub fn create(allocator: std.mem.Allocator, elf_buf: []align(@alignOf(elf.Elf64_
.pages = pages,
.stack = @ptrCast(stack),
.pc = hdr.entry,
- .cleanup_hook = null,
- .term_hook = null,
.page_table = procmem,
.state = .waiting,
- .rds = std.AutoArrayHashMap(usize, vfs.ResourceDescriptor).init(allocator),
};
proc.trap_frame.general_purpose_registers[2] = stack_top;
diff --git a/src/lib/syscall.zig b/src/lib/syscall.zig
index e4d5254..1497cec 100644
--- a/src/lib/syscall.zig
+++ b/src/lib/syscall.zig
@@ -10,7 +10,6 @@ const paging = @import("paging.zig");
const process = @import("process.zig");
const sysexchange = @import("sysexchange.zig");
const trap = @import("trap.zig");
-const vfs = @import("vfs.zig");
pub const Error = error{
Unimplemented,
@@ -24,17 +23,6 @@ pub fn handler(proc: *process.Info, trap_frame: *trap.Frame) !void {
const ret = sysexchange.frameReturn;
switch (trap_frame.general_purpose_registers[17]) {
100000 => ret(null, trap_frame, uprint(trap_frame)),
- 100001 => ret(null, trap_frame, open(proc, trap_frame)),
- 100002 => ret(null, trap_frame, close(proc, trap_frame)),
- 100003 => ret(null, trap_frame, provideStream(proc, trap_frame)),
- 100004 => ret(null, trap_frame, provideFile(proc, trap_frame)),
- 100005 => ret(null, trap_frame, provideHook(proc, trap_frame)),
- 100006 => ret(null, trap_frame, mkdir(proc, trap_frame)),
- 100007 => ret(null, trap_frame, provideDirHook(proc, trap_frame)),
- 100008 => ret(null, trap_frame, remove(trap_frame)),
- 100009 => ret(null, trap_frame, read(proc, trap_frame)),
- 100010 => ret(null, trap_frame, write(proc, trap_frame)),
- 100011 => ret(null, trap_frame, list(proc, trap_frame)),
100012 => ret(null, trap_frame, end(proc)),
100013 => ret(null, trap_frame, processId(proc)),
100014 => ret(null, trap_frame, threadId(proc)),
@@ -57,256 +45,6 @@ fn uprint(trap_frame: *const trap.Frame) void {
w.print("User message: {s}\r\n", .{str}) catch unreachable;
}
-// open(path_c: [*:0]const u8, data: usize) Result(usize) // fixme: Kernel panic if null pointer
-fn open(proc: *process.Info, trap_frame: *trap.Frame) void {
- paging.setUserMemoryAccess(true);
- defer paging.setUserMemoryAccess(false);
-
- const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]);
- const data = trap_frame.general_purpose_registers[11];
-
- const result = vfs.openZ(proc, path_c, data) catch |err| {
- sysexchange.frameReturn(usize, trap_frame, err);
- return;
- };
-
- switch (result) {
- .rd => |rd| {
- const maybe_handle = proc.createRdHandle(rd);
- sysexchange.frameReturn(usize, trap_frame, maybe_handle);
- },
- .data => |result_data| {
- sysexchange.frameReturn(null, trap_frame, result_data);
- },
- }
-}
-
-// close(handle: usize) void
-fn close(proc: *process.Info, trap_frame: *const trap.Frame) void {
- const handle = trap_frame.general_purpose_registers[10];
- proc.destroyRdHandle(handle);
-}
-
-// provideStream(
-// path_c: [*:0]const u8, // fixme: Kernel panic if null pointer
-// options: *const vfs.Options, // fixme: Kernel panic if null pointer
-// readFn: ?vfs.Stream.ReadFn,
-// writeFn: ?vfs.Stream.WriteFn,
-// ) Result(void)
-fn provideStream(proc: *const process.Info, trap_frame: *trap.Frame) void {
- paging.setUserMemoryAccess(true);
- defer paging.setUserMemoryAccess(false);
-
- const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]);
- const options: *const vfs.Options = @ptrFromInt(trap_frame.general_purpose_registers[11]);
- const readFn: ?vfs.Stream.ReadFn = @ptrFromInt(trap_frame.general_purpose_registers[12]);
- const writeFn: ?vfs.Stream.WriteFn = @ptrFromInt(trap_frame.general_purpose_registers[13]);
-
- sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .tag = .stream,
- .data = .{ .stream = .{
- .readFn = readFn,
- .writeFn = writeFn,
- } },
- }, proc.id, options.*));
-}
-
-// provideFile(
-// path_c: [*:0]const u8, // fixme: Kernel panic if null pointer
-// options: *const vfs.Options, // fixme: Kernel panic if null pointer
-// readFn: ?vfs.File.ReadFn,
-// writeFn: ?vfs.File.WriteFn,
-// closeFn: ?vfs.File.CloseFn,
-// initializer: ?*anyopaque,
-// ) Result(void)
-fn provideFile(proc: *const process.Info, trap_frame: *trap.Frame) void {
- paging.setUserMemoryAccess(true);
- defer paging.setUserMemoryAccess(false);
-
- const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]);
- const options: *const vfs.Options = @ptrFromInt(trap_frame.general_purpose_registers[11]);
- const readFn: ?vfs.File.ReadFn = @ptrFromInt(trap_frame.general_purpose_registers[12]);
- const writeFn: ?vfs.File.WriteFn = @ptrFromInt(trap_frame.general_purpose_registers[13]);
- const closeFn: ?vfs.File.CloseFn = @ptrFromInt(trap_frame.general_purpose_registers[14]);
- const initializer: ?*anyopaque = @ptrFromInt(trap_frame.general_purpose_registers[15]);
-
- sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .tag = .file,
- .data = .{ .file = .{
- .readFn = readFn,
- .writeFn = writeFn,
- .closeFn = closeFn,
- .initializer = initializer,
- } },
- }, proc.id, options.*));
-}
-
-// provideHook(
-// path_c: [*:0]const u8, // fixme: Kernel panic if null pointer
-// options: *const vfs.Options, // fixme: Kernel panic if null pointer,
-// callback: vfs.Hook.Callback,
-// ) Result(void)
-fn provideHook(proc: *const process.Info, trap_frame: *trap.Frame) void {
- paging.setUserMemoryAccess(true);
- defer paging.setUserMemoryAccess(false);
-
- const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]);
- const options: *const vfs.Options = @ptrFromInt(trap_frame.general_purpose_registers[11]);
- const callback: vfs.Hook.Callback = @ptrFromInt(trap_frame.general_purpose_registers[12]);
-
- sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .tag = .hook,
- .data = .{ .hook = .{
- .callback = callback,
- } },
- }, proc.id, options.*));
-}
-
-// mkdir(
-// path_c: [*:0]const u8, // fixme: Kernel panic if null pointer
-// ) Result(void)
-fn mkdir(proc: *const process.Info, trap_frame: *trap.Frame) void {
- const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]);
-
- const allocator = vfs.treeRoot().allocator;
- const tree = allocator.create(vfs.Tree) catch |err| {
- sysexchange.frameReturn(void, trap_frame, err);
- return;
- };
- tree.* = vfs.Tree.init(allocator);
-
- sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .tag = .dir,
- .data = .{ .dir = tree },
- }, proc.id, .{
- .reclaimable = false,
- }));
-}
-
-// provideDirHook(
-// path_c: [*:0]const u8, // fixme: Kernel panic if null pointer
-// options: *const vfs.Options, // fixme: Kernel panic if null pointer
-// provideFn: vfs.DirHook.ProvideFn,
-// findFn: vfs.DirHook.FindFn,
-// listFn:vfs.DirHook.ListFn,
-// removeFn: vfs.DirHook.RemoveFn,
-// ) Result(void)
-fn provideDirHook(proc: *const process.Info, trap_frame: *trap.Frame) void {
- paging.setUserMemoryAccess(true);
- defer paging.setUserMemoryAccess(false);
-
- const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]);
- const options: *const vfs.Options = @ptrFromInt(trap_frame.general_purpose_registers[11]);
- const provideFn: vfs.DirHook.ProvideFn = @ptrFromInt(trap_frame.general_purpose_registers[12]);
- const findFn: vfs.DirHook.FindFn = @ptrFromInt(trap_frame.general_purpose_registers[13]);
- const listFn: vfs.DirHook.ListFn = @ptrFromInt(trap_frame.general_purpose_registers[14]);
- const removeFn: vfs.DirHook.RemoveFn = @ptrFromInt(trap_frame.general_purpose_registers[15]);
-
- sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .tag = .dir_hook,
- .data = .{ .dir_hook = .{
- .provideFn = provideFn,
- .findFn = findFn,
- .listFn = listFn,
- .removeFn = removeFn,
- } },
- }, proc.id, options.*));
-}
-
-// remove(path_c: [*:0]const u8) Result(void) // fixme: Kernel panic if null pointer
-fn remove(trap_frame: *trap.Frame) void {
- const path_c: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]);
- const path = std.mem.sliceTo(path_c, 0);
- const dirname = std.fs.path.dirnamePosix(path) orelse "/";
-
- if (vfs.find(dirname)) |inode| {
- const basename = std.fs.path.basenamePosix(path);
- removeFrom(trap_frame, inode, basename);
- } else {
- sysexchange.frameReturn(void, trap_frame, vfs.Error.NotFound);
- }
-}
-
-fn removeFrom(trap_frame: *trap.Frame, inode: *vfs.Inode, basename: []const u8) void {
- switch (inode.resource.tag) {
- .dir => {
- const dir = inode.resource.data.dir;
- sysexchange.frameReturn(null, trap_frame, dir.remove(basename));
- },
- .dir_hook => {
- const dir_hook = inode.resource.data.dir_hook;
-
- const removeFn = dir_hook.removeFn orelse {
- sysexchange.frameReturn(void, trap_frame, vfs.Error.RemoveNotSupported);
- return;
- };
- const result = removeFn(basename.ptr, basename.len);
- sysexchange.frameReturnResult(void, trap_frame, result);
- },
- else => sysexchange.frameReturn(void, trap_frame, vfs.Error.NotADirectory),
- }
-}
-
-// read(handle: usize, buffer: [*]u8, len: usize) Result(usize)
-fn read(proc: *process.Info, trap_frame: *trap.Frame) void {
- paging.setUserMemoryAccess(true);
- defer paging.setUserMemoryAccess(false);
-
- const handle = trap_frame.general_purpose_registers[10];
- const buffer: [*]u8 = @ptrFromInt(trap_frame.general_purpose_registers[11]);
- const len = trap_frame.general_purpose_registers[12];
-
- const rd = proc.rds.get(handle) orelse {
- sysexchange.frameReturn(usize, trap_frame, process.Error.BadRdHandle);
- return;
- };
-
- const result = rd.read(proc, buffer[0..len]) catch |err| blk: {
- if (err == vfs.Error.Orphaned) {
- proc.destroyRdHandle(handle);
- }
-
- break :blk err;
- };
- sysexchange.frameReturn(usize, trap_frame, result);
-}
-
-// write(handle: usize, bytes: [*]const u8, len: usize) Result(usize)
-fn write(proc: *process.Info, trap_frame: *trap.Frame) void {
- paging.setUserMemoryAccess(true);
- defer paging.setUserMemoryAccess(false);
-
- const handle = trap_frame.general_purpose_registers[10];
- const bytes: [*]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[11]);
- const len = trap_frame.general_purpose_registers[12];
-
- const rd = proc.rds.get(handle) orelse {
- sysexchange.frameReturn(usize, trap_frame, process.Error.BadRdHandle);
- return;
- };
-
- const result = rd.write(proc, bytes[0..len]) catch |err| blk: {
- if (err == vfs.Error.Orphaned) {
- proc.destroyRdHandle(handle);
- }
-
- break :blk err;
- };
- 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);
-}
-
// end() void
fn end(proc: *process.Info) void {
proc.terminate();
diff --git a/src/lib/vfs.zig b/src/lib/vfs.zig
deleted file mode 100644
index 26ac977..0000000
--- a/src/lib/vfs.zig
+++ /dev/null
@@ -1,556 +0,0 @@
-// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
-//
-// SPDX-License-Identifier: AGPL-3.0-or-later
-
-const std = @import("std");
-
-const mem = @import("mem.zig");
-const paging = @import("paging.zig");
-const process = @import("process.zig");
-const sysexchange = @import("sysexchange.zig");
-
-const Allocator = std.mem.Allocator;
-
-const Result = sysexchange.Result;
-const TermHook = process.Info.TermHook;
-
-var root: Node = .{
- .data = .{
- .name_ptr = "",
- .name_len = 0,
- .inode = .{
- .resource = .{
- .tag = .dir,
- .data = .{ .dir = undefined },
- },
- .pid = 0,
- .options = .{
- .reclaimable = false,
- },
- .flags = .{},
- },
- },
-};
-
-pub fn treeRoot() *const Tree {
- return root.data.inode.resource.data.dir;
-}
-
-pub const Error = error{
- NotFound,
- RelativePathNotAllowed,
- NotADirectory,
- NoAbsoluteContainingDirectory,
- TooManyReferences,
- ReadNotSupported,
- WriteNotSupported,
- InUse,
- Detached,
- Orphaned,
- AlreadyExists,
- IsAHook,
- IsAContainer,
- ProvideNotSupported,
- RemoveNotSupported,
-};
-
-// A stream is a resource that provides a shared data stream with a driver.
-pub const Stream = extern struct {
- readFn: ?ReadFn,
- writeFn: ?WriteFn,
-
- pub const ReadFn = *const fn (ptr: [*]u8, len: usize) callconv(.C) Result(usize);
- pub const WriteFn = *const fn (ptr: [*]const u8, len: usize) callconv(.C) Result(usize);
-};
-
-// A file is a resource that creates a unique data stream with a driver.
-pub const File = extern struct {
- readFn: ?ReadFn,
- writeFn: ?WriteFn,
- closeFn: ?CloseFn,
- initializer: ?*anyopaque,
-
- pub const ReadFn = *const fn (context: *FileContext, ptr: [*]u8, len: usize) callconv(.C) Result(usize);
- pub const WriteFn = *const fn (context: *FileContext, ptr: [*]const u8, len: usize) callconv(.C) Result(usize);
- pub const CloseFn = *const fn (context: *FileContext) callconv(.C) void;
-};
-
-// A hook is a resource that invokes raw driver callbacks when interacted with.
-pub const Hook = extern struct {
- callback: Callback,
-
- pub const Callback = *allowzero const fn (pid: u16, thread_id: usize, data: usize) callconv(.C) Result(usize);
-};
-
-// A directory hook is a resource that provides other resources via driver callbacks.
-pub const DirHook = extern struct {
- provideFn: ?ProvideFn,
- findFn: FindFn,
- listFn: ListFn,
- removeFn: ?RemoveFn,
-
- 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 (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);
-};
-
-pub const FileContext = extern struct {
- inner: ?*anyopaque,
- initializer: ?*anyopaque,
-};
-
-pub const ResourceKind = enum(u32) {
- stream,
- file,
- hook,
- dir,
- dir_hook,
-};
-
-pub const Resource = extern struct {
- tag: ResourceKind,
- data: extern union {
- stream: Stream,
- file: File,
- hook: Hook,
- dir: *Tree,
- dir_hook: DirHook,
- },
-};
-
-pub const Inode = extern struct {
- resource: Resource,
- refs: usize = 0,
- pid: u16,
- options: Options,
- flags: Flags,
-};
-
-pub const Options = extern struct {
- reclaimable: bool,
-};
-
-pub const Flags = extern struct {
- detached: bool = false,
-};
-
-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;
-
-pub const Tree = struct {
- allocator: Allocator,
- nodes: std.DoublyLinkedList(DirEntry),
-
- pub fn init(allocator: Allocator) Tree {
- return .{
- .allocator = allocator,
- .nodes = std.DoublyLinkedList(DirEntry){},
- };
- }
-
- pub fn find(self: *const Tree, name: []const u8) ?*Node {
- var node = self.nodes.first;
- while (node) |current_node| {
- if (current_node.next == current_node) break;
-
- if (std.mem.eql(u8, current_node.data.name(), name)) return current_node;
- node = current_node.next;
- }
- return null;
- }
-
- pub fn provideResource(self: *Tree, entry: DirEntry) !void {
- var node = try self.allocator.create(Node);
- node.data = entry;
- self.nodes.append(node);
- }
-
- pub fn remove(self: *Tree, name: []const u8) !void {
- if (self.find(name)) |node| {
- if (node.data.inode.refs > 0) return Error.InUse;
- self.nodes.remove(node);
- } else return Error.NotFound;
- }
-};
-
-pub const OpenResult = union(enum) {
- rd: ResourceDescriptor,
- data: usize,
-};
-
-pub const ResourceDescriptor = struct {
- inode: *Inode,
- context: ?*FileContext,
-
- pub fn init(allocator: Allocator, inode: *Inode) !ResourceDescriptor {
- inode.refs = std.math.add(usize, inode.refs, 1) catch return Error.TooManyReferences;
-
- if (inode.resource.tag == .file) {
- const context = try allocator.create(FileContext);
- context.inner = null;
- context.initializer = inode.resource.data.file.initializer;
-
- return .{
- .inode = inode,
- .context = context,
- };
- }
-
- return .{
- .inode = inode,
- .context = null,
- };
- }
-
- pub fn deinit(self: ResourceDescriptor) void {
- self.inode.refs -|= 1;
-
- if (self.inode.resource.tag == .file) {
- if (self.inode.resource.data.file.closeFn) |closeFn| {
- if (self.inode.pid == 0) {
- closeFn(self.context.?);
- return;
- }
-
- const driver = process.latestThread(self.inode.pid).?;
- call(driver, closeFn, .{self.context.?}, null, null) catch {};
- }
- }
- }
-
- pub fn read(self: ResourceDescriptor, proc: *process.Info, buffer: []u8) !usize {
- return readHooked(self, proc, buffer, .{
- .hookFn = crossProcessReturn,
- .context = proc,
- });
- }
-
- pub fn readHooked(self: ResourceDescriptor, proc: *process.Info, buffer: []u8, hook: TermHook) !usize {
- if (self.inode.flags.detached and self.inode.options.reclaimable) {
- return Error.Detached;
- }
- if (self.inode.flags.detached and !self.inode.options.reclaimable) {
- return Error.Orphaned;
- }
-
- return switch (self.inode.resource.tag) {
- .stream => self.readStream(self.inode.resource.data.stream, proc, buffer, hook),
- .file => self.readFile(self.inode.resource.data.file, proc, buffer, hook),
- else => Error.ReadNotSupported,
- };
- }
-
- fn readStream(self: ResourceDescriptor, stream: Stream, proc: *process.Info, buffer: []u8, hook: TermHook) !usize {
- const readFn = stream.readFn orelse return Error.ReadNotSupported;
- if (self.inode.pid == 0) {
- return readFn(buffer.ptr, buffer.len).toErrorUnion();
- }
-
- const driver = process.latestThread(self.inode.pid).?;
- const copy = try driver.copyBuffer(buffer);
-
- proc.state = .suspended;
- try call(driver, readFn, .{ copy.ptr, copy.len }, .{
- .cleanupFn = moveBack,
- .buffer = buffer,
- .copy = copy,
- }, hook);
- }
-
- fn readFile(self: ResourceDescriptor, file: File, proc: *process.Info, buffer: []u8, hook: TermHook) !usize {
- const readFn = file.readFn orelse return Error.ReadNotSupported;
- if (self.inode.pid == 0) {
- return readFn(self.context.?, buffer.ptr, buffer.len).toErrorUnion();
- }
-
- const driver = process.latestThread(self.inode.pid).?;
- const copy = try driver.copyBuffer(buffer);
-
- proc.state = .suspended;
- try call(driver, readFn, .{ self.context.?, copy.ptr, copy.len }, .{
- .cleanupFn = moveBack,
- .buffer = buffer,
- .copy = copy,
- }, hook);
- }
-
- pub fn write(self: ResourceDescriptor, proc: *process.Info, bytes: []const u8) !usize {
- return writeHooked(self, proc, bytes, .{
- .hookFn = crossProcessReturn,
- .context = proc,
- });
- }
-
- pub fn writeHooked(self: ResourceDescriptor, proc: *process.Info, bytes: []const u8, hook: TermHook) !usize {
- if (self.inode.flags.detached and self.inode.options.reclaimable) {
- return Error.Detached;
- }
- if (self.inode.flags.detached and !self.inode.options.reclaimable) {
- return Error.Orphaned;
- }
-
- return switch (self.inode.resource.tag) {
- .stream => self.writeStream(self.inode.resource.data.stream, proc, bytes, hook),
- .file => self.writeFile(self.inode.resource.data.file, proc, bytes, hook),
- else => Error.WriteNotSupported,
- };
- }
-
- fn writeStream(self: ResourceDescriptor, stream: Stream, proc: *process.Info, bytes: []const u8, hook: TermHook) !usize {
- const writeFn = stream.writeFn orelse return Error.WriteNotSupported;
- if (self.inode.pid == 0) {
- return writeFn(bytes.ptr, bytes.len).toErrorUnion();
- }
-
- const driver = process.latestThread(self.inode.pid).?;
- const copy = try driver.copyBytes(bytes);
-
- proc.state = .suspended;
- try call(driver, writeFn, .{ copy.ptr, copy.len }, null, hook);
- }
-
- fn writeFile(self: ResourceDescriptor, file: File, proc: *process.Info, bytes: []const u8, hook: TermHook) !usize {
- const writeFn = file.writeFn orelse return Error.WriteNotSupported;
- if (self.inode.pid == 0) {
- return writeFn(self.context.?, bytes.ptr, bytes.len).toErrorUnion();
- }
-
- const driver = process.latestThread(self.inode.pid).?;
- const copy = try driver.copyBytes(bytes);
-
- proc.state = .suspended;
- try call(driver, writeFn, .{ self.context.?, copy.ptr, copy.len }, null, hook);
- }
-};
-
-pub const UserInfo = union(enum) {
- rd: ResourceDescriptor,
- value: Result(usize),
-};
-
-pub fn init(allocator: Allocator) !void {
- const tree = try allocator.create(Tree);
- tree.* = Tree.init(allocator);
- root.data.inode.resource.data.dir = tree;
-}
-
-pub fn find(path: []const u8) ?*Inode {
- if (!std.fs.path.isAbsolutePosix(path)) return null;
-
- // Error set is empty.
- var it = std.fs.path.ComponentIterator(.posix, u8).init(path) catch unreachable;
- var resource = root.data.inode.resource;
- while (it.next()) |component| {
- const inode = switch (resource.tag) {
- .dir => blk: {
- const dir = resource.data.dir;
- break :blk if (dir.find(component.name)) |entry| &entry.data.inode else null;
- },
- .dir_hook => blk: {
- // fixme: Doesn't call into U-mode drivers correctly
-
- const dir_hook = resource.data.dir_hook;
- break :blk dir_hook.findFn(component.name.ptr, component.name.len);
- },
- else => null, // Not a directory (or directory hook).
- } orelse return null;
-
- if (std.mem.eql(u8, component.path, path)) {
- return inode;
- }
- resource = inode.resource;
- }
-
- // No components, this is the root directory (/).
- return &root.data.inode;
-}
-
-fn reclaim(node: *Node, resource: Resource, pid: u16, options: Options) !void {
- if (node.data.inode.flags.detached and node.data.inode.options.reclaimable) {
- node.data.inode = .{
- .resource = resource,
- .pid = pid,
- .options = options,
- .flags = .{},
- };
- } else return Error.AlreadyExists;
-}
-
-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_ptr = name.ptr,
- .name_len = name.len,
- .inode = .{
- .resource = resource,
- .pid = pid,
- .options = options,
- .flags = .{},
- },
- });
-}
-
-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(name.ptr, name.len, .{
- .resource = resource,
- .pid = pid,
- .options = options,
- .flags = .{},
- }).toErrorUnion()
- else
- Error.ProvideNotSupported;
-}
-
-pub fn provideResource(path: []const u8, resource: Resource, pid: u16, options: Options) !void {
- if (!std.fs.path.isAbsolutePosix(path)) return Error.RelativePathNotAllowed;
-
- const dirname = std.fs.path.dirnamePosix(path) orelse return Error.NoAbsoluteContainingDirectory;
- const basename = std.fs.path.basenamePosix(path);
-
- const inode = find(dirname) orelse return Error.NotFound;
- return switch (inode.resource.tag) {
- .dir => provideInDir(inode.resource.data.dir, basename, resource, pid, options),
- .dir_hook => provideInDirHook(inode.resource.data.dir_hook, basename, resource, pid, options),
- else => Error.NotADirectory,
- };
-}
-
-pub fn provideResourceZ(path_c: [*:0]const u8, resource: Resource, pid: u16, options: Options) !void {
- return provideResource(std.mem.sliceTo(path_c, 0), resource, pid, options);
-}
-
-fn callHook(hook: Hook, pid: u16, proc: *process.Info, data: usize) !usize {
- if (pid == 0) {
- return hook.callback(proc.id, proc.thread_id, data).toErrorUnion();
- }
-
- const driver = process.latestThread(pid).?;
-
- proc.state = .suspended;
- try call(driver, hook.callback, .{ proc.id, proc.thread_id, data }, null, .{
- .hookFn = crossProcessReturn,
- .context = proc,
- });
-}
-
-pub fn open(proc: *process.Info, path: []const u8, data: usize) !OpenResult {
- const inode = find(path) orelse return Error.NotFound;
- if (inode.resource.tag == .hook) {
- const data_out = try callHook(inode.resource.data.hook, inode.pid, proc, data);
- return .{ .data = data_out };
- }
-
- return .{ .rd = try ResourceDescriptor.init(mem.page_allocator, inode) };
-}
-
-pub fn openZ(proc: *process.Info, path_c: [*:0]const u8, data: usize) !OpenResult {
- return open(proc, std.mem.sliceTo(path_c, 0), data);
-}
-
-pub fn openNonHook(path: []const u8) !ResourceDescriptor {
- const inode = find(path) orelse return Error.NotFound;
- if (inode.resource.tag == .hook) return Error.IsAHook;
-
- return ResourceDescriptor.init(mem.page_allocator, inode);
-}
-
-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];
- proc.trap_frame.general_purpose_registers[11] = driver.trap_frame.general_purpose_registers[13];
- proc.allowResume();
-}