diff --git a/boot/efi.zig b/boot/efi.zig index 6b9aa91..8ce96e8 100644 --- a/boot/efi.zig +++ b/boot/efi.zig @@ -63,9 +63,9 @@ fn boot() !noreturn { const entry = try loadKernel(bs, &boot_information); - // Best effort: a volume without sbin/init still boots (kernel-only). + // Best effort: a volume without /system/services/init still boots (kernel-only). loadInit(bs, &boot_information) catch |err| { - log("danos: no sbin/init ("); + log("danos: no /system/services/init ("); logBytes(@errorName(err)); log(") - booting without user space\r\n"); }; @@ -389,13 +389,13 @@ fn loadFile(bs: *uefi.tables.BootServices, name: [*:0]const u16) ![]u8 { return image[0..size]; } -/// Ferry the init program (sbin/init) to the kernel. The kernel does the ELF +/// Ferry the init program (/system/services/init) to the kernel. The kernel does the ELF /// loading itself (into ring-3 mappings) — the loader just carries the bytes. fn loadInit(bs: *uefi.tables.BootServices, boot_information: *BootInformation) !void { const image = try loadFile(bs, init_file_name); boot_information.init_base = @intFromPtr(image.ptr); boot_information.init_len = image.len; - log("danos: sbin/init loaded\r\n"); + log("danos: /system/services/init loaded\r\n"); } /// Ferry the initial_ramdisk (the VFS server + drivers) to the kernel, same as init. diff --git a/docs/driver-model.md b/docs/driver-model.md index 565fdef..d940ae5 100644 --- a/docs/driver-model.md +++ b/docs/driver-model.md @@ -99,21 +99,21 @@ danos already has one of each: `library/runtime/device.zig` is a logic module, and its clients. The pattern generalises directly: ``` -lib/ - rt.zig module "rt" — syscalls, heap, ipc, dev, stdio - mmio.zig module "mmio" — volatile register access + barriers [M14] +library/ + runtime/ module "runtime" — syscalls, heap, ipc, device, stdio + mmio/ module "mmio" — volatile register access + barriers [M14] bus/ - pci.zig module "pci" — ECAM, BAR decode, capability walk - usb.zig module "usb" — descriptors, control transfers, hubs + pci/ module "pci" — ECAM, BAR decode, capability walk + usb/ module "usb" — descriptors, control transfers, hubs proto/ - vfs.zig module "proto.vfs" (today: system/services/vfs/protocol.zig) - block.zig module "proto.block" - hid.zig module "proto.hid" + vfs/ module "vfs-protocol" (today: system/services/vfs/protocol.zig) + block/ module "block-protocol" + hid/ module "hid-protocol" -sbin/ - xhcid.zig HCD + bus driver imports rt, pci, usb, mmio - usbhid.zig class driver imports rt, usb, proto.hid - blockd.zig class driver imports rt, proto.block +system/drivers/ one sub-project each → /system/drivers (no `d` suffix) + xhci/ HCD + bus driver imports runtime, pci, usb, mmio + usb-hid/ class driver imports runtime, usb, hid-protocol + block/ class driver imports runtime, block-protocol ``` The only build change needed: [`addUserBinary`](build.zig) currently takes exactly one diff --git a/docs/vision.md b/docs/vision.md index 9314bd4..31a70c9 100644 --- a/docs/vision.md +++ b/docs/vision.md @@ -84,13 +84,13 @@ interrupts](interrupts.md), a [calibrated timer + ns clock](device-interrupts.md in-kernel [IPC channels](ipc.md), SMP (all cores scheduling, with affinity), a **higher-half kernel** with a physmap, and **user space**: per-process address spaces, `syscall`/`sysret` with the `swapgs` discipline, a user-ELF loader, and -`/sbin/init` — a real user ELF built from `sbin/`, running at CPL 3 as PID 1 on its +`/system/services/init` — a real user ELF built from `system/services/init/`, running at CPL 3 as PID 1 on its own page tables — plus a [test harness](testing.md). - **Isolation track** — **user mode + address-space isolation**. *Done: a higher-half kernel with a physmap (the low half is user space), per-process address spaces with CR3 switched on context switch, the `swapgs` discipline, - `syscall`/`sysret`, a user-ELF loader, and `/sbin/init` running as a real + `syscall`/`sysret`, a user-ELF loader, and `/system/services/init` running as a real preemptive ring-3 process (PID 1). Remaining polish: an address-space/stack reaper for exited tasks, SMAP + fault-recovering copy-in/out, the real IPC syscalls (IPC_Call/IPC_ReplyWait — they arrive with the second user server), diff --git a/system/boot-handoff.zig b/system/boot-handoff.zig index b379d71..1ce2d87 100644 --- a/system/boot-handoff.zig +++ b/system/boot-handoff.zig @@ -142,7 +142,7 @@ pub const BootInformation = extern struct { /// A device-tree boot path leaves this 0 and (later) fills a `device_tree_blob` /// field instead, so the kernel discovers devices without knowing what booted it. acpi_rsdp: u64 = 0, - /// The raw `/sbin/init` ELF image, read off the boot volume by the loader + /// The raw `/system/services/init` ELF image, read off the boot volume by the loader /// into memory that survives the handoff (classified reserved, so the kernel /// identity-maps it and never allocates over it). 0/0 = no init found — the /// kernel boots without user space. Grows into a full initial_ramdisk handoff later. diff --git a/system/drivers/bus/bus.zig b/system/drivers/bus/bus.zig index e3decf8..07e9d33 100644 --- a/system/drivers/bus/bus.zig +++ b/system/drivers/bus/bus.zig @@ -1,4 +1,4 @@ -//! /sbin/bus — a user-space **bus driver**, and the smallest honest example of one. +//! /system/drivers/bus — a user-space **bus driver**, and the smallest honest example of one. //! //! A bus driver owns a device that *contains other devices*, enumerates them by some //! bus-specific protocol, and publishes each one into the kernel's device table so a diff --git a/system/drivers/hpet/hpet.zig b/system/drivers/hpet/hpet.zig index 1ee70b2..676806e 100644 --- a/system/drivers/hpet/hpet.zig +++ b/system/drivers/hpet/hpet.zig @@ -1,4 +1,4 @@ -//! /sbin/hpet — a user-space HPET driver. It proves the whole driver model end to +//! /system/drivers/hpet — a user-space HPET driver. It proves the whole driver model end to //! end: enumerate the device table, find the HPET, claim it, map its registers into //! this ring-3 address space (strong-uncacheable), **bind its interrupt to an IPC //! endpoint**, then sit blocked in `replyWait` until the hardware wakes it. diff --git a/system/kernel/kernel.zig b/system/kernel/kernel.zig index 76b13d9..d7e1f89 100644 --- a/system/kernel/kernel.zig +++ b/system/kernel/kernel.zig @@ -272,18 +272,18 @@ fn kmain(boot_information: *const BootInformation) noreturn { log.checkpoint(cp_running); status("kernel initialised.\n"); - // Hand over to user space: load /sbin/init (read off the boot volume by the + // Hand over to user space: load /system/services/init (read off the boot volume by the // loader) and spawn it as a real ring-3 process, PID 1. It runs on its own // address space, preemptively, alongside the kernel — no cooperative // borrowing. This boot context then becomes the BSP's idle loop. if (boot_information.init_len != 0) { - status("starting /sbin/init...\n"); + status("starting /system/services/init...\n"); const image = @as([*]const u8, @ptrFromInt(boot_handoff.physicalToVirtual(boot_information.init_base)))[0..boot_information.init_len]; process.spawnProcess(image, 4) catch |err| { - statusPrint("/sbin/init failed to load: {s}\n", .{@errorName(err)}); + statusPrint("/system/services/init failed to load: {s}\n", .{@errorName(err)}); }; } else { - status("no /sbin/init on the boot volume.\n"); + status("no /system/services/init on the boot volume.\n"); } // Spawn the extra user binaries the loader ferried in the initial_ramdisk (the VFS @@ -294,7 +294,7 @@ fn kmain(boot_information: *const BootInformation) noreturn { // Become the idle task: drop below every real task and halt until an // interrupt. The timer keeps preempting into init and any other work. scheduler.setPriority(0); - status("\nkernel idle; /sbin/init is running.\n"); + status("\nkernel idle; /system/services/init is running.\n"); architecture.halt(); } @@ -311,7 +311,7 @@ fn startInitialRamdiskBinaries(boot_information: *const boot_handoff.BootInforma var i: u32 = 0; while (i < rd.count) : (i += 1) { const item = rd.entry(i) orelse continue; - statusPrint("starting /sbin/{s} (from initial_ramdisk)...\n", .{item.name}); + statusPrint("starting {s} (from initial-ramdisk)...\n", .{item.name}); process.spawnProcess(item.blob, 4) catch |err| { statusPrint("initial_ramdisk: {s} failed to load: {s}\n", .{ item.name, @errorName(err) }); }; diff --git a/system/kernel/process.zig b/system/kernel/process.zig index f1409c0..4e9a3d6 100644 --- a/system/kernel/process.zig +++ b/system/kernel/process.zig @@ -3,7 +3,7 @@ //! loader; in-kernel code is linked into the kernel image, not loaded here. //! //! Two entry points: -//! - `spawnProcess` loads a user ELF (`/sbin/init`, and later servers/drivers) +//! - `spawnProcess` loads a user ELF (`/system/services/init`, and later servers/drivers) //! into a fresh address space and schedules it as a real preemptive ring-3 //! process on its own page tables. This is the production path. //! - `run` executes a raw code blob (the user-pf isolation test program) on the @@ -448,7 +448,7 @@ pub fn run(blob: []const u8) RunError!void { pmm.free(stack_frame); } -// --- user ELF loading (/sbin/init) ------------------------------------------ +// --- user ELF loading (/system/services/init) ------------------------------------------ pub const InitError = error{ BadElf, // malformed/inapplicable image (magic, class, machine, type, bounds) diff --git a/system/kernel/tests.zig b/system/kernel/tests.zig index 7a39375..db23afa 100644 --- a/system/kernel/tests.zig +++ b/system/kernel/tests.zig @@ -868,7 +868,7 @@ fn procWorker() void { scheduler.exit(); } -/// Real processes: load /sbin/init as TWO scheduled ring-3 processes, each with +/// Real processes: load /system/services/init as TWO scheduled ring-3 processes, each with /// its own address space at the same virtual addresses, running concurrently /// with a kernel task. Both must make heartbeat syscalls from CPL 3 — which can /// only happen if each runs on its own page tables (CR3 switched correctly per @@ -876,7 +876,7 @@ fn procWorker() void { /// strongest cheap proof of address-space isolation. fn processTest(boot_information: *const BootInformation) void { log("DANOS-TEST-BEGIN: process\n", .{}); - check("bootloader handed over sbin/init", boot_information.init_len != 0); + check("bootloader handed over /system/services/init", boot_information.init_len != 0); if (boot_information.init_len == 0) { result(); return; @@ -920,14 +920,14 @@ fn userPfTest() void { log("DANOS-TEST-RESULT: FAIL (user read of kernel memory did not fault)\n", .{}); } -/// The full PID-1 path: the bootloader read sbin/init off the boot volume and +/// The full PID-1 path: the bootloader read /system/services/init off the boot volume and /// handed it over; load it as a user ELF and spawn it as a real ring-3 process /// — the same call the normal boot path makes — then confirm it beats. init /// heartbeats forever, so this proves it reaches ring 3, makes repeated syscalls /// (write + sleep), and stays alive rather than exiting. fn initTest(boot_information: *const BootInformation) void { log("DANOS-TEST-BEGIN: init\n", .{}); - check("bootloader handed over sbin/init", boot_information.init_len != 0); + check("bootloader handed over /system/services/init", boot_information.init_len != 0); if (boot_information.init_len == 0) { result(); return; diff --git a/system/services/init/init.zig b/system/services/init/init.zig index 493b615..00901d3 100644 --- a/system/services/init/init.zig +++ b/system/services/init/init.zig @@ -1,5 +1,5 @@ -//! /sbin/init — the first user-space program, PID 1. Built as its own -//! freestanding binary (see build.zig), shipped on the boot volume at sbin/init, +//! /system/services/init — the first user-space program, PID 1. Built as its own +//! freestanding binary (see build.zig), shipped on the boot volume at /system/services/init, //! loaded by the bootloader, and started in ring 3 as a scheduled process by the //! kernel (system/kernel/process.zig). It links against the shared user runtime //! library `runtime` and talks to the kernel only through `runtime`'s system_call wrappers. diff --git a/system/services/vfs/vfs-test.zig b/system/services/vfs/vfs-test.zig index 1ad0361..f30afd6 100644 --- a/system/services/vfs/vfs-test.zig +++ b/system/services/vfs/vfs-test.zig @@ -1,4 +1,4 @@ -//! /sbin/vfstest — a client that proves the VFS round trip end to end: open a +//! /system/services/vfs/vfs-test — a client that proves the VFS round trip end to end: open a //! file through the `runtime` file API, write to it, seek back, read it, and compare. //! On success it heartbeats "vfstest: ok" so the kernel test can observe it; //! on failure it reports what went wrong. Shipped in the initial_ramdisk alongside vfs. diff --git a/test/qemu_test.py b/test/qemu_test.py index 922610c..ef0e41e 100644 --- a/test/qemu_test.py +++ b/test/qemu_test.py @@ -169,12 +169,12 @@ CASES = [ {"name": "user-pf", "expect": r"page fault \(vector 14\)[\s\S]*error code : 0x5[\s\S]*IP\s*: 0x00007000000000", "fail": r"DANOS-TEST-RESULT: FAIL"}, - # The real user binary: the bootloader ships sbin/init off the ESP, the + # The real user binary: the bootloader ships /system/services/init off the ESP, the # kernel loads the ELF and runs it in ring 3, and it writes + exits cleanly. {"name": "init", "expect": r"DANOS-TEST-RESULT: PASS", "fail": r"DANOS-TEST-RESULT: FAIL"}, - # Real processes: /sbin/init loaded as a scheduled ring-3 process with its + # Real processes: /system/services/init loaded as a scheduled ring-3 process with its # own address space, run twice (create/exit/teardown/recreate), coexisting # with a kernel task under preemption. {"name": "process",