Skip to content

Commit b3bc66d

Browse files
interrupt docs
1 parent 23a43af commit b3bc66d

File tree

3 files changed

+138
-7
lines changed

3 files changed

+138
-7
lines changed

BOOTFLOW.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ void kmain()
5757
preboot_fail("Failed to mount boot drive to VFS!");
5858
}
5959

60-
init_rtl8139();
61-
init_e1000();
6260
netdev_t* network = get_active_network_device();
6361
if (network) {
6462
kprintf("Active network card: %s\n", network->description);
@@ -95,6 +93,8 @@ init_func_t init_funcs[] = {
9593
init_iso9660,
9694
init_devfs,
9795
init_fat32,
96+
init_rtl8139,
97+
init_e1000,
9898
NULL,
9999
};
100100
```
@@ -120,6 +120,8 @@ Each function is executed in sequence with logging.
120120
| 13 | `init_iso9660` | ISO9660 read-only FS |
121121
| 14 | `init_devfs` | /devices virtual filesystem |
122122
| 15 | `init_fat32` | FAT32 support |
123+
| 16 | `init_rtl8139` | Realtek RTL8139 network driver |
124+
| 17 | `init_e1000` | Intel e1000 network driver |
123125

124126
---
125127

INTERRUPTS.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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 |

src/rtl8139.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,13 +275,16 @@ void init_rtl8139() {
275275
kprintf("rtl8139: BAR0 not IO-mapped! Value: 0x%x\n", rtl8139_device.bar_type);
276276
}
277277

278+
interrupts_off();
279+
278280
// Power on and reset
279281
rtl_outb(Config1, 0x0);
280282
rtl_outb(ChipCmd, CMDRESET);
281283
time_t reset_start = time(NULL);
282284
while ((rtl_inb(ChipCmd) & CMDRESET) != 0) {
283285
if (time(NULL) - reset_start >= 3) {
284286
kprintf("RTL8139: Device would not reset within 3 seconds. Faulty hardware? Not enabled.\n");
287+
interrupts_on();
285288
return;
286289
}
287290
}
@@ -347,9 +350,5 @@ void init_rtl8139() {
347350
net->next = NULL;
348351
register_network_device(net);
349352

350-
dprintf("RTL8139 REGISTER DUMP:\n");
351-
for (uint32_t i = 0; i <= 0x6C; i += 4) {
352-
uint32_t val = rtl_inl(i);
353-
dprintf("%02X: %08x\n", i, val);
354-
}
353+
interrupts_on();
355354
}

0 commit comments

Comments
 (0)