IOAPIC
Basic Info
The Intel I/O Advanced Programmable Interrupt Controller is used to distribute external interrupts in a more advanced manner than that of the standard PIC. With the I/O APIC, interrupts can be distributed to physical or logical (clusters) of processors and can be prioritized.
Detecting I/O APIC
In order to detect the existence of an I/O APIC (or multiple ones), the Intel Multi-Processor or ACPI tables must be parsed. In the MP tables, configuration tables with the entry identification of 0x02 are for I/O APICs. Parsing will tell how many (if any) I/O APICs exist and what their ID and MMIO address is. For more information of parsing the MP tables, see the External MP Tables Links section below.
Programming the I/O APIC
IOREGSEL and IOWIN
The register IOREGSEL is an MMIO register select register that is used to access all the other I/O APIC registers. IOREGSEL only selects the register and does not actually write or read the register. The IOWIN register is the 'data' register. Once the IOREGSEL register has been set, the IOWIN register can be used to write or read the register in the IOREGSEL.
eg:
// set IOREGSEL void io_apic_set_reg(uint32 address, uint8 reg) { *(uint32*)(address) = (uint32)reg; // set IOREGSEL } // write a 64-bit value to IO APIC (two 32-bit values) void io_apic write_64(uint32 address, uint8 reg, uint32 val_hi, uint32 val_lo) { io_apic_set_reg(address, reg); // set reg (bits 0-31) *(uint32*)(address + 0x10) = (uint32)(val_lo); // write val (bits 0-31) io_apic_set_reg(address, reg+1); // set reg (bits 32-63) *(uint32*)(address + 0x10) = (uint32)(val_hi); // write val (bits 32-63) } // read a 32-bit value from IO APIC uint32 io_apic_read_32(uint32 address, uint8 reg) { io_apic_set_reg(address, reg); // set reg return *(uint32*)(address + 0x10); }