Files
nt-lite/code/hal/hal_apic.c
T

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);
}
}