77 lines
3.4 KiB
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,
|
|
};
|