Split the system contract into boot-handoff / abi / device-abi

The `system` module (formerly `danos`) had become a grab-bag: it held the
loader<->kernel handoff *and* the kernel<->user ABI *and* the device wire types, in
one module three different audiences imported. Usage proved the seam — the
bootloader never touched the syscall/device ABI, and user space never touched the
boot handoff — so split it by audience, one module per contract:

  system/boot-handoff.zig       loader <-> kernel: BootInformation, Framebuffer,
                                MemoryMap, the VM layout + physicalToVirtual, kernel_abi
  system/abi.zig                kernel <-> user, core: SystemCall, mmap prot flags,
                                page_size, notify_badge_bit, ServiceId
  system/devices/device-abi.zig kernel <-> user, devices: DeviceDescriptor,
                                DeviceClass, ResourceDescriptor, ResourceKind, ...

device-abi is the devices sub-project's public interface, exposed as its own module
the way vfs exposes vfs-protocol — importable by user space, unlike the
kernel-internal device model it also feeds. That collapses a real duplication:
DeviceClass and ResourceKind were defined twice (device-model.zig and the contract,
kept "in sync by hand"); device-model now re-exports them from device-abi, so the
enum a driver matches on and the one the kernel classifies with are one type.

Each import now declares which contract it speaks: the bootloader imports only
boot-handoff; a driver only abi + device-abi (via the runtime); the kernel all
three. This also retires the `system` / `runtime.system` name overlap. page_size
lands in abi (it's part of the mmap contract user space aligns to); the bootloader
keeps its own local 4 KiB constant so it depends on nothing but the handoff.

All 21 importers rewired, docs updated to keep /system mapping to source. Build,
host tests, and the QEMU suite (36/36) all green.
This commit is contained in:
Daniel Samson
2026-07-10 18:08:51 +01:00
parent 47610e8ee2
commit be81394be3
37 changed files with 395 additions and 337 deletions
+5 -5
View File
@@ -14,7 +14,7 @@
//! never assumes a display exists.
const std = @import("std");
const system = @import("system");
const boot_handoff = @import("boot-handoff");
/// The one framebuffer console, valid only when `con_present`.
var con: Console = undefined;
@@ -22,7 +22,7 @@ var con_present: bool = false;
/// Set up the console over `fb`, or mark it absent if there's no usable
/// framebuffer. Clears the screen when present.
pub fn init(fb: system.Framebuffer) void {
pub fn init(fb: boot_handoff.Framebuffer) void {
if (!fb.present()) {
con_present = false;
return;
@@ -58,7 +58,7 @@ const glyph_bytes = glyph_h; // 8 pixels wide => 1 byte per row
const glyph_data = 32; // PSF2 header size
pub const Console = struct {
fb: system.Framebuffer,
fb: boot_handoff.Framebuffer,
cols: u32,
rows: u32,
col: u32 = 0,
@@ -66,12 +66,12 @@ pub const Console = struct {
fg: u32 = 0x00c8_c8c8, // light grey
bg: u32 = 0x0000_0000, // black
pub fn init(fb: system.Framebuffer) Console {
pub fn init(fb: boot_handoff.Framebuffer) Console {
// Reach the framebuffer through the physmap, so the pointer stays valid
// once the low identity map is gone. The base is mapped by both the
// loader's bootstrap tables and paging.init.
var mapped = fb;
if (fb.base != 0) mapped.base = system.physicalToVirtual(fb.base);
if (fb.base != 0) mapped.base = boot_handoff.physicalToVirtual(fb.base);
return .{
.fb = mapped,
.cols = fb.width / glyph_w,