Impossible OS Docs

APIC and Interrupt Routing

What is it?

The APIC is the x86 interrupt controller: a local APIC in every CPU delivers interrupts and timer ticks, and an I/O APIC routes device interrupt lines to them. Impossible OS routes interrupts through the APIC, falling back to the legacy PIC only on a PC-compatible platform whose I/O APIC fails, and has a working local APIC, one I/O APIC, a calibrated timer and a dynamic vector allocator. This roadmap adds the advanced layer: x2APIC mode, MSI vector helpers, cross-CPU TLB shootdown, an NMI watchdog and an interrupt profiler. None of its six sections is complete.

How does it work?

Local APIC. lapic_init() in lapic.c maps the APIC registers uncached, enables the APIC, masks every local vector table entry and logs LAPIC enabled: base=..., ID=..., ver=..., maxLVT=.... Registers are reached through memory-mapped I/O (xAPIC mode), so APIC IDs are 8 bits wide. Inter-processor interrupts go through lapic_send_ipi() and its variants, and the reserved vectors live in one table, vectors.h, with compile-time uniqueness checks.

I/O APIC. ioapic.c drives a single I/O APIC under a lock: ioapic_route_irq() programs a redirection entry, ioapic_isa_to_gsi() applies the ACPI interrupt source overrides, and mask, unmask and destination calls follow. If the I/O APIC does not respond, a PC-compatible platform falls back to the 8259 PIC (and the PIT for the tick); a platform whose firmware declares no PIC halts instead, since devices would otherwise never interrupt.

Vectors and handlers. irq.c hands out vectors 0x30 to 0xEF with irq_alloc_vector(), lets drivers request a global system interrupt with irq_request_gsi_ex() (shared chains allowed), sets affinity and counts interrupts per vector. On a shared line, a vector that keeps firing while every handler reports it was not theirs is quarantined; an interrupt a handler keeps claiming without clearing is not caught.

Timer calibration. lapic_timer_calibrate() tries three tiers in order: a frequency the hypervisor or CPUID reports directly, then a measurement against the HPET or ACPI PM timer, then the legacy PIT when the platform still has one. Each result must pass a plausibility check, and the log names the tier that succeeded. timer.c then starts the tick at 100 Hz.

flowchart LR
    D[Device] --> IO[I/O APIC: route GSI]
    M[MSI device] -->|message write| L
    IO --> L[Local APIC per CPU]
    L --> V[IDT vector 0x30-0xEF]
    V --> H[irq handler chain]
    L -->|IPI 0xF9-0xFD| O[Other CPUs]

CPUs above ID 255. Because the APIC runs in xAPIC mode, the MADT parser in acpi.c skips processors whose x2APIC ID does not fit in 8 bits, and if the boot CPU is one of them it logs x2APIC mode required; forcing BSP-only, no AP bringup.

What are its interfaces?

Interface Purpose
lapic_init(), lapic_send_ipi(), lapic_send_ipi_all_but_self() Local APIC setup and IPIs (lapic.h)
lapic_timer_calibrate(), lapic_timer_init(), lapic_timer_set_hz() Timer calibration and tick rate
ioapic_route_irq(), ioapic_mask_irq(), ioapic_isa_to_gsi() I/O APIC routing (ioapic.c)
irq_alloc_vector(), irq_request_gsi_ex(), irq_set_affinity(), irq_get_counts() Vectors, handlers, affinity and counts (irq.h)
VECTOR_*, IPI_VECTOR_* Reserved vector map (vectors.h)

How do I use it?

A driver requests its interrupt line and receives a vector; it never programs the I/O APIC directly. The interrupt and timer layer is tested in the boot category by test_irq_timer.c, covering MADT parsing, the ISA-to-vector map, allocator bounds, affinity and calibration state:

bash scripts/test.sh SUITE=boot

At boot, look for the calibration tier line and a LAPIC/IOAPIC line in the serial log; its absence means the machine fell back to the PIC.

What is not implemented yet?

How does it compare with Windows 11 and Linux?

Windows 11 and Linux both run x2APIC where the firmware enables it, flush remote TLBs with IPIs and allocate MSI vectors from a pool; Linux adds an NMI watchdog and /proc/interrupts counts, while Windows keeps per-interrupt timing inside ETW. Impossible OS has the xAPIC base, calibration and vector allocation but no x2APIC, shootdown or watchdog. The roadmap's additions are an NMI watchdog and a readable per-vector time profile.

See also

Impossible OS is free software under the GPL-3.0-only license. Last updated Edit this page on GitHub