From f5c0af047e2a203902be4050c2f80119e3c422d2 Mon Sep 17 00:00:00 2001 From: Ratakor Date: Sun, 12 Nov 2023 19:08:07 +0100 Subject: [PATCH] rework apic + WIP vfs Add a basic docs step to build system. Cleanup and improve apic.zig. Change idle thread to null. Move pit to arch. Start HPET. --- .github/workflows/ci.yml | 2 +- build.zig | 10 ++- kernel/acpi.zig | 53 +++++++---- kernel/arch/x86_64.zig | 1 + kernel/arch/x86_64/apic.zig | 162 +++++++++++++++++++++------------- kernel/arch/x86_64/cpu.zig | 13 +-- kernel/arch/x86_64/idt.zig | 7 +- kernel/arch/x86_64/pit.zig | 32 +++++++ kernel/arch/x86_64/x86_64.zig | 28 +++--- kernel/event.zig | 40 ++++++--- kernel/fs/initramfs.zig | 15 ++-- kernel/mm/pmm.zig | 2 + kernel/mm/vmm.zig | 44 +++++---- kernel/ps2.zig | 2 +- kernel/sched.zig | 43 +++++---- kernel/smp.zig | 20 ++--- kernel/time.zig | 35 +------- kernel/vfs.zig | 80 +++++++++-------- lib/ubik.zig | 5 +- 19 files changed, 338 insertions(+), 256 deletions(-) create mode 100644 kernel/arch/x86_64/pit.zig diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 832733d..3b6a098 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: shell: bash run: | set +e - timeout 60 zig build run -Dnodisplay=true + timeout 30 zig build run -Dnodisplay=true [ $? -ne 124 ] && exit 1 || exit 0 lint: diff --git a/build.zig b/build.zig index 17f1ddd..e28c4a9 100644 --- a/build.zig +++ b/build.zig @@ -51,7 +51,8 @@ fn findModules(b: *std.Build) []const u8 { while (iter.next()) |line| { if (std.mem.startsWith(u8, line, "MODULE_PATH=boot://") and - !std.mem.endsWith(u8, line, ".tar")) { + !std.mem.endsWith(u8, line, ".tar")) + { const i = std.mem.lastIndexOfScalar(u8, line, '/') orelse unreachable; modules.append(line[i + 1 ..]) catch unreachable; } @@ -123,6 +124,13 @@ pub fn build(b: *std.Build) void { run_cmd.step.dependOn(image_step); run_step.dependOn(&run_cmd.step); + const docs_step = b.step("docs", "Generate documentations"); + docs_step.dependOn(&b.addInstallDirectory(.{ + .source_dir = kernel.getEmittedDocs(), + .install_dir = .prefix, + .install_subdir = "docs", + }).step); + const fmt_step = b.step("fmt", "Format all source files"); fmt_step.dependOn(&b.addFmt(.{ .paths = &[_][]const u8{ "kernel", "lib" } }).step); diff --git a/kernel/acpi.zig b/kernel/acpi.zig index 2db513b..ff6e1e5 100644 --- a/kernel/acpi.zig +++ b/kernel/acpi.zig @@ -1,4 +1,5 @@ //! https://uefi.org/specs/ACPI/6.5/ +//! https://uefi.org/acpi const std = @import("std"); const root = @import("root"); @@ -6,6 +7,7 @@ const arch = @import("arch.zig"); const apic = arch.apic; const vmm = root.vmm; const log = std.log.scoped(.acpi); +const readInt = std.mem.readInt; /// System Description Table const SDT = extern struct { @@ -56,9 +58,9 @@ const RSDP = extern struct { /// Generic Address Structure const GAS = extern struct { - address_space: u8 align(1), - bit_width: u8 align(1), - bit_offset: u8 align(1), + address_space_id: u8 align(1), + register_bit_width: u8 align(1), + register_bit_offset: u8 align(1), access_size: u8 align(1), address: u64 align(1), }; @@ -122,6 +124,25 @@ const FADT = extern struct { x_gpe1_block: GAS align(1), }; +/// High Precision Event Timer +const HPET = packed struct(u160) { + hardware_rev_id: u8, + comparator_count: u5, + counter_size: u1, + reserved0: u1, + legacy_replacement: u1, + pci_vendor_id: u16, + // address: GAS, // `only packed structs layout are allowed in packed types` + address_space_id: u8, + register_bit_width: u8, + register_bit_offset: u8, + reserved1: u8, + address: u64, + hpet_number: u8, + minimum_tick: u16, + page_protection: u8, +}; + var use_xsdt: bool = undefined; var fadt: *const FADT = undefined; @@ -135,25 +156,25 @@ pub fn init() void { if (use_xsdt) { parse(u64, rsdp.xsdt_addr); } else { - parse(u32, @intCast(rsdp.rsdt_addr)); + parse(u32, rsdp.rsdt_addr); } } -fn parse(comptime T: type, addr: u64) void { +fn parse(comptime T: type, addr: T) void { const rsdt: *const SDT = @ptrFromInt(addr + vmm.hhdm_offset); - rsdt.doChecksum(); log.info("RSDT is at 0x{x}", .{@intFromPtr(rsdt)}); + rsdt.doChecksum(); const entries = std.mem.bytesAsSlice(T, rsdt.data()); for (entries) |entry| { const sdt: *const SDT = @ptrFromInt(entry + vmm.hhdm_offset); sdt.doChecksum(); - 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 + switch (readInt(u32, &sdt.signature, arch.endian)) { + readInt(u32, "APIC", arch.endian) => handleMADT(sdt), + readInt(u32, "FACP", arch.endian) => handleFADT(sdt), + readInt(u32, "HPET", arch.endian) => {}, // TODO + readInt(u32, "WAET", arch.endian) => {}, // ignored else => log.warn("unhandled ACPI table: {s}", .{sdt.signature}), } } @@ -161,9 +182,9 @@ 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], arch.endian); + apic.lapic_base = readInt(u32, madt.data()[0..4], arch.endian) + vmm.hhdm_offset; log.info("lapic base: 0x{x}", .{apic.lapic_base}); - var data = madt.data()[8..]; // discard madt header + var data = madt.data()[8..]; // discard the rest of madt header while (data.len > 2) { const kind = data[0]; @@ -268,15 +289,15 @@ inline fn parseInt(s5_addr: []const u8, value: *u64) usize { return 2; }, 0xb => { - value.* = std.mem.readInt(u16, s5_addr[1..3], arch.endian); + value.* = readInt(u16, s5_addr[1..3], arch.endian); return 3; }, 0xc => { - value.* = std.mem.readInt(u32, s5_addr[1..5], arch.endian); + value.* = readInt(u32, s5_addr[1..5], arch.endian); return 5; }, 0xe => { - value.* = std.mem.readInt(u64, s5_addr[1..9], arch.endian); + value.* = readInt(u64, s5_addr[1..9], arch.endian); return 9; }, else => unreachable, diff --git a/kernel/arch/x86_64.zig b/kernel/arch/x86_64.zig index c26edd6..c87c569 100644 --- a/kernel/arch/x86_64.zig +++ b/kernel/arch/x86_64.zig @@ -3,6 +3,7 @@ pub const gdt = @import("x86_64/gdt.zig"); pub const idt = @import("x86_64/idt.zig"); pub const apic = @import("x86_64/apic.zig"); pub const cpu = @import("x86_64/cpu.zig"); +pub const pit = @import("x86_64/pit.zig"); pub const Context = idt.Context; const mem = @import("x86_64/mem.zig"); diff --git a/kernel/arch/x86_64/apic.zig b/kernel/arch/x86_64/apic.zig index 1cba63a..e57fa48 100644 --- a/kernel/arch/x86_64/apic.zig +++ b/kernel/arch/x86_64/apic.zig @@ -1,22 +1,39 @@ const std = @import("std"); const root = @import("root"); const x86 = @import("x86_64.zig"); +const pit = @import("pit.zig"); const vmm = root.vmm; const smp = root.smp; -const pit = root.time; const SpinLock = root.SpinLock; -const Register = enum(u64) { - lapic_id = 0x020, - eoi = 0x0b0, // end of interrupt - spurious = 0x0f0, - cmci = 0x2f0, // LVT corrected machine check interrupt - icr0 = 0x300, // interrupt command register - icr1 = 0x310, - lvt_timer = 0x320, - timer_initial_count = 0x380, - timer_current_count = 0x390, - timer_divide = 0x3e0, +/// Local Advanced Programmable Interrupt Controller +const LAPIC = struct { + // intel manual volume 3A page 11-6 (396) + const Register = enum(u64) { + lapic_id = 0x020, + eoi = 0x0b0, // end of interrupt + spurious = 0x0f0, + cmci = 0x2f0, // LVT corrected machine check interrupt + icr_low = 0x300, + icr_high = 0x310, + lvt_timer = 0x320, + lvt_thermal = 0x330, // LVT thermal sensor + lvt_perf = 0x340, // LVT performance monitoring counters + timer_initial_count = 0x380, + timer_current_count = 0x390, + timer_divide = 0x3e0, + }; + + fn read(register: Register) u32 { + const reg = @intFromEnum(register); + return @as(*volatile u32, @ptrFromInt(lapic_base + reg)).*; + } + + fn write(register: Register, val: u32) void { + const reg = @intFromEnum(register); + const addr: *volatile u32 = @ptrFromInt(lapic_base + reg); + addr.* = val; + } }; /// Input/Output Advanced Programmable Interrupt Controller @@ -26,6 +43,27 @@ const IOAPIC = extern struct { addr: u32 align(1), base_gsi: u32 align(1), + const Redirect = packed struct(u64) { + vector: u8, + delivery_mode: u3 = 0, + destination_mode: u1 = 0, + delivery_status: u1 = 0, + pin_polarity: u1, + remote_irr: u1 = 0, + trigger_mode: u1, + mask: u1, + reserved: u39 = 0, + destination: u8, + + inline fn low(self: Redirect) u32 { + return @truncate(@as(u64, @bitCast(self))); + } + + inline fn high(self: Redirect) u32 { + return @truncate(@as(u64, @bitCast(self)) >> 32); + } + }; + fn read(self: IOAPIC, reg: u32) u32 { const base: [*]volatile u32 = @ptrFromInt(self.addr + vmm.hhdm_offset); base[0] = reg; @@ -51,8 +89,29 @@ const ISO = extern struct { flags: u16 align(1), }; -pub var lapic_base: u32 = undefined; // set in acpi.zig with handleMADT() +// look intel manual volume 3A page 11-19 (409) for details about each field +/// Interrupt Command Register (bits 0-31) +const ICRLow = packed struct(u32) { + vector: u8, + delivery_mode: u3 = 0b000, + destination_mode: u1 = 0b0, + delivery_status: u1 = 0, // read-only + reserved0: u1 = 0, + level: u1 = 0b1, + trigger_mode: u1 = 0b0, + reserved1: u2 = 0, + destination_shorthand: DestinationShorthand = .no_shorthand, + reserved2: u12 = 0, + + const DestinationShorthand = enum(u2) { + no_shorthand = 0b00, + self = 0b01, + all_including_self = 0b10, + all_excluding_self = 0b11, + }; +}; +pub var lapic_base: u64 = undefined; // set in acpi.zig with handleMADT() pub var io_apics: std.ArrayListUnmanaged(*const IOAPIC) = .{}; pub var isos: std.ArrayListUnmanaged(*const ISO) = .{}; @@ -65,51 +124,44 @@ pub fn init() void { timerCalibrate(); // configure spurious IRQ - writeRegister(.spurious, readRegister(.spurious) | (1 << 8) | 0xff); + LAPIC.write(.spurious, LAPIC.read(.spurious) | 0x1ff); } pub inline fn eoi() void { - writeRegister(.eoi, 0); + LAPIC.write(.eoi, 0); } pub fn timerOneShot(microseconds: u64, vector: u8) void { const old_state = x86.toggleInterrupts(false); defer _ = x86.toggleInterrupts(old_state); - timerStop(); - const ticks = microseconds * (smp.thisCpu().lapic_freq / 1_000_000); - writeRegister(.lvt_timer, vector); - writeRegister(.timer_divide, 0); - writeRegister(.timer_initial_count, @truncate(ticks)); + LAPIC.write(.lvt_timer, vector); // clear mask and set vector + LAPIC.write(.timer_divide, 0); + LAPIC.write(.timer_initial_count, @intCast(ticks)); } pub fn timerStop() void { - writeRegister(.timer_initial_count, 0); - writeRegister(.lvt_timer, 1 << 16); + LAPIC.write(.timer_initial_count, 0); // stop timer + LAPIC.write(.lvt_timer, 1 << 16); // mask vector } -pub fn sendIPI(lapic_id: u32, vector: u32) void { - writeRegister(.icr1, lapic_id << 24); - writeRegister(.icr0, vector | (1 << 14)); // clear init level +pub fn sendIPI(lapic_id: u32, icr_low: ICRLow) void { + LAPIC.write(.icr_high, lapic_id << 24); // bits 32-55 of ICR are reserved + LAPIC.write(.icr_low, @bitCast(icr_low)); } -// TODO -pub fn timerCalibrate() void { +fn timerCalibrate() void { timerStop(); - - // init PIT - writeRegister(.lvt_timer, (1 << 16) | 0xff); // vector 0xff, masked - writeRegister(.timer_divide, 0); - + LAPIC.write(.timer_divide, 0); pit.setReloadValue(0xffff); // reset PIT - const samples: u64 = 0xfffff; + const samples = 0xfffff; const initial_tick = pit.getCurrentCount(); - writeRegister(.timer_initial_count, @truncate(samples)); - while (readRegister(.timer_current_count) != 0) {} + LAPIC.write(.timer_initial_count, samples); + while (LAPIC.read(.timer_current_count) != 0) {} const final_tick = pit.getCurrentCount(); @@ -119,18 +171,7 @@ pub fn timerCalibrate() void { timerStop(); } -fn readRegister(register: Register) u32 { - const reg = @intFromEnum(register); - return @as(*volatile u32, @ptrFromInt(lapic_base + vmm.hhdm_offset + reg)).*; -} - -fn writeRegister(register: Register, val: u32) void { - const reg = @intFromEnum(register); - const ptr: *volatile u32 = @ptrFromInt(lapic_base + vmm.hhdm_offset + reg); - ptr.* = val; -} - -fn setGSIRedirect(lapic_id: u32, vector: u8, gsi: u8, flags: u16) void { +fn setGSIRedirect(lapic_id: u32, vector: u8, gsi: u8, flags: u16, enable: bool) void { const io_apic = for (io_apics.items) |io_apic| { if (gsi >= io_apic.base_gsi and gsi < io_apic.base_gsi + io_apic.gsiCount()) { break io_apic; @@ -139,29 +180,26 @@ fn setGSIRedirect(lapic_id: u32, vector: u8, gsi: u8, flags: u16) void { std.debug.panic("Could not find an IOAPIC for GSI {}", .{gsi}); }; - var redirect: u64 = vector; - if ((flags & (1 << 1)) != 0) { - redirect |= (1 << 13); - } - - if ((flags & (1 << 3)) != 0) { - redirect |= (1 << 15); - } - - redirect |= @as(u64, @intCast(lapic_id)) << 56; + const redirect: IOAPIC.Redirect = .{ + .vector = vector, + .pin_polarity = @intFromBool(flags & (1 << 1) != 0), + .trigger_mode = @intFromBool(flags & (1 << 3) != 0), + .mask = @intFromBool(!enable), + .destination = @intCast(lapic_id), + }; const io_redirect_table = 0x10 + (gsi - io_apic.base_gsi) * 2; - io_apic.write(io_redirect_table, @truncate(redirect)); - io_apic.write(io_redirect_table + 1, @truncate(redirect >> 32)); + io_apic.write(io_redirect_table, redirect.low()); + io_apic.write(io_redirect_table + 1, redirect.high()); } -pub fn setIRQRedirect(lapic_id: u32, vector: u8, irq: u8) void { +pub fn setIRQRedirect(lapic_id: u32, vector: u8, irq: u8, enable: bool) void { for (isos.items) |iso| { if (iso.irq_source == irq) { - setGSIRedirect(lapic_id, vector, @intCast(iso.gsi), iso.flags); + setGSIRedirect(lapic_id, vector, @intCast(iso.gsi), iso.flags, enable); return; } } - setGSIRedirect(lapic_id, vector, irq, 0); + setGSIRedirect(lapic_id, vector, irq, 0, enable); } diff --git a/kernel/arch/x86_64/cpu.zig b/kernel/arch/x86_64/cpu.zig index 514c9a3..b28e0eb 100644 --- a/kernel/arch/x86_64/cpu.zig +++ b/kernel/arch/x86_64/cpu.zig @@ -14,8 +14,7 @@ pub const CpuLocal = struct { this: *CpuLocal, id: usize, - idle_thread: *sched.Thread, - current_thread: *sched.Thread, + current_thread: ?*sched.Thread, lapic_id: u32, lapic_freq: u64, @@ -29,12 +28,9 @@ pub const CpuLocal = struct { pub const stack_size = 0x10000; // 64KiB pub const stack_pages = stack_size / std.mem.page_size; - pub inline fn is_idle(self: *const CpuLocal) bool { - return self.current_thread == self.idle_thread; - } - pub fn initCpu(self: *CpuLocal, is_bsp: bool) void { self.this = self; + self.current_thread = null; gdt.reload(); idt.reload(); @@ -45,11 +41,6 @@ pub const CpuLocal = struct { x86.wrmsr(.gs_base, @intFromPtr(self)); x86.wrmsr(.kernel_gs_base, @intFromPtr(self)); - const idle_thread = root.allocator.create(sched.Thread) catch unreachable; - idle_thread.process = sched.kernel_process; - self.idle_thread = idle_thread; - self.current_thread = idle_thread; - const common_int_stack_phys = pmm.alloc(stack_pages, true) orelse unreachable; const common_int_stack = common_int_stack_phys + stack_size + vmm.hhdm_offset; self.tss.rsp0 = common_int_stack; diff --git a/kernel/arch/x86_64/idt.zig b/kernel/arch/x86_64/idt.zig index c88f0ed..b34c985 100644 --- a/kernel/arch/x86_64/idt.zig +++ b/kernel/arch/x86_64/idt.zig @@ -99,6 +99,7 @@ const exceptions = [_]?[]const u8{ null, }; +// TODO: replace isr with a interrupt dispatcher func? var isr = [_]InterruptHandler{defaultHandler} ** 256; var next_vector: u8 = exceptions.len; pub var panic_ipi_vector: u8 = undefined; @@ -110,9 +111,8 @@ pub fn init() void { idtr.base = @intFromPtr(&idt); inline for (0..256) |i| { - const handler = comptime makeStubHandler(i); + const handler = makeHandler(i); idt[i] = IDTEntry.init(@intFromPtr(handler), 0, interrupt_gate); - // log.info("init idt[{}] with {}", .{ i, handler }); } setIST(0x0e, 2); // page fault uses IST 2 @@ -218,7 +218,7 @@ fn defaultHandler(ctx: *Context) callconv(.SysV) void { }); } -fn makeStubHandler(vector: u8) *const fn () callconv(.Naked) void { +fn makeHandler(comptime vector: u8) *const fn () callconv(.Naked) void { return struct { fn handler() callconv(.Naked) void { const has_error_code = switch (vector) { @@ -248,6 +248,7 @@ export fn commonStub() callconv(.Naked) void { \\je 1f \\swapgs \\1: + \\cld \\push %r15 \\push %r14 \\push %r13 diff --git a/kernel/arch/x86_64/pit.zig b/kernel/arch/x86_64/pit.zig new file mode 100644 index 0000000..7ee72ba --- /dev/null +++ b/kernel/arch/x86_64/pit.zig @@ -0,0 +1,32 @@ +//! https://wiki.osdev.org/PIT + +const x86 = @import("x86_64.zig"); + +pub const dividend = 1_193_182; +pub const timer_freq = 1000; + +pub fn init() void { + setFrequency(timer_freq); +} + +fn setFrequency(divisor: u64) void { + var count = dividend / divisor; + if (dividend % divisor > divisor / 2) { + count += 1; + } + setReloadValue(@truncate(count)); +} + +pub fn setReloadValue(count: u16) void { + // channel 0, lo/hi access mode, mode 2 (rate generator) + x86.out(u8, 0x43, 0b00_11_010_0); + x86.out(u8, 0x40, @truncate(count)); + x86.out(u8, 0x40, @truncate(count >> 8)); +} + +pub fn getCurrentCount() u16 { + x86.out(u8, 0x43, 0); + const lo = x86.in(u8, 0x40); + const hi = x86.in(u8, 0x40); + return (@as(u16, hi) << 8) | lo; +} diff --git a/kernel/arch/x86_64/x86_64.zig b/kernel/arch/x86_64/x86_64.zig index 9a9fbc3..99c5ea0 100644 --- a/kernel/arch/x86_64/x86_64.zig +++ b/kernel/arch/x86_64/x86_64.zig @@ -1,8 +1,6 @@ -const assert = @import("std").debug.assert; - pub const RFlags = packed struct(u64) { CF: u1 = 0, - reserved: u1 = 1, + reserved0: u1 = 1, PF: u1 = 0, reserved1: u1 = 0, AF: u1 = 0, @@ -23,10 +21,20 @@ pub const RFlags = packed struct(u64) { VIP: u1 = 0, ID: u1 = 0, reserved4: u42 = 0, + + pub inline fn get() RFlags { + return asm volatile ( + \\pushfq + \\pop %[ret] + : [ret] "=r" (-> RFlags), + : + : "memory" + ); + } }; pub const MSR = enum(u32) { - apic = 0x1b, + apic_base = 0x1b, pat = 0x277, fs_base = 0xc0000100, gs_base = 0xc0000101, @@ -53,13 +61,7 @@ pub inline fn enableInterrupts() void { } pub inline fn interruptState() bool { - return asm volatile ( - \\pushfq - \\pop %[ret] - : [ret] "=r" (-> u64), - : - : "memory" - ) & (1 << 9) != 0; + return RFlags.get().IF != 0; } pub inline fn toggleInterrupts(state: bool) bool { @@ -161,7 +163,7 @@ pub inline fn rdmsr(msr: MSR) u64 { \\rdmsr : [_] "={eax}" (low), [_] "={edx}" (high), - : [_] "{ecx}" (msr), + : [_] "{ecx}" (@intFromEnum(msr)), : "memory" ); @@ -174,7 +176,7 @@ pub inline fn wrmsr(msr: MSR, value: u64) void { : : [_] "{eax}" (@as(u32, @truncate(value))), [_] "{edx}" (@as(u32, @truncate(value >> 32))), - [_] "{ecx}" (msr), + [_] "{ecx}" (@intFromEnum(msr)), : "memory" ); } diff --git a/kernel/event.zig b/kernel/event.zig index dded286..f10d323 100644 --- a/kernel/event.zig +++ b/kernel/event.zig @@ -4,11 +4,23 @@ const arch = @import("arch.zig"); const sched = @import("sched.zig"); const SpinLock = root.SpinLock; +// TODO: this can be simplified + pub const Listener = struct { thread: *sched.Thread, which: usize, }; +// TODO +// pub const Events = struct { +// lock: SpinLock, +// events: std.ArrayListUnmanaged(usize), +// // events: struct { +// // pending: usize, +// // listeners: std.ArrayListUnmanaged(Listener), +// // }, +// }; + pub const Event = struct { lock: SpinLock, pending: usize, @@ -51,7 +63,6 @@ pub const Event = struct { } }; -// TODO: this can be simplified pub var int_events: [256]Event = undefined; pub fn init() void { @@ -61,28 +72,31 @@ pub fn init() void { } } -pub fn awaitEvents(events: []*Event, block: bool) isize { +pub fn awaitEvents(events: []*Event, blocking: bool) ?*Event { const old_state = arch.toggleInterrupts(false); defer _ = arch.toggleInterrupts(old_state); - const thread = sched.currentThread(); - lockEvents(events); defer unlockEvents(events); - const i = checkForPending(events); - if (i != -1) return i; - if (!block) return -1; + if (getFirstPending(events)) |event| { + return event; + } + + if (!blocking) { + return null; + } + const thread = sched.currentThread(); attachListeners(events, thread); - sched.dequeue(thread); + sched.dequeue(thread); // re-enqueue when? unlockEvents(events); sched.yieldAwait(); arch.disableInterrupts(); // const ret = if (thread.enqueued_by_signal) -1 else thread.which_event; - const ret = thread.which_event; + const ret = thread.which_event; // TODO lockEvents(events); detachListeners(thread); @@ -95,14 +109,14 @@ fn intEventHandler(ctx: *arch.Context) callconv(.SysV) void { arch.apic.eoi(); } -fn checkForPending(events: []*Event) isize { - for (events, 0..) |event, i| { +fn getFirstPending(events: []*Event) ?*Event { + for (events) |event| { if (event.pending > 0) { event.pending -= 1; - return @intCast(i); + return event; } } - return -1; + return null; } fn attachListeners(events: []*Event, thread: *sched.Thread) void { diff --git a/kernel/fs/initramfs.zig b/kernel/fs/initramfs.zig index 7a59c81..4f1d2a5 100644 --- a/kernel/fs/initramfs.zig +++ b/kernel/fs/initramfs.zig @@ -2,10 +2,12 @@ const std = @import("std"); const root = @import("root"); const log = std.log.scoped(.initramfs); +// TODO: use std.tar.pipeToFileSystem + /// https://wiki.osdev.org/USTAR /// If the first byte of `prefix` is 0, the file name is `name` otherwise it is `prefix/name` const Tar = extern struct { - name: [99:0]u8, // can be 100 bytes long with no sentinel + name: [100]u8, // 0 terminated, can be 100 bytes long with no sentinel mode: [8]u8, uid: [8]u8, gid: [8]u8, @@ -13,17 +15,18 @@ const Tar = extern struct { mtime: [12]u8, checksum: [8]u8, type_flag: std.tar.Header.FileType, - link_name: [99:0]u8, // can be 100 bytes long with no sentinel + link_name: [100]u8, // 0 terminated, can be 100 bytes long with no sentinel magic: [5:0]u8, version: [2]u8, uname: [31:0]u8, gname: [31:0]u8, dev_major: [8]u8, dev_minor: [8]u8, - prefix: [154:0]u8, // can be 155 bytes long with no sentinel + prefix: [155]u8, // 0 terminated, can be 155 bytes long with no sentinel + padding: [12]u8, comptime { - std.debug.assert(@sizeOf(Tar) == 500); + std.debug.assert(@sizeOf(Tar) == 512); } }; @@ -35,10 +38,8 @@ pub fn init() void { const tar: *Tar = @ptrCast(module.address); if (!std.mem.eql(u8, tar.magic[0..], "ustar")) continue; - // TODO - log.debug("file {*} is a tar", .{module.address}); + log.debug("file `{s}` is a tar", .{module.path}); - // TODO const mode = std.fmt.parseUnsigned(u64, tar.mode[0..], 8) catch unreachable; const uid = std.fmt.parseUnsigned(u64, tar.uid[0..], 8) catch unreachable; const gid = std.fmt.parseUnsigned(u64, tar.gid[0..], 8) catch unreachable; diff --git a/kernel/mm/pmm.zig b/kernel/mm/pmm.zig index b226c59..8e23c17 100644 --- a/kernel/mm/pmm.zig +++ b/kernel/mm/pmm.zig @@ -5,6 +5,8 @@ const SpinLock = root.SpinLock; const log = std.log.scoped(.pmm); const page_size = std.mem.page_size; const free_page = false; +// const used_page = 1; +// const cache_page = 2; var bitmap: []bool = undefined; var last_idx: u64 = 0; diff --git a/kernel/mm/vmm.zig b/kernel/mm/vmm.zig index a243cb3..3c81504 100644 --- a/kernel/mm/vmm.zig +++ b/kernel/mm/vmm.zig @@ -57,16 +57,16 @@ pub const PTE = packed struct(u64) { return @as(u64, @bitCast(self)) & 0xf800_0000_0000_0fff; } - inline fn getNextLevel(self: *PTE, allocate: bool) ?[*]PTE { + inline fn getNextLevel(self: *PTE, allocate: bool) MapError![*]PTE { if (self.present) { return @ptrFromInt(self.getAddress() + hhdm_offset); } if (!allocate) { - return null; // TODO return error + return error.NotMapped; } - const new_page_table = pmm.alloc(1, true) orelse return null; // TODO return OOM + const new_page_table = pmm.alloc(1, true) orelse return error.OutOfMemory; self.* = @bitCast(new_page_table | present | writable | user); return @ptrFromInt(new_page_table + hhdm_offset); } @@ -136,8 +136,8 @@ const Addr2Range = struct { // TODO: rename Pagemap? pub const AddressSpace = struct { pml4: *[512]PTE, - lock: SpinLock, - mmap_ranges: std.ArrayListUnmanaged(*MMapRangeLocal), + lock: SpinLock = .{}, + mmap_ranges: std.ArrayListUnmanaged(*MMapRangeLocal) = .{}, pub fn init() !*AddressSpace { const addr_space = try root.allocator.create(AddressSpace); @@ -159,7 +159,7 @@ pub const AddressSpace = struct { if (level == 0) return; for (start..end) |i| { - const next_level = pml[i].getNextLevel(false) orelse unreachable; // TODO: continue + const next_level = pml[i].getNextLevel(false) catch unreachable; // TODO: continue destroyLevel(next_level, 0, 512, level - 1); } @@ -201,8 +201,8 @@ pub const AddressSpace = struct { try global_range.locals.append(root.allocator, new_local_range); var i = local_range.base; while (i < local_range.base + local_range.length) : (i += page_size) { - const old_pte = self.virt2pte(i, false) orelse unreachable; // TODO: continue? - const new_pte = new_addr_space.virt2pte(i, true) orelse unreachable; // TODO: free + const old_pte = self.virt2pte(i, false) catch unreachable; // TODO: continue? + const new_pte = new_addr_space.virt2pte(i, true) catch unreachable; // TODO: free new_pte.* = old_pte.*; } } else { @@ -224,10 +224,10 @@ pub const AddressSpace = struct { var i = local_range.base; while (i < local_range.base + local_range.length) : (i += page_size) { - const old_pte = self.virt2pte(i, false) orelse unreachable; // TODO: continue? + const old_pte = self.virt2pte(i, false) catch unreachable; // TODO: continue? if (old_pte.present == false) continue; - const new_pte = new_addr_space.virt2pte(i, true) orelse unreachable; // TODO: free - const new_spte = new_global_range.shadow_addr_space.virt2pte(i, true) orelse unreachable; // TODO: free + const new_pte = new_addr_space.virt2pte(i, true) catch unreachable; // TODO: free + const new_spte = new_global_range.shadow_addr_space.virt2pte(i, true) catch unreachable; // TODO: free const old_page = old_pte.getAddress(); const new_page = pmm.alloc(1, false) orelse unreachable; // TODO: free @@ -243,22 +243,22 @@ pub const AddressSpace = struct { return new_addr_space; } - pub fn virt2pte(self: *const AddressSpace, vaddr: u64, allocate: bool) ?*PTE { + pub fn virt2pte(self: *const AddressSpace, vaddr: u64, allocate: bool) MapError!*PTE { const pml4_idx = (vaddr & (0x1ff << 39)) >> 39; const pml3_idx = (vaddr & (0x1ff << 30)) >> 30; const pml2_idx = (vaddr & (0x1ff << 21)) >> 21; const pml1_idx = (vaddr & (0x1ff << 12)) >> 12; const pml4 = self.pml4; - const pml3 = pml4[pml4_idx].getNextLevel(allocate) orelse return null; - const pml2 = pml3[pml3_idx].getNextLevel(allocate) orelse return null; - const pml1 = pml2[pml2_idx].getNextLevel(allocate) orelse return null; + const pml3 = try pml4[pml4_idx].getNextLevel(allocate); + const pml2 = try pml3[pml3_idx].getNextLevel(allocate); + const pml1 = try pml2[pml2_idx].getNextLevel(allocate); return &pml1[pml1_idx]; } pub fn virt2phys(self: *const AddressSpace, vaddr: u64) MapError!u64 { - const pte = self.virt2pte(vaddr, false) orelse unreachable; + const pte = try self.virt2pte(vaddr, false); if (!pte.present) return error.NotMapped; return pte.getAddress(); } @@ -268,7 +268,7 @@ pub const AddressSpace = struct { defer self.lock.unlock(); // TODO: when virt2pte fails the memory it allocated is not freed - const pte = self.virt2pte(vaddr, true) orelse return error.OutOfMemory; + const pte = try self.virt2pte(vaddr, true); if (pte.present) return error.AlreadyMapped; pte.* = @bitCast(paddr | flags); self.flush(vaddr); @@ -278,7 +278,7 @@ pub const AddressSpace = struct { self.lock.lock(); defer self.lock.unlock(); - const pte = self.virt2pte(vaddr, false) orelse unreachable; // TODO: unreachable? + const pte = try self.virt2pte(vaddr, false); if (!pte.present) return error.NotMapped; pte.* = @bitCast(pte.getAddress() | flags); self.flush(vaddr); @@ -288,7 +288,7 @@ pub const AddressSpace = struct { if (lock) self.lock.lock(); defer if (lock) self.lock.unlock(); - const pte = self.virt2pte(vaddr, false) orelse unreachable; // TODO: unreachable? + const pte = try self.virt2pte(vaddr, false); if (!pte.present) return error.NotMapped; pte.* = @bitCast(@as(u64, 0)); self.flush(vaddr); @@ -453,12 +453,10 @@ pub fn init() void { kaddr_space = root.allocator.create(AddressSpace) catch unreachable; const pml4_phys = pmm.alloc(1, true) orelse unreachable; - kaddr_space.pml4 = @ptrFromInt(pml4_phys + hhdm_offset); - kaddr_space.lock = .{}; - kaddr_space.mmap_ranges = .{}; + kaddr_space.* = .{ .pml4 = @ptrFromInt(pml4_phys + hhdm_offset) }; for (256..512) |i| { - _ = kaddr_space.pml4[i].getNextLevel(true); + _ = kaddr_space.pml4[i].getNextLevel(true) catch unreachable; } kaddr_space.mapSection("text", PTE.present); diff --git a/kernel/ps2.zig b/kernel/ps2.zig index 3316a86..12b82f3 100644 --- a/kernel/ps2.zig +++ b/kernel/ps2.zig @@ -29,7 +29,7 @@ pub fn init() void { } keyboard_vector = idt.allocVector(); - apic.setIRQRedirect(smp.bsp_lapic_id, keyboard_vector, 1); + apic.setIRQRedirect(smp.bsp_lapic_id, keyboard_vector, 1, true); _ = arch.in(u8, 0x60); } diff --git a/kernel/sched.zig b/kernel/sched.zig index a2e845f..2a63a07 100644 --- a/kernel/sched.zig +++ b/kernel/sched.zig @@ -63,8 +63,8 @@ pub const Process = struct { @memset(&process.name, 0); process.addr_space = addr_space.?; // TODO - process.thread_stack_top = 0x70000000000; - process.mmap_anon_base = 0x80000000000; + process.thread_stack_top = 0x0700_0000_0000; + process.mmap_anon_base = 0x0800_0000_0000; // process.cwd = vfs.tree.root.?; process.umask = std.os.S.IWGRP | std.os.S.IWOTH; } @@ -87,7 +87,7 @@ pub const Process = struct { }; pub const Thread = struct { - errno: u64, + errno: usize, tid: usize, lock: SpinLock = .{}, process: *Process, @@ -98,6 +98,7 @@ pub const Thread = struct { enqueued: bool, // enqueued_by_signal: bool, // TODO: for events yield_await: SpinLock = .{}, + // gs_base fs_base: u64, cr3: u64, fpu_storage: u64, @@ -297,8 +298,10 @@ pub const Thread = struct { } }; -/// reschedule every 1ms -pub const timeslice = 1000; +/// reschedule every 5ms +pub const timeslice = 5_000; +/// wait for 10ms if there is no thread +pub const wait_timeslice = 10_000; pub var kernel_process: *Process = undefined; pub var processes: std.ArrayListUnmanaged(*Process) = .{}; // TODO: hashmap with pid? @@ -318,7 +321,7 @@ pub fn init() void { } pub inline fn currentThread() *Thread { - return smp.thisCpu().current_thread; + return smp.thisCpu().current_thread.?; } pub inline fn currentProcess() *Process { @@ -361,10 +364,8 @@ pub fn enqueue(thread: *Thread) !void { sched_lock.unlock(); for (smp.cpus) |cpu| { - // TODO: can this append when a cpu start scheduling causing it to - // reschedule right after - if (cpu.is_idle()) { - apic.sendIPI(cpu.lapic_id, sched_vector); + if (cpu.current_thread == null) { + apic.sendIPI(cpu.lapic_id, .{ .vector = sched_vector }); break; } } @@ -404,12 +405,9 @@ fn schedHandler(ctx: *arch.Context) callconv(.SysV) void { // return; // } - // cpu.active = true; - - const current_thread = currentThread(); const maybe_next_thread = nextThread(); - if (!cpu.is_idle()) { + if (cpu.current_thread) |current_thread| { // current_thread.yield_await.unlock(); // TODO if (maybe_next_thread == null and current_thread.enqueued) { @@ -454,8 +452,7 @@ fn schedHandler(ctx: *arch.Context) callconv(.SysV) void { apic.timerOneShot(timeslice, sched_vector); contextSwitch(&next_thread.ctx); } else { - // cpu.active = false; - cpu.current_thread = cpu.idle_thread; + cpu.current_thread = null; vmm.switchPageTable(vmm.kaddr_space.cr3()); apic.eoi(); wait(); @@ -465,7 +462,7 @@ fn schedHandler(ctx: *arch.Context) callconv(.SysV) void { pub fn wait() noreturn { arch.disableInterrupts(); - apic.timerOneShot(timeslice * 10, sched_vector); + apic.timerOneShot(wait_timeslice, sched_vector); arch.enableInterrupts(); arch.halt(); } @@ -475,8 +472,8 @@ pub fn yield() noreturn { apic.timerStop(); const cpu = smp.thisCpu(); - cpu.current_thread = cpu.idle_thread; - apic.sendIPI(cpu.lapic_id, sched_vector); + cpu.current_thread = null; + apic.sendIPI(cpu.lapic_id, .{ .vector = sched_vector }); arch.enableInterrupts(); arch.halt(); @@ -484,17 +481,17 @@ pub fn yield() noreturn { // TODO pub fn yieldAwait() void { - arch.disableInterrupts(); + std.debug.assert(arch.interruptState() == false); + apic.timerStop(); const thread = currentThread(); - const cpu = smp.thisCpu(); - thread.yield_await.lock(); - apic.sendIPI(cpu.lapic_id, sched_vector); + apic.sendIPI(undefined, .{ .vector = sched_vector, .destination_shorthand = .self }); arch.enableInterrupts(); + // TODO: useless since yield_await should already be unlocked thread.yield_await.lock(); thread.yield_await.unlock(); } diff --git a/kernel/smp.zig b/kernel/smp.zig index 6d39b6c..5cf88c8 100644 --- a/kernel/smp.zig +++ b/kernel/smp.zig @@ -8,8 +8,6 @@ const sched = @import("sched.zig"); const CpuLocal = arch.cpu.CpuLocal; const log = std.log.scoped(.smp); -// TODO: use SYSENTER/SYSEXIT? - pub var bsp_lapic_id: u32 = undefined; // bootstrap processor lapic id pub var cpus: []CpuLocal = undefined; var cpus_started: usize = 0; @@ -24,13 +22,14 @@ pub fn init() void { for (smp.cpus(), cpus, 0..) |cpu, *cpu_local, id| { cpu.extra_argument = @intFromPtr(cpu_local); cpu_local.id = id; - cpu_local.lapic_id = cpu.lapic_id; + if (arch.arch == .x86_64) { + cpu_local.lapic_id = cpu.lapic_id; + } if (cpu.lapic_id != bsp_lapic_id) { cpu.goto_address = initAp; } else { cpu_local.initCpu(true); - log.info("bootstrap processor is online with id: {}", .{cpu_local.id}); _ = @atomicRmw(usize, &cpus_started, .Add, 1, .Release); } @@ -42,13 +41,11 @@ pub fn init() void { } pub fn stopAll() void { - if (cpus_started <= 1) return; - - const self = thisCpu(); - for (cpus) |*cpu| { - if (cpu != self) { - apic.sendIPI(cpu.lapic_id, idt.panic_ipi_vector); - } + if (cpus_started > 0) { + apic.sendIPI(undefined, .{ + .vector = idt.panic_ipi_vector, + .destination_shorthand = .all_excluding_self, + }); } } @@ -62,7 +59,6 @@ fn initAp(smp_info: *limine.SmpInfo) callconv(.C) noreturn { const cpu_local: *CpuLocal = @ptrFromInt(smp_info.extra_argument); cpu_local.initCpu(false); - log.info("processor {} is online", .{cpu_local.id}); _ = @atomicRmw(usize, &cpus_started, .Add, 1, .Release); diff --git a/kernel/time.zig b/kernel/time.zig index 02dd400..e33bbc4 100644 --- a/kernel/time.zig +++ b/kernel/time.zig @@ -1,10 +1,8 @@ -//! https://wiki.osdev.org/PIT -// TODO: move PIT code to arch/x86_64/pit.zig - const std = @import("std"); const root = @import("root"); const arch = @import("arch.zig"); const smp = @import("smp.zig"); +const pit = arch.pit; const idt = arch.idt; const apic = arch.apic; const ev = @import("event.zig"); @@ -60,9 +58,6 @@ pub const Timer = struct { } }; -pub const dividend = 1_193_182; -pub const timer_freq = 1000; - pub var monotonic: timespec = .{}; pub var realtime: timespec = .{}; @@ -73,32 +68,10 @@ pub fn init() void { const boot_time = root.boot_time_request.response.?.boot_time; realtime.sec = boot_time; - setFrequency(timer_freq); + pit.init(); const timer_vector = idt.allocVector(); idt.registerHandler(timer_vector, timerHandler); - apic.setIRQRedirect(smp.bsp_lapic_id, timer_vector, 0); -} - -fn setFrequency(divisor: u64) void { - var count = dividend / divisor; - if (dividend % divisor > divisor / 2) { - count += 1; - } - setReloadValue(@truncate(count)); -} - -pub fn setReloadValue(count: u16) void { - // channel 0, lo/hi access mode, mode 2 (rate generator) - arch.out(u8, 0x43, 0b00_11_010_0); - arch.out(u8, 0x40, @truncate(count)); - arch.out(u8, 0x40, @truncate(count >> 8)); -} - -pub fn getCurrentCount() u16 { - arch.out(u8, 0x43, 0); - const lo = arch.in(u8, 0x40); - const hi = arch.in(u8, 0x40); - return (@as(u16, hi) << 8) | lo; + apic.setIRQRedirect(smp.bsp_lapic_id, timer_vector, 0, true); } fn timerHandler(ctx: *arch.Context) callconv(.SysV) void { @@ -106,7 +79,7 @@ fn timerHandler(ctx: *arch.Context) callconv(.SysV) void { defer apic.eoi(); - const interval: timespec = .{ .nsec = std.time.ns_per_s / timer_freq }; + const interval: timespec = .{ .nsec = std.time.ns_per_s / pit.timer_freq }; monotonic.add(interval); realtime.add(interval); diff --git a/kernel/vfs.zig b/kernel/vfs.zig index 934c4a1..00ceefc 100644 --- a/kernel/vfs.zig +++ b/kernel/vfs.zig @@ -5,7 +5,7 @@ const time = root.time; const SpinLock = root.SpinLock; const log = std.log.scoped(.vfs); -pub const DirectoryEntry = root.os.system.DirectoryEntry; +pub const DirectoryEntry = @import("ubik").dirent; // TODO // TODO pub const DefaultError = error{ @@ -32,7 +32,11 @@ pub const Node = struct { kind: Kind, // TODO: useless since S.IF exist? stat: os.Stat, // TODO mode = 0o666 | S.IFREG by default open_flags: u64 = undefined, // TODO: read/write/append, ... - mount_point: ?*Node = null, // TODO: idk + + // TODO + mount_point: ?*Node = null, + mounted_node: ?*Node = null, + refcount: usize, // TODO lock: SpinLock = .{}, // TODO: use a u64 with flags and lock with atomic OR // status: i32, // TODO @@ -65,7 +69,8 @@ pub const Node = struct { // closedir // free_context_dir // rewinddir - readdir: *const fn (node: *Node, index: usize) ReadDirError!*DirectoryEntry = @ptrCast(&stubFn), + // TODO: use a stream for DIR + // readdir: *const fn (node: *Node, index: usize) ReadDirError!*DirectoryEntry = @ptrCast(&stubFn), open: *const fn (node: *Node, flags: u64) OpenError!void = @ptrCast(&stubFn), close: *const fn (node: *Node) void = @ptrCast(&stubFn), @@ -244,6 +249,9 @@ pub const Node = struct { // if (self.redirection) |redirection| { // return getEffectiveNode(redirection, follow_symlinks); // } + if (self.mounted_node) |mounted_node| { + return getEffectiveNode(mounted_node, follow_symlinks); + } if (self.mount_point) |mount_point| { return getEffectiveNode(mount_point, follow_symlinks); } @@ -259,6 +267,7 @@ pub const Node = struct { // TODO: lock defer unlock by default for everything // TODO: modify atime too? // TODO: asserts + // TODO: call getEffectiveNode and use it instead of self? pub inline fn readlink(self: *Node, buf: []u8) ReadLinkError!void { if (self.kind != .symlink) return error.IsNotLink; @@ -314,6 +323,14 @@ pub const Node = struct { pub inline fn stat(self: *Node, statbuf: *os.Stat) StatError!void { return self.vtable.stat(self, statbuf); } + + pub fn writePath(self: *Node, writer: anytype) !void { + if (self.parent) |parent| { + try parent.writePath(writer); + try writer.writeAll(std.fs.path.sep_str); + } + try writer.writeAll(self.name); + } }; // TODO: unused @@ -383,7 +400,6 @@ pub fn mount(parent: *Node, source: ?[]const u8, target: []const u8, fs_name: [] _ = parent; vfs_lock.lock(); defer vfs_lock.unlock(); - // TODO } @@ -429,31 +445,17 @@ pub fn unlink(parent: *Node, name: []const u8) DefaultError!void { return parent.vtable.unlink(parent, name); } -fn makePath(path: []const u8, fs_name: []const u8) !*Node { - if (!std.fs.path.isAbsolute(path)) return error.PathIsNotAbsolute; - const fs = filesystems.get(fs_name) orelse return error.UnknownFileSystem; - _ = fs; - - var node = root_node; - var iter = std.mem.tokenizeScalar(u8, path, std.fs.path.sep); - 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 Node.init(); // TODO fs.create - gop.value_ptr.* = new_node; - node = new_node; - } - } - return node; -} +const Entry = struct { + name: []u8, + file: ?*Node = null, // inode + // device: ?[]u8 = null, + // fs_type: ?[]u8 = null, +}; // 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(); @@ -465,39 +467,41 @@ fn makePath(path: []const u8, fs_name: []const u8) !*Node { // 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 = try root.allocator.create(Entry); +// entry.* = .{ .name = try root.allocator.dupe(u8, component) }; +// gop.value_ptr.* = entry; +// // TODO +// // node = tree.insert(node, entry); +// // node = entry; // } // } // // 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: yet another different implem of mount +// fn mount(source: *Node, target: *Node) void { +// // lock? +// std.debug.assert(target.mounted_node == null); +// std.debug.assert(source.parent == undefined); + +// target.mounted_node = source; +// source.parent = target.parent; +// } + // TODO: rework const Path2Node = struct { target_parent: *Node, diff --git a/lib/ubik.zig b/lib/ubik.zig index 4141383..069eb93 100644 --- a/lib/ubik.zig +++ b/lib/ubik.zig @@ -3,6 +3,8 @@ const std = @import("std"); const linux = std.os.linux; +pub const PATH_MAX = 4096; + pub const T = linux.T; pub const S = linux.S; pub const E = linux.E; @@ -10,6 +12,7 @@ pub const PROT = linux.PROT; pub const MAP = linux.MAP; pub const DT = linux.DT; pub const O = linux.O; +pub const SIG = linux.SIG; // TODO: rename those the zig way? pub const blkcnt_t = linux.blkcnt_t; @@ -68,7 +71,7 @@ pub const Stat = extern struct { birthtim: timespec, }; -pub const DirectoryEntry = extern struct { +pub const dirent = extern struct { ino: ino_t, off: off_t, reclen: u16,