← Blog

All Five HAL Contracts: How sigilOS Binds Drivers to the Kernel

June 22, 2026 · sigil-kernel · Sigil-Docs
kernel hal drivers capabilities 0.6.0

The CLS_BUS seam lands today, completing the five-contract Hardware Abstraction Layer that governs how sigilOS binds real hardware drivers. Every device class — input, storage, USB, power management, and now PCI bus — has a defined kernel-side contract: a fixed function signature, a capability gate, and a QEMU-verifiable model. Real silicon plugs in; the kernel doesn't change.

CLS_INPUT
HID / keyboard / mouse
inputhal.sg
CLS_STORAGE
block device / NVMe / SD
storhal.sg
CLS_USBHOST
USB host controller
usbhal.sg
CLS_POWER
PSCI / ACPI power state
powerhal.sg
CLS_BUS
PCI cfg / BAR / I²C
bushal.sg

The contract pattern

Every HAL seam uses the same structure. The kernel side defines a routing function:

bus_route(id, op, a0, a1, a2, need)

Where id is the bound driver slot, op is the operation code, a0–a2 are operation-specific arguments, and need is the required capability. Before doing anything, bus_route checks cap_check(need). If the caller doesn't hold CAP_BUS, it returns E_PERM immediately — no operation is performed, no state is read, no address is touched.

This is the same pattern as power_route (CLS_POWER) and every other HAL seam. The capability check is not a suggestion — it is the first instruction in the dispatch path.

The driver side implements three functions:

Three real backends exist: AArch64 ECAM (memory-mapped config space), x86 CF8/CFC port-I/O, and I²C SMBus. All three implement the same three functions. The kernel doesn't know which one is bound — it calls through the HAL and gets the right answer.


CLS_BUS in detail

core/bushal.sg defines the kernel-side dispatch. modules/busmodel.sg is the QEMU-side model: a 4-entry PCI config table at 0x3C0000, each entry holding bdf, vid:did, command:status, class:rev, BAR0, and BAR1. This is enough to smoke-test every HAL operation without real PCI hardware:

Test stepWhat it verifiesResult
initAdd 2 simulated PCI devices to the bus modelinit=1
cfg_readRead vid:did and class:rev from device 0read=1
cfg_writeWrite command register, read back to confirm round-tripwrite=1
map_barRetrieve BAR0 and BAR1 base addressesbar=1
cap gateCall with wrong capability → E_PERM, no read performedgate=1

Serial output: BUS init=1 read=1 write=1 bar=1 gate=1 K PASS.


Why five contracts, why now

A traditional kernel HAL is implicit — the kernel calls into driver code that was compiled against a set of headers. There's no runtime check that the driver implements the right interface, and nothing stops a driver from calling back into kernel internals it wasn't supposed to touch.

sigilOS's HAL contracts make the interface explicit and the boundary enforceable:

The five contracts cover every hardware class the 0.6.0 milestone requires. Input handles HID from USB keyboards, mice, and Bluetooth game controllers. Storage handles the block layer for FAT, NTFS, and the FS stack. USB host handles the xHCI and dwc2 controllers that enumerate the device tree. Power handles PSCI (AArch64) and ACPI (x86) for suspend/resume and shutdown. Bus handles PCI config space and I²C, which is the discovery mechanism for everything that isn't USB.


What's next

The HAL contracts are kernel-side seams — they define what the kernel expects. The Drivers repo (sigil-drivers) is where the real implementations live. The USB UHCI control schedule and device enumeration have already landed (504022a). The remaining 0.6.0 driver work is OHCI and UVC (camera). Both can now develop against a defined contract with a QEMU model that proves compliance before any hardware is touched.