aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel.zig2
-rw-r--r--src/lib/syscall.zig44
-rw-r--r--src/lib/vfs.zig138
3 files changed, 119 insertions, 65 deletions
diff --git a/src/kernel.zig b/src/kernel.zig
index 1ab300b..b66bef1 100644
--- a/src/kernel.zig
+++ b/src/kernel.zig
@@ -197,7 +197,7 @@ fn pagedRun() !noreturn {
}
}
- vfs.init(allocator);
+ try vfs.init(allocator);
try w.print("Initialize VFS\r\n", .{});
try w.print("Start init process\r\n", .{});
diff --git a/src/lib/syscall.zig b/src/lib/syscall.zig
index 3b7ed71..51f6ff5 100644
--- a/src/lib/syscall.zig
+++ b/src/lib/syscall.zig
@@ -86,10 +86,11 @@ fn provideStream(proc: *const process.Info, trap_frame: *trap.Frame) void {
const writeFn: ?vfs.Stream.WriteFn = @ptrFromInt(trap_frame.general_purpose_registers[12]);
sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .stream = .{
+ .tag = .stream,
+ .data = .{ .stream = .{
.readFn = readFn,
.writeFn = writeFn,
- },
+ } },
}, proc.id));
}
@@ -111,12 +112,13 @@ fn provideFile(proc: *const process.Info, trap_frame: *trap.Frame) void {
const closeFn: ?vfs.File.CloseFn = @ptrFromInt(trap_frame.general_purpose_registers[14]);
sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .file = .{
+ .tag = .file,
+ .data = .{ .file = .{
.openFn = openFn,
.readFn = readFn,
.writeFn = writeFn,
.closeFn = closeFn,
- },
+ } },
}, proc.id));
}
@@ -132,9 +134,10 @@ fn provideHook(proc: *const process.Info, trap_frame: *trap.Frame) void {
const callback: vfs.Hook.Callback = @ptrFromInt(trap_frame.general_purpose_registers[11]);
sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .hook = .{
+ .tag = .hook,
+ .data = .{ .hook = .{
.callback = callback,
- },
+ } },
}, proc.id));
}
@@ -143,8 +146,17 @@ fn provideHook(proc: *const process.Info, trap_frame: *trap.Frame) void {
// ) 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, .{
- .dir = vfs.Tree.init(vfs.treeRoot().allocator),
+ .tag = .dir,
+ .data = .{ .dir = tree },
}, proc.id));
}
@@ -164,11 +176,12 @@ fn provideDirHook(proc: *const process.Info, trap_frame: *trap.Frame) void {
const removeFn: vfs.DirHook.RemoveFn = @ptrFromInt(trap_frame.general_purpose_registers[13]);
sysexchange.frameReturn(null, trap_frame, vfs.provideResourceZ(path_c, .{
- .dir_hook = .{
+ .tag = .dir_hook,
+ .data = .{ .dir_hook = .{
.provideFn = provideFn,
.findFn = findFn,
.removeFn = removeFn,
- },
+ } },
}, proc.id));
}
@@ -178,11 +191,16 @@ fn remove(trap_frame: *trap.Frame) void {
const path = std.mem.sliceTo(path_c, 0);
const dirname = std.fs.path.dirnamePosix(path) orelse "/";
- if (vfs.find(dirname)) |node| {
+ if (vfs.find(dirname)) |inode| {
const basename = std.fs.path.basenamePosix(path);
- switch (node.data.resource) {
- .dir => |*dir| sysexchange.frameReturn(null, trap_frame, dir.remove(basename)),
- .dir_hook => |dir_hook| {
+ 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 result = dir_hook.removeFn(basename.ptr, basename.len);
sysexchange.frameReturnResult(void, trap_frame, result);
},
diff --git a/src/lib/vfs.zig b/src/lib/vfs.zig
index 49a086a..4285b79 100644
--- a/src/lib/vfs.zig
+++ b/src/lib/vfs.zig
@@ -10,10 +10,10 @@ const sysexchange = @import("sysexchange.zig");
const mem = std.mem;
-var root: Node = .{ .data = .{ .name = "", .resource = .{ .dir = undefined }, .pid = 0 } };
+var root: Node = .{ .data = .{ .name = "", .inode = .{ .resource = .{ .tag = .dir, .data = .{ .dir = undefined } }, .pid = 0 } } };
pub fn treeRoot() *const Tree {
- return &root.data.resource.dir;
+ return root.data.inode.resource.data.dir;
}
pub const Error = error{
@@ -28,7 +28,7 @@ pub const Error = error{
};
// A stream is a resource that provides a shared data stream with a driver.
-pub const Stream = struct {
+pub const Stream = extern struct {
readFn: ?ReadFn,
writeFn: ?WriteFn,
@@ -37,7 +37,7 @@ pub const Stream = struct {
};
// A file is a resource that creates a unique data stream with a driver.
-pub const File = struct {
+pub const File = extern struct {
openFn: OpenFn,
readFn: ?ReadFn,
writeFn: ?WriteFn,
@@ -50,48 +50,63 @@ pub const File = struct {
};
// A hook is a resource that invokes raw driver callbacks when interacted with.
-pub const Hook = struct {
+pub const Hook = extern struct {
callback: Callback,
- pub const Callback = *allowzero const fn (pid: u16, data: usize) sysexchange.Result(usize);
+ pub const Callback = *allowzero const fn (pid: u16, data: usize) callconv(.C) sysexchange.Result(usize);
};
// A directory hook is a resource that provides other resources via driver callbacks.
-pub const DirHook = struct {
+pub const DirHook = extern struct {
provideFn: ProvideFn,
findFn: FindFn,
removeFn: RemoveFn,
- pub const ProvideFn = *allowzero const fn (inode: Inode) sysexchange.Result(void);
- pub const FindFn = *allowzero const fn (name: [*:0]const u8) ?Inode;
- pub const RemoveFn = *allowzero const fn (name: [*]const u8, name_len: usize) callconv(.C) sysexchange.Result(void);
+ pub const ProvideFn = *allowzero const fn (inode: Inode) callconv(.C) sysexchange.Result(void);
+ pub const FindFn = *allowzero const fn (name_ptr: [*]const u8, name_len: usize) callconv(.C) ?*Inode;
+ pub const RemoveFn = *allowzero const fn (name_ptr: [*]const u8, name_len: usize) callconv(.C) sysexchange.Result(void);
};
-pub const Resource = union(enum) {
- stream: Stream,
- file: File,
- hook: Hook,
- dir: Tree,
- dir_hook: DirHook,
+pub const ResourceKind = enum(u32) {
+ stream,
+ file,
+ hook,
+ dir,
+ dir_hook,
};
-pub const Inode = struct {
- name: []const u8,
+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,
};
-pub const Node = std.DoublyLinkedList(Inode).Node;
+pub const DirEntry = struct {
+ name: []const u8,
+ inode: Inode,
+};
+
+pub const Node = std.DoublyLinkedList(DirEntry).Node;
pub const Tree = struct {
allocator: mem.Allocator,
- nodes: std.DoublyLinkedList(Inode),
+ nodes: std.DoublyLinkedList(DirEntry),
pub fn init(allocator: mem.Allocator) Tree {
return .{
.allocator = allocator,
- .nodes = std.DoublyLinkedList(Inode){},
+ .nodes = std.DoublyLinkedList(DirEntry){},
};
}
@@ -106,15 +121,15 @@ pub const Tree = struct {
return null;
}
- pub fn provideResource(self: *Tree, inode: Inode) !void {
+ pub fn provideResource(self: *Tree, entry: DirEntry) !void {
var node = try self.allocator.create(Node);
- node.data = inode;
+ node.data = entry;
self.nodes.append(node);
}
pub fn remove(self: *Tree, name: []const u8) !void {
if (self.find(name)) |node| {
- if (node.data.refs > 0) return Error.InUse;
+ if (node.data.inode.refs > 0) return Error.InUse;
self.nodes.remove(node);
} else return Error.NotFound;
}
@@ -135,8 +150,10 @@ pub const ResourceDescriptor = struct {
}
pub fn read(self: ResourceDescriptor, proc: *process.Info, buffer: []u8) !noreturn {
- return switch (self.inode.resource) {
- .stream => |stream| {
+ return switch (self.inode.resource.tag) {
+ .stream => {
+ const stream = self.inode.resource.data.stream;
+
const driver = process.latestThread(self.inode.pid).?;
const copy = try driver.copyBuffer(buffer);
@@ -157,8 +174,10 @@ pub const ResourceDescriptor = struct {
}
pub fn write(self: ResourceDescriptor, proc: *process.Info, bytes: []const u8) !noreturn {
- return switch (self.inode.resource) {
- .stream => |stream| {
+ return switch (self.inode.resource.tag) {
+ .stream => {
+ const stream = self.inode.resource.data.stream;
+
const driver = process.latestThread(self.inode.pid).?;
const copy = try driver.copyBytes(bytes);
@@ -193,43 +212,58 @@ pub const UserInfo = union(enum) {
value: sysexchange.Result(usize),
};
-pub fn init(allocator: mem.Allocator) void {
- root.data.resource.dir = Tree.init(allocator);
+pub fn init(allocator: mem.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) ?*Node {
+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 tree = root.data.resource.dir;
+ var resource = root.data.inode.resource;
while (it.next()) |component| {
- const node = tree.find(component.name) orelse return null;
+ 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: {
+ 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 (mem.eql(u8, component.path, (it.last() orelse return null).path)) {
- return node;
- }
- switch (node.data.resource) {
- .dir => |dir| tree = dir,
- else => {},
+ return inode;
}
+ resource = inode.resource;
}
// No components, this is the root directory (/).
- return &root;
+ return &root.data.inode;
}
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;
- if (find(dirname)) |node| {
- return switch (node.data.resource) {
- .dir => |*dir| dir.provideResource(.{
- .name = std.fs.path.basenamePosix(path),
- .resource = resource,
- .pid = pid,
- }),
+ if (find(dirname)) |inode| {
+ return switch (inode.resource.tag) {
+ .dir => blk: {
+ const dir = inode.resource.data.dir;
+
+ break :blk dir.provideResource(.{
+ .name = std.fs.path.basenamePosix(path),
+ .inode = .{
+ .resource = resource,
+ .pid = pid,
+ },
+ });
+ },
else => Error.NotADirectory,
};
} else return Error.NotFound;
@@ -240,10 +274,12 @@ pub fn provideResourceZ(path_c: [*:0]const u8, resource: Resource, pid: u16) !vo
}
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| {
- const driver = process.latestThread(node.data.pid).?;
+ const inode = find(path) orelse return Error.NotFound;
+ return switch (inode.resource.tag) {
+ .hook => {
+ const hook = inode.resource.data.hook;
+
+ const driver = process.latestThread(inode.pid).?;
proc.state = .suspended;
try call(driver, hook.callback, .{ pid, data }, null, .{
@@ -251,7 +287,7 @@ pub fn open(proc: *process.Info, path: []const u8, pid: u16, data: usize) !Resou
.context = proc,
});
},
- else => ResourceDescriptor.init(&node.data),
+ else => ResourceDescriptor.init(inode),
};
}