diff options
author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-31 22:35:04 +0200 |
---|---|---|
committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-31 22:35:04 +0200 |
commit | 866912eb5f7906da2545f27f7bbef01a7d61c87f (patch) | |
tree | 2472110bcf868837d84893bc257edcbafefe5a59 /src/apic.c | |
parent | 5e12467c860372dfa10323365fb0df9db79c8f9b (diff) |
Diffstat (limited to 'src/apic.c')
-rw-r--r-- | src/apic.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/apic.c b/src/apic.c new file mode 100644 index 0000000..26adfae --- /dev/null +++ b/src/apic.c @@ -0,0 +1,121 @@ +#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; +} |