Files
danos/system/devices/device-abi.zig
Daniel Samson 452080e997 Add runtime.time, drop demo drivers, harden TSC timekeeping
Time is a kernel concern in danos: the kernel owns the scheduling timer and
already exposes monotonic time via the clock/sleep/timer_bind syscalls, so a
userspace time service would be a redundant, slower path. This adds the generic
runtime.time module over those syscalls, retires the two demonstration drivers,
reorganizes the milestone docs, and makes the monotonic clock correct on Intel,
AMD, and inside any VM.

runtime.time (library/runtime/time.zig)
- Instant/Duration interface: now, sleep, spin, after, monotonicNanos, available
- a thin layer over system.clock/sleep/timerOnce; unit-tested arithmetic

Remove the demo drivers hpet and bus (a teaching example belongs in the docs,
not shipped in the tree)
- system/drivers/ now holds only real drivers: pci-bus, ps2-bus, usb-xhci-bus
- device-manager end-to-end test repointed to pci-bus (asserts on kernel state:
  the process table and the device tree, not a racy serial marker)
- device_register containment moved to a new in-kernel `containment` test
- the driver-model worked example moved inline into docs/drivers.md

Reorganize milestone docs into topic docs
- m17-m18 / m19-m20 / m21 plans dissolved into process-lifecycle, device-manager,
  discovery, and acpi docs; new docs/power.md and docs/timers.md; ~20 citations
  repointed; plan docs deleted

TSC reliability (apic.zig, smp.zig, cpu.zig, kernel.zig)
- check the invariant-TSC bit (CPUID 0x80000007 EDX[8]) on Intel and AMD
- cross-core "warp" check at SMP bring-up, pairwise BSP<->AP as each core comes up
- fall back to the HPET clocksource when the TSC is not invariant (a bare VM) or
  not synchronized (a warp), switched continuously so time never jumps
- boot log reports the outcome; new tsc-sync test exercises the TSC + warp path

Verified: zig build; zig build test; 60/60 QEMU cases (incl. new containment and
tsc-sync).
2026-07-13 11:56:43 +01:00

91 lines
4.2 KiB
Zig

//! The **device ABI**: the flat, `extern` device types that cross the system_call
//! boundary — what `device_enumerate` hands a user-space driver, what
//! `device_register` takes back. This is the devices sub-project's *public
//! interface*, exposed as its own `device-abi` module the same way the VFS server
//! exposes `vfs-protocol` — so both the kernel and user space depend on the contract
//! by name, and neither reaches into the other's files.
//!
//! It is also the **single source of truth** for `DeviceClass` and `ResourceKind`:
//! the kernel's rich, pointer-based device tree (system/devices/device-model.zig,
//! which user space must never import) re-exports these, so the enum that a driver
//! matches on and the enum the kernel classifies with are the *same* type — no
//! hand-kept "mirror in order" to drift. The core kernel↔user ABI is [[abi]]; the
//! loader↔kernel handoff is [[boot-handoff]].
/// A coarse classification of a device, independent of the describing firmware.
/// Kept small on purpose; refine as real drivers arrive. `enum(u32)` because the
/// `@intFromEnum` value crosses the system_call boundary in `DeviceDescriptor.class`.
pub const DeviceClass = enum(u32) {
/// The synthetic root every discovered device hangs beneath.
root,
processor,
interrupt_controller,
timer,
/// A PCI(e) host bridge — the root of a PCI segment (owns an ECAM window).
pci_host_bridge,
/// A single PCI function.
pci_device,
/// A device named in the ACPI namespace (from the DSDT/SSDT), carrying a
/// hardware ID (`_HID`) and, where static, current resource settings (`_CRS`).
acpi_device,
/// The ACPI tables themselves, published as one node for the user-space acpi
/// service (docs/discovery.md): memory resources over the AML blobs,
/// a broad io_port grant for OperationRegion access, and the SCI interrupt.
/// The one node whose claimant is trusted to run firmware bytecode.
acpi_tables,
unknown,
};
/// The kind of hardware resource a device occupies. `enum(u32)` for the same
/// boundary-crossing reason as `DeviceClass` (see `ResourceDescriptor.kind`).
pub const ResourceKind = enum(u32) {
/// A memory-mapped I/O window: `start` is the physical base, `len` its size.
memory,
/// A legacy I/O-port range: `start` is the first port, `len` the count.
io_port,
/// An interrupt: `start` is the global system interrupt (GSI), `len` is 1.
irq,
/// A range of bus numbers owned by a bridge: `start`..`start+len`.
bus_range,
};
/// One device resource, as handed to a user-space driver (flat, extern).
pub const ResourceDescriptor = extern struct {
kind: u64, // a ResourceKind value
start: u64,
len: u64,
};
pub const maximum_device_resources = 8;
/// `DeviceDescriptor.parent` for a device with no parent — a root of the device tree.
pub const no_parent: u64 = ~@as(u64, 0);
/// `DeviceDescriptor.pci_class` for a device that is not a PCI function. (Zero would be
/// ambiguous: 0x000000 is a real class code, "unclassified device".)
pub const no_pci_class: u64 = ~@as(u64, 0);
/// A device, as snapshotted for user space by `device_enumerate`. A driver scans
/// these to find the hardware it owns, claims it, and maps its MMIO.
///
/// `parent` makes the table a tree rather than a list, which is what a **bus driver**
/// needs: it claims the bus, finds the devices below it, and publishes any it
/// discovers itself with `device_register`. A registered child's resources must lie
/// within its parent's (the kernel enforces this) — that containment is what makes
/// delegation safe, since a device descriptor is otherwise a licence to map physical
/// memory.
pub const DeviceDescriptor = extern struct {
id: u64,
parent: u64, // a device id, or `no_parent`
class: u64, // a DeviceClass value
// The PCI class/subclass/prog-IF triple packed as 0xCCSSPP when this device is a PCI
// function, or `no_pci_class` otherwise. This is how a manager tells *what* a
// `pci_device` is (an xHCI controller, an AHCI controller) — decode the triple into
// names with the pci-class module.
pci_class: u64,
hid_len: u64,
resource_count: u64,
hid: [8]u8,
resources: [maximum_device_resources]ResourceDescriptor,
};