danos/system/devices/device-abi.zig

77 lines
3.4 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,
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);
/// 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
hid_len: u64,
resource_count: u64,
hid: [8]u8,
resources: [maximum_device_resources]ResourceDescriptor,
};