#include "aplos.h" enum { APIC_BASE = 0x1B, SPURIOUS_INTERRUPT_VECTOR = 0xF0, END_OF_INTERRUPT = 0xB0 }; static volatile uint32_t *apic_base; static volatile uint8_t *ioapic_reg; static volatile uint32_t *ioapic_data; static uint8_t ioapic_max_entries; static uint32_t read_apic_reg(uint64_t); static void write_apic_reg(uint64_t, uint32_t); static uint32_t read_ioapic_reg(uint8_t); static void write_ioapic_reg(uint8_t, uint32_t); void setup_apic(struct ioapic_info *ioapic) { uint64_t v = get_msr(APIC_BASE); uint64_t addr = v & 0x0000000FFFFFF000; apic_base = (uint32_t *)map_page(addr, 1, false); write_apic_reg(SPURIOUS_INTERRUPT_VECTOR, read_apic_reg(SPURIOUS_INTERRUPT_VECTOR) | 0x1FF); uint8_t *ioapic_base = (uint8_t*)map_page(ioapic->base, 1, false); ioapic_reg = ioapic_base; ioapic_data = (uint32_t*)(ioapic_base+16); ioapic_max_entries = (read_ioapic_reg(1) >> 16)&0xFF; } void apic_end_of_interrupt(void) { write_apic_reg(END_OF_INTERRUPT, 0); } struct ioapic_redirection read_redirection(uint8_t n) { assert(n <= ioapic_max_entries); struct ioapic_redirection r; uint32_t low = read_ioapic_reg(0x10+2*n); uint32_t high = read_ioapic_reg(0x11+2*n); r.vector = low & 0xFF; r.delivery_mode = (low >> 8) & 0x7; r.destination_mode = (low >> 11) & 0x1; r.delivery_status = (low >> 12) & 0x1; r.pin_polarity = (low >> 13) & 0x1; r.remote_irr = (low >> 14) & 0x1; r.trigger_mode = (low >> 15) & 0x1; r.mask = (low >> 16) & 0x1; r.reserved = (low >> 17) & 0xFF; r.reserved |= high & 0xFFFFFF; if(r.destination_mode) r.destination = (high >> 24) & 0xF; else r.destination = (high >> 24) & 0xFF; return r; } void write_redirection(uint8_t n, struct ioapic_redirection r) { uint32_t high, low; high = low = 0; assert(n <= ioapic_max_entries); assert(r.vector >= 0x10 && r.vector <= 0xFE); low |= r.vector & 0xFF; low |= (r.delivery_mode & 0x7) << 8; low |= (r.destination_mode & 0x1) << 11; low |= (r.delivery_status & 0x1) << 12; low |= (r.pin_polarity & 0x1) << 13; low |= (r.remote_irr & 0x1) << 14; low |= (r.trigger_mode & 0x1) << 15; low |= (r.mask & 0x1) << 16; low |= (r.reserved & 0xF) << 17; high |= (r.reserved & 0xFFFFFF00) >> 8; if(r.destination_mode) high |= (r.destination & 0xF) << 24; else high |= (r.destination & 0xFF) << 24; write_ioapic_reg(0x10+2*n, low); write_ioapic_reg(0x11+2*n, high); } static uint32_t read_apic_reg(uint64_t r) { r /= 4; return apic_base[r]; } static void write_apic_reg(uint64_t r, uint32_t v) { r /= 4; apic_base[r] = v; } static uint32_t read_ioapic_reg(uint8_t r) { *ioapic_reg = r; return *ioapic_data; } static void write_ioapic_reg(uint8_t r, uint32_t v) { *ioapic_reg = r; *ioapic_data = v; }