|
| 1 | +# Interrupt Handling in Retro Rocket (AMD64) |
| 2 | + |
| 3 | +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. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +Interrupts in Retro Rocket are composed of three tightly integrated layers: |
| 10 | + |
| 11 | +| Layer | Component | Role | |
| 12 | +|------------|-------------------------|--------------------------------------| |
| 13 | +| IDT | `idt.c` | Sets up the Interrupt Descriptor Table (IDT) and traps | |
| 14 | +| APIC | `apic.c` | Local APIC timer, EOI, spurious interrupt handling | |
| 15 | +| ACPI / MADT| `acpi.c` | Enumerates Local APICs, IOAPICs, IRQ/GSI mappings | |
| 16 | + |
| 17 | +--- |
| 18 | + |
| 19 | +## IDT Initialisation (`idt.c`) |
| 20 | + |
| 21 | +Retro Rocket sets up a full 256-entry Interrupt Descriptor Table, aligned on a 16-byte boundary. The `init_idt()` function: |
| 22 | + |
| 23 | +1. Clears all entries to a known zero state. |
| 24 | +2. Registers `IRQ0` (timer) as a demonstration. |
| 25 | +3. Calls `idt_init()` (defined in `loader.S`) to populate handler stubs. |
| 26 | +4. Loads the IDT via `lidtq`. |
| 27 | + |
| 28 | +The legacy PIC is briefly remapped to avoid IRQ overlaps with CPU exceptions, and then **disabled entirely** if APIC is enabled. |
| 29 | + |
| 30 | +```c |
| 31 | +__asm__ volatile("lidtq (%0)" :: "r"(&idt64)); |
| 32 | +``` |
| 33 | +
|
| 34 | +### All Interrupts Are Initially Masked |
| 35 | +
|
| 36 | +Each IRQ is masked until a handler is explicitly registered using: |
| 37 | +
|
| 38 | +```c |
| 39 | +register_interrupt_handler(irqnum, handler, dev, ctx); |
| 40 | +``` |
| 41 | + |
| 42 | +This design guarantees no spurious IRQs during boot and enforces strict control of enabled sources. |
| 43 | + |
| 44 | +--- |
| 45 | + |
| 46 | +## APIC Handling (`apic.c`) |
| 47 | + |
| 48 | +Retro Rocket assumes all hardware conforms to the AMD64 specification. This includes mandatory support for: |
| 49 | + |
| 50 | +- **Local APIC (LAPIC)**: Per-core interrupt controller for inter-processor signalling and timers. |
| 51 | +- **I/O APIC (IOAPIC)**: Routes external device interrupts to LAPIC via GSIs (Global System Interrupts). |
| 52 | + |
| 53 | +### Key APIC Features |
| 54 | + |
| 55 | +- **LAPIC Base Detection**: Via the ACPI MADT. |
| 56 | +- **Timer Configuration**: One-shot mode, calibrated via TSC. |
| 57 | +- **End-of-Interrupt (EOI)**: Sent with `apic_write(APIC_EOI, 0)` after each interrupt. |
| 58 | +- **Spurious IRQ Handling**: IRQ 7 is handled explicitly and does not send EOI. |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## ACPI & MADT Processing (`acpi.c`) |
| 63 | + |
| 64 | +The ACPI module is responsible for: |
| 65 | + |
| 66 | +- Initialising `uACPI` and parsing the RSDP, RSDT, and MADT tables. |
| 67 | +- Discovering: |
| 68 | + - Local APIC base address (32- or 64-bit form) |
| 69 | + - All LAPIC IDs (active CPUs) |
| 70 | + - All IOAPICs and their GSI ranges |
| 71 | + - Interrupt overrides (e.g. legacy IRQ remapping) |
| 72 | + |
| 73 | +### IRQ to GSI Routing |
| 74 | + |
| 75 | +The system maintains a `pci_irq_routes[]` map of IRQ→GSI mappings with polarity and trigger mode. |
| 76 | + |
| 77 | +Interrupt sources are discovered from: |
| 78 | + |
| 79 | +1. **MADT entries** (APIC table) |
| 80 | +2. **ACPI `_PRT`** entries (`EXT_IRQ` and `IRQ` resources) |
| 81 | +3. Fallback: direct 1:1 IRQ to GSI mapping |
| 82 | + |
| 83 | +This routing is queried using: |
| 84 | + |
| 85 | +```c |
| 86 | +uint32_t irq_to_gsi(uint8_t irq); |
| 87 | +uint8_t get_irq_polarity(uint8_t irq); |
| 88 | +uint8_t get_irq_trigger_mode(uint8_t irq); |
| 89 | +``` |
| 90 | +
|
| 91 | +--- |
| 92 | +
|
| 93 | +## Registering a Handler |
| 94 | +
|
| 95 | +Drivers register handlers with: |
| 96 | +
|
| 97 | +```c |
| 98 | +register_interrupt_handler(uint8_t irq, handler_t fn, device_t dev, void *ctx); |
| 99 | +``` |
| 100 | + |
| 101 | +This: |
| 102 | + |
| 103 | +- Unmasks the interrupt line (GSI) in the APIC. |
| 104 | +- Enables delivery from the specified source. |
| 105 | +- Ensures the handler will be called on interrupt. |
| 106 | + |
| 107 | +If not registered, the line remains masked and ignored. |
| 108 | + |
| 109 | +--- |
| 110 | + |
| 111 | +## Legacy PIC Support (Deprecated) |
| 112 | + |
| 113 | +- Retro Rocket targets only **AMD64 hardware**. There is no support for 32-bit x86. |
| 114 | +- The legacy PIC is only touched briefly during boot for compatibility and **immediately disabled** once APIC initialisation completes. |
| 115 | +- All AMD64 systems (including virtualised environments) must support LAPIC and IOAPIC per specification. |
| 116 | + |
| 117 | +**TL;DR:** APIC is mandatory. |
| 118 | + |
| 119 | +--- |
| 120 | + |
| 121 | +## Terminology |
| 122 | + |
| 123 | +| Term | Meaning | |
| 124 | +|--------------|-----------------------------------------------| |
| 125 | +| IRQ | Legacy interrupt request (ISA, PIC) | |
| 126 | +| GSI | Global System Interrupt (IOAPIC input) | |
| 127 | +| LAPIC | Local Advanced Programmable Interrupt Ctrl. | |
| 128 | +| IOAPIC | I/O Advanced Programmable Interrupt Ctrl. | |
| 129 | +| MADT | Multiple APIC Description Table (ACPI) | |
| 130 | +| PIC | Legacy 8259 Programmable Interrupt Controller | |
0 commit comments