From d597931b088d045c98ef1896083b02510c7d6d5a Mon Sep 17 00:00:00 2001 From: Ratakor Date: Fri, 10 Nov 2023 00:53:31 +0100 Subject: [PATCH] Add port device + use Node.init for zero device --- README.md | 1 + kernel/acpi.zig | 18 ++++----- kernel/arch.zig | 1 + kernel/debug.zig | 16 ++++---- kernel/fs/port.zig | 46 +++++++++++++++++++++++ kernel/fs/tmpfs.zig | 42 ++++++++++++++------- kernel/fs/zero.zig | 43 ++++------------------ kernel/vfs.zig | 89 ++++++++++++++++++++++++++------------------- 8 files changed, 151 insertions(+), 105 deletions(-) create mode 100644 kernel/fs/port.zig diff --git a/README.md b/README.md index cda5d40..4bbee51 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Make sure to have `zig master`, `xorriso` and `qemu-system-x86` then run # File structure This shouldn't be in readme. +TODO: move init function at the end of file? 1. imports 2. type definitions diff --git a/kernel/acpi.zig b/kernel/acpi.zig index 9a48617..2db513b 100644 --- a/kernel/acpi.zig +++ b/kernel/acpi.zig @@ -149,11 +149,11 @@ fn parse(comptime T: type, addr: u64) void { const sdt: *const SDT = @ptrFromInt(entry + vmm.hhdm_offset); sdt.doChecksum(); - switch (std.mem.readInt(u32, &sdt.signature, .little)) { - std.mem.readInt(u32, "APIC", .little) => handleMADT(sdt), - std.mem.readInt(u32, "FACP", .little) => handleFADT(sdt), - std.mem.readInt(u32, "HPET", .little) => {}, // ignored - std.mem.readInt(u32, "WAET", .little) => {}, // ignored + switch (std.mem.readInt(u32, &sdt.signature, arch.endian)) { + std.mem.readInt(u32, "APIC", arch.endian) => handleMADT(sdt), + std.mem.readInt(u32, "FACP", arch.endian) => handleFADT(sdt), + std.mem.readInt(u32, "HPET", arch.endian) => {}, // ignored + std.mem.readInt(u32, "WAET", arch.endian) => {}, // ignored else => log.warn("unhandled ACPI table: {s}", .{sdt.signature}), } } @@ -161,7 +161,7 @@ fn parse(comptime T: type, addr: u64) void { /// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt fn handleMADT(madt: *const SDT) void { - apic.lapic_base = std.mem.readInt(u32, madt.data()[0..4], .little); + apic.lapic_base = std.mem.readInt(u32, madt.data()[0..4], arch.endian); log.info("lapic base: 0x{x}", .{apic.lapic_base}); var data = madt.data()[8..]; // discard madt header @@ -268,15 +268,15 @@ inline fn parseInt(s5_addr: []const u8, value: *u64) usize { return 2; }, 0xb => { - value.* = std.mem.readInt(u16, s5_addr[1..3], .little); + value.* = std.mem.readInt(u16, s5_addr[1..3], arch.endian); return 3; }, 0xc => { - value.* = std.mem.readInt(u32, s5_addr[1..5], .little); + value.* = std.mem.readInt(u32, s5_addr[1..5], arch.endian); return 5; }, 0xe => { - value.* = std.mem.readInt(u64, s5_addr[1..9], .little); + value.* = std.mem.readInt(u64, s5_addr[1..9], arch.endian); return 9; }, else => unreachable, diff --git a/kernel/arch.zig b/kernel/arch.zig index 52da4d2..4fbd72c 100644 --- a/kernel/arch.zig +++ b/kernel/arch.zig @@ -1,4 +1,5 @@ pub const arch = @import("builtin").target.cpu.arch; +pub const endian = arch.endian(); pub usingnamespace switch (arch) { .x86_64 => @import("arch/x86_64.zig"), diff --git a/kernel/debug.zig b/kernel/debug.zig index 1b14283..3b9b71f 100644 --- a/kernel/debug.zig +++ b/kernel/debug.zig @@ -242,7 +242,7 @@ fn initDebugInfo() !void { const kernel_file = root.kernel_file_request.response.?.kernel_file; debug_info = .{ - .endian = .little, + .endian = arch.endian, .sections = .{ .{ .data = try getSectionSlice(kernel_file.address, ".debug_info"), .owned = true }, .{ .data = try getSectionSlice(kernel_file.address, ".debug_abbrev"), .owned = true }, @@ -266,8 +266,8 @@ fn initDebugInfo() !void { } fn getSectionSlice(elf: [*]const u8, section_name: []const u8) ![]const u8 { - const sh_strndx = std.mem.readInt(u16, elf[62 .. 62 + 2], .little); - const sh_num = std.mem.readInt(u16, elf[60 .. 60 + 2], .little); + const sh_strndx = std.mem.readInt(u16, elf[62 .. 62 + 2], arch.endian); + const sh_num = std.mem.readInt(u16, elf[60 .. 60 + 2], arch.endian); if (sh_strndx > sh_num) { return error.ShstrndxOutOfRange; @@ -288,22 +288,22 @@ fn getSectionSlice(elf: [*]const u8, section_name: []const u8) ![]const u8 { } fn getShdr(elf: [*]const u8, idx: u16) []const u8 { - const sh_offset = std.mem.readInt(u64, elf[40 .. 40 + 8], .little); - const sh_entsize = std.mem.readInt(u16, elf[58 .. 58 + 2], .little); + const sh_offset = std.mem.readInt(u64, elf[40 .. 40 + 8], arch.endian); + const sh_entsize = std.mem.readInt(u16, elf[58 .. 58 + 2], arch.endian); const off = sh_offset + sh_entsize * idx; return elf[off .. off + sh_entsize]; } fn getSectionData(elf: [*]const u8, shdr: []const u8) []const u8 { - const offset = std.mem.readInt(u64, shdr[24..][0..8], .little); - const size = std.mem.readInt(u64, shdr[32..][0..8], .little); + const offset = std.mem.readInt(u64, shdr[24..][0..8], arch.endian); + const size = std.mem.readInt(u64, shdr[32..][0..8], arch.endian); return elf[offset .. offset + size]; } fn getSectionName(names: []const u8, shdr: []const u8) ?[]const u8 { - const offset = std.mem.readInt(u32, shdr[0..][0..4], .little); + const offset = std.mem.readInt(u32, shdr[0..][0..4], arch.endian); const len = std.mem.indexOfScalar(u8, names[offset..], 0) orelse return null; return names[offset .. offset + len]; diff --git a/kernel/fs/port.zig b/kernel/fs/port.zig new file mode 100644 index 0000000..82545f0 --- /dev/null +++ b/kernel/fs/port.zig @@ -0,0 +1,46 @@ +const std = @import("std"); +const root = @import("root"); +const vfs = root.vfs; +const arch = root.arch; + +const vtable = vfs.Node.VTable{ + .read = read, + .write = write, +}; + +pub fn init() void { + const node = vfs.Node.init(&vtable, "port", undefined, 0o640 | std.os.S.IFBLK) catch unreachable; + vfs.mount("/dev/port", node) catch unreachable; +} + +fn read(node: *vfs.Node, buf: []u8, offset: std.os.off_t) vfs.ReadError!usize { + _ = node; + + const port: u16 = @intCast(offset); + switch (buf.len) { + @sizeOf(u8) => buf[0] = arch.in(u8, port), + @sizeOf(u16) => @as(*u16, @ptrCast(@alignCast(buf.ptr))).* = arch.in(u16, port), + @sizeOf(u32) => @as(*u32, @ptrCast(@alignCast(buf.ptr))).* = arch.in(u32, port), + else => for (buf, 0..) |*byte, i| { + byte.* = arch.in(u8, @intCast(port + i)); + }, + } + + return buf.len; +} + +fn write(node: *vfs.Node, buf: []const u8, offset: std.os.off_t) vfs.WriteError!usize { + _ = node; + + const port: u16 = @intCast(offset); + switch (buf.len) { + @sizeOf(u8) => arch.out(u8, port, buf[0]), + @sizeOf(u16) => arch.out(u16, port, std.mem.readInt(u16, buf[0..@sizeOf(u16)], arch.endian)), + @sizeOf(u32) => arch.out(u32, port, std.mem.readInt(u32, buf[0..@sizeOf(u32)], arch.endian)), + else => for (buf, 0..) |byte, i| { + arch.out(u8, @intCast(port + i), byte); + }, + } + + return buf.len; +} diff --git a/kernel/fs/tmpfs.zig b/kernel/fs/tmpfs.zig index 4d2a525..49930ad 100644 --- a/kernel/fs/tmpfs.zig +++ b/kernel/fs/tmpfs.zig @@ -248,11 +248,12 @@ fn create(parent: *vfs.Node, name: []const u8, mode: std.os.mode_t) vfs.CreateEr parent.lock.lock(); defer parent.lock.unlock(); - const self: *Inode = @ptrCast(@alignCast(parent.context)); - const gop = try self.children.getOrPut(root.allocator, name); - if (gop.found_existing) { - return error.PathAlreadyExists; - } + // TODO + // const self: *Inode = @ptrCast(@alignCast(parent.context)); + // const gop = try self.children.getOrPut(root.allocator, name); + // if (gop.found_existing) { + // return error.PathAlreadyExists; + // } const node = try vfs.Node.init(&Inode.vtable, name, parent, mode); const inode = try Inode.init(node.kind, null); @@ -262,7 +263,7 @@ fn create(parent: *vfs.Node, name: []const u8, mode: std.os.mode_t) vfs.CreateEr node.stat.gid = sched.currentProcess().group; node.stat.blksize = Inode.blksize; node.context = @ptrCast(inode); - gop.value_ptr.* = node; + // gop.value_ptr.* = node; } fn symlink(parent: *vfs.Node, name: []const u8, target: []const u8) vfs.CreateError!void { @@ -271,11 +272,12 @@ fn symlink(parent: *vfs.Node, name: []const u8, target: []const u8) vfs.CreateEr parent.lock.lock(); defer parent.lock.unlock(); - const self: *Inode = @ptrCast(@alignCast(parent.context)); - const gop = try self.children.getOrPut(root.allocator, name); - if (gop.found_existing) { - return error.PathAlreadyExists; - } + // TODO + // const self: *Inode = @ptrCast(@alignCast(parent.context)); + // const gop = try self.children.getOrPut(root.allocator, name); + // if (gop.found_existing) { + // return error.PathAlreadyExists; + // } const node = try vfs.Node.init(&Inode.vtable, name, parent, 0o777 | std.os.S.IFLNK); const inode = try Inode.init(node.kind, target); @@ -285,7 +287,7 @@ fn symlink(parent: *vfs.Node, name: []const u8, target: []const u8) vfs.CreateEr node.stat.gid = sched.currentProcess().group; node.stat.blksize = Inode.blksize; node.context = @ptrCast(inode); - gop.value_ptr.* = node; + // gop.value_ptr.* = node; } fn link(parent: *vfs.Node, name: []const u8, node: *vfs.Node) vfs.CreateError!void { @@ -329,8 +331,20 @@ fn mount(parent: *vfs.Node, name: []const u8, _: *vfs.Node) vfs.CreateError!*vfs // TODO the problem is that this won't work if parent is not of the same filesystem // and it returns nothing - _ = try create(parent, name, 0o777 | std.os.S.IFDIR); - return undefined; + // _ = try create(parent, name, 0o777 | std.os.S.IFDIR); + + // TODO: use create + const node = try vfs.Node.init(&Inode.vtable, name, parent, 0o777 | std.os.S.IFDIR); + const inode = try Inode.init(node.kind, null); + node.stat.dev = vfs.allocDevID(); + node.stat.ino = 0; + // node.stat.ino = @atomicRmw(os.ino_t, self.inode_counter, .Add, 1, .Release); + node.stat.uid = 0; + node.stat.gid = 0; + node.stat.blksize = Inode.blksize; + node.context = @ptrCast(inode); + + return node; } pub fn init() void { diff --git a/kernel/fs/zero.zig b/kernel/fs/zero.zig index a0a081e..bd7707d 100644 --- a/kernel/fs/zero.zig +++ b/kernel/fs/zero.zig @@ -22,23 +22,9 @@ const Null = struct { return buf.len; } - fn init() !*vfs.Node { - const node = try root.allocator.create(vfs.Node); - - node.* = .{ - .vtable = &vtable, - .name = try root.allocator.dupe(u8, "null"), - .stat = .{ - .ino = 0, - .mode = 0o666, - .uid = 0, - .gid = 0, - }, - .kind = .character_device, - .inode = 0, - }; - - return node; + fn init() *vfs.Node { + // 0o666 = std.fs.File.default_mode + return vfs.Node.init(&vtable, "null", undefined, 0o666 | std.os.S.IFCHR) catch unreachable; } }; @@ -63,27 +49,12 @@ const Zero = struct { return buf.len; } - fn init() !*vfs.Node { - const node = try root.allocator.create(vfs.Node); - - node.* = .{ - .vtable = &vtable, - .name = try root.allocator.dupe(u8, "zero"), - .stat = .{ - .ino = 0, - .mode = 0o666, - .uid = 0, - .gid = 0, - }, - .kind = .character_device, - .inode = 0, - }; - - return node; + fn init() *vfs.Node { + return vfs.Node.init(&vtable, "zero", undefined, 0o666 | std.os.S.IFCHR) catch unreachable; } }; pub fn init() void { - _ = vfs.mount("/dev/null", Null.init() catch unreachable) catch unreachable; - _ = vfs.mount("/dev/zero", Zero.init() catch unreachable) catch unreachable; + _ = vfs.mount("/dev/null", Null.init()) catch unreachable; + _ = vfs.mount("/dev/zero", Zero.init()) catch unreachable; } diff --git a/kernel/vfs.zig b/kernel/vfs.zig index ce4e57b..934c4a1 100644 --- a/kernel/vfs.zig +++ b/kernel/vfs.zig @@ -346,7 +346,7 @@ pub const FileDescriptor = struct { // TODO: mode, lock, flags, refcount? }; -pub const MountFn = *const fn (parent: *Node, name: []const u8, source: *Node) CreateError!*Node; +// pub const MountFn = *const fn (parent: *Node, name: []const u8, source: *Node) CreateError!*Node; var filesystems: std.StringHashMapUnmanaged(MountFn) = .{}; pub var root_node: *Node = undefined; @@ -375,6 +375,7 @@ pub fn allocDevID() os.dev_t { /// source: new node original path e.g. /dev/sda1 /// target: path for the new node /// fs_name: file system name +pub const MountFn = *const fn (parent: *Node, name: []const u8, source: *Node) CreateError!*Node; pub fn mount(parent: *Node, source: ?[]const u8, target: []const u8, fs_name: []const u8) !void { _ = fs_name; _ = target; @@ -448,6 +449,55 @@ fn makePath(path: []const u8, fs_name: []const u8) !*Node { return node; } +// TODO: this uses Entry and Tree from previous commits +// pub const MountFn = *const fn (source: []const u8, target: []const u8) CreateError!*Node; +// pub fn mount(path: []const u8, local_root: *Node) !*Node { +// if (!std.fs.path.isAbsolute(path)) return error.PathIsNotAbsolute; +// // std.debug.assert(local_root.mountpoint == null); // TODO + +// vfs_lock.lock(); +// defer vfs_lock.unlock(); + +// // TODO needed? +// local_root.lock.lock(); +// defer local_root.lock.unlock(); +// // local_root.refcount = -1; + +// var node = root_node; +// var iter = std.mem.tokenizeScalar(u8, path, std.fs.path.sep); + +// // TODO: this is makePath +// while (iter.next()) |component| { +// const gop = try node.children.getOrPut(root.allocator, component); +// if (gop.found_existing) { +// node = gop.value_ptr.*; +// } else { +// // fail here? + +// // const entry = try root.allocator.create(Entry); +// // entry.* = .{ .name = try root.allocator.dupe(u8, component) }; +// const new_node = try root.allocator.create(Node); +// // const new_node = try Node.init(); // TODO +// gop.value_ptr.* = new_node; +// node = new_node; +// } +// } + +// // const entry = node.value; +// // if (entry.file) |_| { +// // log.warn("path {s} is already mounted!", .{path}); +// // return error.AlreadyMounted; +// // } +// // entry.file = local_root; +// // return node; + +// // local_root.mountpoint = node; + +// log.info("mounted `{s}` to `{s}`", .{ local_root.name, path }); + +// return node; +// } + // TODO: rework const Path2Node = struct { target_parent: *Node, @@ -511,43 +561,6 @@ const Path2Node = struct { } }; -// pub fn mount(path: []const u8, file: *Node) !*Node { -// std.debug.assert(std.fs.path.isAbsolute(path)); -// std.debug.assert(file.mountpoint == null); // TODO - -// vfs_lock.lock(); -// defer vfs_lock.unlock(); - -// file.refcount = -1; - -// var node = root_node; -// var iter = std.mem.tokenizeScalar(u8, path, std.fs.path.sep); - -// // TODO: this is makePath, extract it? -// while (iter.next()) |component| { -// const gop = try node.children.getOrPut(root.allocator, component); -// if (gop.found_existing) { -// node = gop.value_ptr.*; -// } else { -// const new_node = try root.allocator.create(Node); -// // const new_node = try Node.init(); // TODO -// gop.value_ptr.* = new_node; -// node = new_node; -// } -// } - -// // TODO: mountpoint? -// // if (node.mountpoint) |_| { -// // log.warn("path {s} is already mounted!", .{path}); -// // // TODO: return or throw err? -// // } -// file.mountpoint = node; - -// log.info("mounted `{s}` to `{s}`", .{ file.name, path }); - -// return node; -// } - // // TODO // fn readDirMapper(self: *Node, index: usize) ReadDirError!*DirectoryEntry { // if (self.device) |device| {