acpi: uACPI, for interrupt routing, the power button and power-off

The firmware's AML is now interpreted. uACPI 6.1.1 (MIT) is fetched by
ports/uacpi, checksum-verified, and compiled into the kernel unmodified,
the same way lwIP is. kernel/acpi/host.c is its host layer: memory,
mapping, port and PCI config I/O, time, mutexes and events that spin
before the scheduler exists, the SCI, and an "acpi" thread for the
work the SCI defers.

PCI interrupts go where the board says. pci_init() now routes every
device's INTx through the root bridge's _PRT before drivers bind. It
follows link devices' _CRS, uses a bridge's own _PRT where the namespace
has one, and swizzles through bridges that don't. Before this, INTx
waited on the 8259's line number, which is the wrong pin in APIC mode.
irq_register() takes a trigger mode rather than a level/low flag,
because q35's links and most SCIs are level, active-high. The MADT's
interrupt source overrides are now parsed, and are what places the SCI.

The power button syncs the filesystems and powers off. shutdown() and
reboot() go through the firmware's S5 and reset register first, and
only then fall back to the emulators' ports, which a real board does
not answer.

Tested under QEMU: q35 with MSI off routes xHCI to GSI 22,
level/active-high, and it takes real interrupts with nothing polled.
system_powerdown powers off q35 and i440fx (QEMU exits 0), and q35
with 4 CPUs boots from NVMe with USB hot-plug working alongside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-22 16:12:28 +02:00
commit 93f981c7ea
16 changed files with 1237 additions and 14 deletions

View file

@ -276,16 +276,20 @@ does not choose how. In order of preference:
2. **MSI-X**, but only if the driver passes `PCI_IRQF_MSIX`. Some parts change
how they report interrupt causes in that mode; the 82574 needs its IVAR
programmed, which `e1000` does not do, so it does not ask.
3. **INTx**, on the line named by the device's `INTERRUPT_LINE` register.
3. **INTx**, on the pin ACPI's `_PRT` names for it.
MSI comes first because INTx on real hardware is **the wrong pin**.
`INTERRUPT_LINE` holds the number the firmware gave the 8259. In APIC mode the
device is wired to an IOAPIC input that only ACPI's `_PRT` describes, and
reading `_PRT` takes an AML interpreter, which SchOS does not have. Under QEMU
the two numbers happen to agree, which is why this went unnoticed until the
drivers were read with a real board in mind.
device is wired to an IOAPIC input that only `_PRT` describes, and reading
`_PRT` takes an AML interpreter. That is uACPI (`ports/uacpi`, host side in
`kernel/acpi/`): `pci_init()` asks it for every device's pin between scanning
the bus and binding drivers, following link devices' `_CRS` and swizzling
through PCI-to-PCI bridges that have no `_PRT` of their own. The trigger mode
comes from there too -- q35's links are level/active-high, which
`irq_register()` could not express until it took a mode rather than a flag.
INTx is therefore backed by the poller in `kernel/dev/irq.c`:
MSI still comes first: it needs no routing at all, and a machine whose AML
does not load still has it. INTx is also backed by the poller in
`kernel/dev/irq.c`:
- A level-triggered line that has had a handler for two seconds and has never
fired gets its handlers called every tick, from a kernel thread with
@ -318,6 +322,17 @@ configurations:
mounted.
- The old INTx path, unchanged on i440fx.
And since `_PRT`: on q35 with MSI disabled, xHCI routed to GSI 22 level/high
and taking real interrupts, with nothing polled.
### Power
uACPI also handles the SCI, the power button and S5. The power button syncs
the filesystems and powers off, from the `acpi` kernel thread rather than the
interrupt; `shutdown()` and `reboot()` go through the FADT's PM1 and reset
registers first, and fall back to the emulators' fixed ports only if the AML
did not load.
---
## `/dev/random` and `/dev/urandom`

View file

@ -172,6 +172,13 @@ Ethernet driver and no infrastructure to speak of. Its port layer is a handful
of files, it has no dependency on the host kernel's allocator or locking, and it
brings ARP, IPv4, ICMP, UDP, TCP, DHCP and DNS.
### uACPI
The AML interpreter, `ports/uacpi`, compiled into the kernel like lwIP.
Verified 2026-10-22 from its `LICENSE`: MIT, Daniil Tatianin. Compatible, one
NOTICE entry. The choice over ACPICA was not about licensing but size: uACPI
asks a host for far less, and its whole host side is `kernel/acpi/host.c`.
### Fonts
Chosen 2026-08-09, both licences checked at source rather than assumed: