diff options
-rw-r--r-- | src/lib/syscall.zig | 56 | ||||
-rw-r--r-- | src/lib/sysexchange.zig | 60 | ||||
-rw-r--r-- | src/lib/vfs.zig | 42 |
3 files changed, 108 insertions, 50 deletions
diff --git a/src/lib/syscall.zig b/src/lib/syscall.zig index 0e0c1f1..07c62fd 100644 --- a/src/lib/syscall.zig +++ b/src/lib/syscall.zig @@ -4,32 +4,20 @@ const instructions = @import("instructions.zig"); const paging = @import("paging.zig"); +const sysexchange = @import("sysexchange.zig"); const trap = @import("trap.zig"); +const vfs = @import("vfs.zig"); pub const Error = error{ UnknownSyscall, }; -pub const Status = enum(usize) { - success, -}; - -pub const ReadFn = *const fn (context: u16, buffer: []u8) Result(usize); -pub const WriteFn = *const fn (context: u16, bytes: []const u8) Result(usize); - -pub fn Result(comptime T: type) type { - return struct { - status: Status, - value: T, - }; -} - -pub fn handle(trap_frame: *const trap.Frame) !void { +pub fn handle(trap_frame: *trap.Frame) !void { switch (trap_frame.general_purpose_registers[17]) { 100000 => uprint(trap_frame), 100001 => open(trap_frame), 100002 => close(trap_frame), - 100003 => provide(trap_frame), + 100003 => provideStream(trap_frame), 100004 => remove(trap_frame), else => return Error.UnknownSyscall, } @@ -48,9 +36,9 @@ fn uprint(trap_frame: *const trap.Frame) void { w.print("User message: {s}\r\n", .{str}) catch unreachable; } -// open(path: *const [:0]u8) Result(usize) +// open(path: [*:0]const u8) Result(usize) // fixme: Kernel panic if null pointer fn open(trap_frame: *const trap.Frame) void { - const path: *const [:0]u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]); + const path: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]); _ = path; unreachable; @@ -64,25 +52,27 @@ fn close(trap_frame: *const trap.Frame) void { unreachable; } -// provide( -// path: *const [:0]u8, -// readFn: fn (context: u16, buffer: []u8) Result(usize), -// writeFn: fn (context: u16, bytes: []const u8) Result(usize) +// provideStream( +// path: [*:0]const u8, // fixme: Kernel panic if null pointer +// readFn: ?vfs.Stream.ReadFn, +// writeFn: ?vfs.Stream.WriteFn, // ) Result(usize) -fn provide(trap_frame: *const trap.Frame) void { - const path: *const [:0]u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]); - const readFn: ReadFn = @ptrFromInt(trap_frame.general_purpose_registers[11]); - const writeFn: WriteFn = @ptrFromInt(trap_frame.general_purpose_registers[12]); - - _ = path; - _ = readFn; - _ = writeFn; - unreachable; +fn provideStream(trap_frame: *trap.Frame) void { + const path: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]); + const readFn: ?vfs.Stream.ReadFn = @ptrFromInt(trap_frame.general_purpose_registers[11]); + const writeFn: ?vfs.Stream.WriteFn = @ptrFromInt(trap_frame.general_purpose_registers[12]); + + sysexchange.frameReturn(trap_frame, vfs.provideResourceZ(path, .{ + .stream = .{ + .readFn = readFn, + .writeFn = writeFn, + }, + })); } -// remove(path: *const [:0]u8) Result(usize) +// remove(path: [*:0]const u8) Result(usize) // fixme: Kernel panic if null pointer fn remove(trap_frame: *const trap.Frame) void { - const path: *const [:0]u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]); + const path: [*:0]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[10]); _ = path; unreachable; diff --git a/src/lib/sysexchange.zig b/src/lib/sysexchange.zig new file mode 100644 index 0000000..0359700 --- /dev/null +++ b/src/lib/sysexchange.zig @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +const std = @import("std"); + +const trap = @import("trap.zig"); + +pub const Status = enum(usize) { + success = 0, + unknown = std.math.maxInt(usize), + + pub fn fromError(err: anyerror) Status { + return switch (err) { + else => .unknown, + }; + } +}; + +pub fn Result(comptime T: type) type { + return struct { + value: T, + status: Status, + + const Self = @This(); + + pub fn fromAnyTypeOrError(value: anytype) Self { + if (@typeInfo(@TypeOf(value)) == .ErrorUnion) { + if (value) |inner| + return .{ + .value = inner, + .status = .success, + } + else |err| + return .{ + .value = undefined, + .status = Status.fromError(err), + }; + } + } + }; +} + +pub fn frameReturn(trap_frame: *trap.Frame, value: anytype) void { + const ValueType = @TypeOf(value); + const T = switch (@typeInfo(ValueType)) { + .ErrorUnion => |err_union| err_union.payload, + else => ValueType, + }; + + const result = Result(T).fromAnyTypeOrError(value); + + const return_value = switch (@typeInfo(T)) { + .Void => undefined, + else => result.value, + }; + + trap_frame.general_purpose_registers[10] = return_value; + trap_frame.general_purpose_registers[11] = @intFromEnum(result.status); +} diff --git a/src/lib/vfs.zig b/src/lib/vfs.zig index e44d061..c324c48 100644 --- a/src/lib/vfs.zig +++ b/src/lib/vfs.zig @@ -4,23 +4,26 @@ const std = @import("std"); +const sysexchange = @import("sysexchange.zig"); + const mem = std.mem; -var root = undefined; +var root: Tree = undefined; pub const Error = error{ NotFound, RelativePathNotAllowed, NotADirectory, + NoAbsoluteContainingDirectory, }; // A stream is a resource that provides a shared data stream with a driver. pub const Stream = struct { - readFn: ReadFn, - writeFn: WriteFn, + readFn: ?ReadFn, + writeFn: ?WriteFn, - pub const ReadFn = *const fn (context: u16, buffer: []u8) Result(usize); - pub const WriteFn = *const fn (context: u16, bytes: []const u8) Result(usize); + pub const ReadFn = *const fn (context: u16, buffer: []u8) sysexchange.Result(usize); + pub const WriteFn = *const fn (context: u16, bytes: []const u8) sysexchange.Result(usize); }; // A file is a resource that creates a unique data stream with a driver. @@ -41,7 +44,7 @@ pub const Resource = union(enum) { }; pub const Inode = struct { - name: []u8, + name: []const u8, resource: Resource, }; @@ -59,11 +62,11 @@ pub const Tree = struct { } pub fn find(self: *const Tree, name: []const u8) ?*Node { - var node = self.nodes.first orelse return null; + var node = self.nodes.first; while (node) |current_node| { if (current_node.next == current_node) break; - if (current_node.data.name == name) return current_node; + if (mem.eql(u8, current_node.data.name, name)) return current_node; node = current_node.next; } return null; @@ -89,14 +92,18 @@ pub fn init(allocator: mem.Allocator) void { pub fn find(path: []const u8) ?*Node { if (!std.fs.path.isAbsolutePosix(path)) return null; - var it = std.fs.path.ComponentIterator(.posix, u8).init(path); + // Error set is empty. + var it = std.fs.path.ComponentIterator(.posix, u8).init(path) catch unreachable; var tree = root; while (it.next()) |component| { const node = tree.find(component.name) orelse return null; - if (component == it.last()) return node; - if (node.data.resource == .dir) |dir| { - tree = dir; + if (mem.eql(u8, component.path, (it.last() orelse return null).path)) { + return node; + } + switch (node.data.resource) { + .dir => |dir| tree = dir, + else => {}, } } @@ -107,14 +114,15 @@ pub fn find(path: []const u8) ?*Node { pub fn provideResource(path: []const u8, resource: Resource) !void { if (!std.fs.path.isAbsolutePosix(path)) return Error.RelativePathNotAllowed; - const dirname = std.fs.path.dirnamePosix(path); + const dirname = std.fs.path.dirnamePosix(path) orelse return Error.NoAbsoluteContainingDirectory; if (find(dirname)) |node| { - if (node.data.resource == .dir) |dir| { - return dir.provideResource(.{ + return switch (node.data.resource) { + .dir => |dir| @constCast(&dir).provideResource(.{ .name = std.fs.path.basenamePosix(path), .resource = resource, - }); - } else return Error.NotADirectory; + }), + else => Error.NotADirectory, + }; } else return Error.NotFound; } |