5.2 KiB
ACPI
Power management and hardware enumeration via the Advanced Configuration and Power Interface.
BoredOS implements an ACPI subsystem that handles power state transitions, hardware discovery, and I2C device enumeration from the firmware tables. The implementation lives in src/drivers/ACPI/.
Table Discovery
At boot, the kernel requests the RSDP (Root System Description Pointer) from Limine. If the pointer is absent or fails its checksum, the kernel panics - this is a hard requirement, not a graceful fallback.
From the RSDP, the kernel determines which top-level descriptor table to use:
- XSDT (64-bit pointers) - used when RSDP revision ≥ 2 and a valid
xsdt_addressis present. - RSDT (32-bit pointers) - fallback for older firmware.
This selection is handled transparently by acpi_get_sdt(), which walks whichever table is available and returns the first SDT matching a given 4-char signature.
Note
The DSDT is a special case - it is not listed in the XSDT/RSDT. It is instead pointed to directly by the
dsdtfield in the FADT. Useacpi_get_dsdt()to retrieve it.
FADT and ACPI Enable
The FADT (Fixed ACPI Description Table, signature "FACP") is located first. It contains the port addresses needed for power management and the SMI command port used to hand off hardware control from firmware to the OS.
If smi_cmd and acpi_enable are both non-zero, the kernel writes the enable byte to the SMI command port and spins on PM1a_CNT bit 0 until the hardware acknowledges. A timeout here is a fatal error.
MADT and Interrupt Routing
The MADT (Multiple APIC Description Table, signature "APIC") is parsed for Interrupt Source Override entries (type 2). These describe cases where a legacy ISA IRQ is wired to a different GSI on the I/O APIC - for example, IRQ 0 (PIT) may be redirected to GSI 2 on some platforms.
Two functions expose this mapping to the rest of the kernel:
acpi_irq_to_gsi(irq)- returns the GSI for a given IRQ, or the IRQ itself if no override exists.acpi_irq_flags(irq)- returns the polarity and trigger mode flags for the override.
AML Parsing
The DSDT and any SSDTs present in the firmware contain AML (ACPI Machine Language) bytecode describing the hardware namespace. BoredOS does not implement a full AML interpreter - instead src/drivers/ACPI/acpi_aml.c implements a targeted byte-stream walker sufficient for I2C device enumeration and basic power management.
The walker handles:
_HID&_CID- Device identification. Supports inline strings and packed EISAID integers.- Specifically recognizes touchpads/input devices:
PNP0C50,SYNA,ELAN,ALPS.
- Specifically recognizes touchpads/input devices:
_CRS- Current Resource Settings. Scans forI2cSerialBusV2descriptors (large item tag0x8E) to extract slave address and bus speed.- Deep Scanning - If a device lacks a static
_CRS, the walker scans AML methods for literalBufferobjects that contain I2C serial bus descriptors. - Controller Detection - Identifies Intel I2C controllers via HIDs
INTC1040andINTC1043. - Power States - Records presence of
_PS0,_PS3,_PR0,_PR3as flags for power management.
Important
While the walker can find literal buffers inside methods, it still cannot evaluate complex AML logic or dynamic expressions.
I2C Enumeration
acpi_i2c_enumerate() is called during kernel initialization. It performs a comprehensive sweep of the ACPI namespace:
- DSDT Walk: Scans the main DSDT for I2C devices.
- SSDT Walk: Iterates through all Secondary System Description Tables.
- Deep HID Search: Performs a raw byte search across all system tables for
_HIDpatterns and specific EISAIDs (likeSYNA) to catch devices that might be missed by the structured walker.
Devices are recorded in a global table, accessible via:
acpi_i2c_count()- Number of enumerated devices.acpi_i2c_get(index)- Pointer to anaml_i2c_dev_trecord containing the name, HID, slave address, and capabilities.
Shutdown
Performing a clean S5 (soft power-off) requires writing the correct SLP_TYP value to the PM1 Control Block. This value is firmware-specific and must be read from the _S5_ object in the DSDT.
aml_parse_s5() scans the DSDT AML for the _S5_ name and extracts SLP_TYPa and SLP_TYPb, pre-shifted to bit position 10 ready for outw. If the parse fails, the kernel falls back to SLP_TYP = 5, which works on the majority of hardware.
Shutdown sequence
On compliant hardware, step 1 is all that runs and the machine powers off immediately. The remaining steps target known virtual machine implementations that don't respond to standard ACPI.
- Write
SLP_TYPa | SLP_ENtoPM1a_CNT_BLK(andPM1b_CNT_BLKif present). - Write known virtualizer-specific magic values - QEMU (
0x604), VirtualBox (0x4004), Bochs (0xB004), Cloud Hypervisor (0x600) - to trigger their respective shutdown paths. - Disable interrupts and halt indefinitely as a last resort.
Note
The virtualizer ports are sent after the ACPI write deliberately. On real hardware, sending those port values is harmless, but the ordering avoids any ambiguity about what triggered the power-off.