![]() |
Retro Rocket OS
|
Retro Rocket uses a modern, APIC-based interrupt system suitable for 64-bit long mode. It fully supports Symmetric Multiprocessing (SMP) and I/O APICs via ACPI detection, with legacy PIC support deprecated and disabled after boot.
Retro Rocket supports two interrupt delivery mechanisms:
At boot, the kernel attempts to initialise FRED first. If FRED is unavailable or disabled, it falls back to the IDT path.
Interrupts in Retro Rocket are composed of four tightly integrated layers:
| Layer | Component | Role |
|---|---|---|
| Delivery | idt.c, fred.c | Sets up the CPU interrupt delivery mechanism |
| Routing | apic.c | Local APIC timer, EOI, spurious interrupt handling |
| Discovery | acpi.c | Enumerates Local APICs, IOAPICs, IRQ/GSI mappings |
| Dispatch | interrupt.c | Dispatches exceptions and IRQs to registered handlers |
The delivery mechanism determines how the CPU enters the kernel on an interrupt or exception. The routing layer determines how external interrupt sources reach the CPU. Both delivery mechanisms ultimately dispatch into the same higher-level interrupt handling code.
Retro Rocket supports two interrupt delivery mechanisms on AMD64:
| Mechanism | Component | Role |
|---|---|---|
| IDT | idt.c | Traditional descriptor-table-based interrupt delivery |
| FRED | fred.c | Modern MSR-configured interrupt and exception delivery |
The kernel attempts to enable FRED first:
If this fails, it falls back to IDT initialisation.
Both delivery mechanisms share common BSP setup for interrupt handling. This includes:
This avoids duplicating platform interrupt setup while allowing the CPU entry mechanism to differ.
Both IDT and FRED ultimately dispatch into the same higher-level interrupt handling functions in interrupt.c:
This keeps IRQ routing, handler registration, entropy collection, FPU state save/restore, and end-of-interrupt handling consistent regardless of delivery mechanism.
Retro Rocket sets up a full 256-entry Interrupt Descriptor Table, aligned on a 16-byte boundary. The init_idt() function:
The legacy PIC is briefly remapped to avoid IRQ overlaps with CPU exceptions, and then disabled entirely if APIC is enabled.
Each IRQ is masked until a handler is explicitly registered using:
This design guarantees no spurious IRQs during boot and enforces strict control of enabled sources.
Retro Rocket can use Intel FRED as an alternative to IDT-based interrupt delivery on supported CPUs.
FRED uses:
The init_fred() function performs the same BSP interrupt setup as the IDT path, then enables FRED for the current CPU and completes late interrupt initialisation.
FRED support is detected via CPUID before being enabled. FRED is enabled per CPU, and application processors enable it separately during AP startup.
FRED state is not global. Each CPU must enable it independently. The BSP does this during init_fred(), and APs do so during shared interrupt loading.
The low-level FRED entry stubs live in loader.S.
Retro Rocket provides:
The ring 0 entry stub saves general-purpose registers, passes a pointer to the hardware-constructed FRED frame into C, and returns using erets.
The FRED entry page must be laid out exactly as required by the architecture. The configured entry address must point at the start of the page containing the stubs.
On entry, FRED provides a hardware-defined event frame containing saved architectural state and event metadata. Retro Rocket decodes the delivered vector from the FRED frame and dispatches either to Interrupt() or IRQ().
This allows FRED to reuse the same higher-level interrupt and exception handling logic as the IDT path.
The low-level interrupt and exception entry stubs are implemented in loader.S.
For the IDT path, loader.S provides:
These stubs save register state, prepare arguments for the C dispatch layer, call into Interrupt() or IRQ(), restore register state, and return with iretq.
For the FRED path, loader.S also provides the FRED entry-page stubs used by fred.c.
This means loader.S contains the low-level entry machinery for both interrupt delivery mechanisms.
Retro Rocket assumes all hardware conforms to the AMD64 specification. This includes mandatory support for:
APIC is responsible for interrupt routing and delivery to a CPU. It is not responsible for the CPU-side interrupt entry mechanism itself. That role is handled by either the IDT or FRED.
The ACPI module is responsible for:
The system maintains a pci_irq_routes[] map of IRQ→GSI mappings with polarity and trigger mode.
Interrupt sources are discovered from:
This routing is queried using:
Drivers register handlers with:
This:
If not registered, the line remains masked and ignored.
Handlers are ultimately invoked by the common dispatch layer in interrupt.c, regardless of whether the interrupt reached the kernel through IDT or FRED.
TL;DR: APIC is mandatory.
| Term | Meaning |
|---|---|
| IRQ | Legacy interrupt request (ISA, PIC) |
| GSI | Global System Interrupt (IOAPIC input) |
| LAPIC | Local Advanced Programmable Interrupt Ctrl. |
| IOAPIC | I/O Advanced Programmable Interrupt Ctrl. |
| MADT | Multiple APIC Description Table (ACPI) |
| PIC | Legacy 8259 Programmable Interrupt Controller |
| IDT | Interrupt Descriptor Table |
| FRED | Flexible Return and Event Delivery |
| ERETS | FRED return instruction |