75 lines
2.6 KiB
C
75 lines
2.6 KiB
C
// hal_apic.c - Local APIC + I/O APIC
|
|
#include <hal_apic.h>
|
|
#include <hal_api.h>
|
|
#include <stdint.h>
|
|
|
|
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);
|
|
}
|
|
}
|