// hal_apic.c - Local APIC + I/O APIC #include #include #include extern HAL_API gApi; // ---- Local APIC ---- static volatile uint32_t* gLapic = (volatile uint32_t *)0; #define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off))) #define LAPIC_EOI 0x0B0 #define LAPIC_SPURIOUS 0x0F0 #define LAPIC_ENABLE 0x100 // bit in spurious vector register // ---- I/O APIC ---- static volatile uint32_t* gIoapic = (volatile uint32_t *)0; #define IOAPIC_IDX 0x00 #define IOAPIC_DATA 0x10 static uint32_t IoapicRead(uint8_t reg) { *(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_IDX) = reg; return *(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_DATA); } static void IoapicWrite(uint8_t reg, uint32_t val) { *(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_IDX) = reg; *(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_DATA) = val; } // IRQ n -> redirection table at register 0x10 + 2*n (low), 0x11 + 2*n (high). #define IOREDTBL_LO(n) (0x10 + 2*(n)) #define IOREDTBL_HI(n) (0x11 + 2*(n)) // Interrupt vector base: IRQ 0 -> vector 0x20, IRQ 1 -> 0x21, ... #define IRQ_VECTOR_BASE 0x20 void HalApicRouteIrq(uint8_t irq) { // Full initial setup of the redirection entry. // Sets the vector and clears the mask bit in one write. uint32_t vector = IRQ_VECTOR_BASE + irq; // e.g. IRQ 1 -> vector 0x21 IoapicWrite(IOREDTBL_LO(irq), vector); // unmasked (bit 16 = 0), edge, fixed IoapicWrite(IOREDTBL_HI(irq), 0); // deliver to LAPIC id 0 } void HalApicMaskIrq(uint8_t irq) { uint32_t lo = IoapicRead(IOREDTBL_LO(irq)); lo |= (1 << 16); IoapicWrite(IOREDTBL_LO(irq), lo); } void HalApicUnmaskIrq(uint8_t irq) { uint32_t lo = IoapicRead(IOREDTBL_LO(irq)); lo &= ~(1 << 16); // clear mask bit lo = (lo & ~0xFF) | (IRQ_VECTOR_BASE + irq); IoapicWrite(IOREDTBL_LO(irq), lo); IoapicWrite(IOREDTBL_HI(irq), 0); // LAPIC id 0 } void HalApicSendEoi(void) { LAPIC_REG(LAPIC_EOI) = 0; } void HalApicInitialize(uintptr_t lapicPhys, uintptr_t ioapicPhys) { gLapic = (volatile uint32_t *)(gApi.PhysToVirt(lapicPhys)); gIoapic = (volatile uint32_t *)(gApi.PhysToVirt(ioapicPhys)); // Enable Local APIC, set spurious vector to 0xFF. LAPIC_REG(LAPIC_SPURIOUS) = LAPIC_ENABLE | 0xFF; // Mask all IOAPIC lines initially. uint32_t maxRedir = (IoapicRead(1) >> 16) & 0xFF; for (uint8_t i = 0; i <= maxRedir; i++) { IoapicWrite(IOREDTBL_LO(i), (1 << 16) | (IRQ_VECTOR_BASE + i)); IoapicWrite(IOREDTBL_HI(i), 0); } }