IOAPIC: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (Interwiki)
No edit summary
Line 1: Line 1:
== Basic Info ==
== 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 [[8259 PIC]]. With the I/O APIC, interrupts can be distributed to physical or logical (clusters) of processors and can be prioritized.
The Intel I/O Advanced Programmable Interrupt Controller is used to distribute external interrupts in a more advanced manner than that of the standard [[8259 PIC]]. With the I/O APIC, interrupts can be distributed to physical or logical (clusters) of processors and can be prioritized. Each I/O APIC can handle up to 24 IRQs.


== Detecting I/O APIC ==
== 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.
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, what are their APIC ID, base MMIO address and first IRQ (or GSI - Global System Interrupt). For more information of parsing the MP tables, see the External MP Tables Links section below. So you can have, say, 2 I/O APICs, the first handling IRQs 0 - 23 and the second 24 - 47.


== Programming the I/O APIC ==
== Programming the I/O APIC ==
Each I/O APIC has a set of 3 32-bit registers and up to 24 64-bit registers (one per IRQ). The 64-bit registers have actually to be accessed as two 32-bit reads/writes. So here we have 51 registers. All registers are memory indexed. It means that you actually have only two 32-bit registers in memory, called IOREGSEL and IOREGWIN. You put the register index in IOREGSEL, and then you can read/write in IOREGWIN. The first three registers are: IOAPICID (index 0), which contains in bits 24 - 27 the APIC ID for this "device" (should be the same in MP/ACPI MADT Tables), IOAPICVER (index 1), which contains the I/O APIC Version in bits 0 - 8, and the ''Max Redirection Entry'' (how many IRQs can this handle - max 24) in bits 16 - 23, finally IOAPICARB (index 2), which contains in bits 24 - 27 the APIC Arbitration ID.

=== IOREGSEL and IOWIN ===
=== 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.
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.


<source lang="c">
<source lang="c">
void write_ioapic_register(const ptr_t apic_base, const uint8_t offset, const uint32_t val)
void write_ioapic_register(const uintptr_t apic_base, const uint8_t offset, const uint32_t val)
{
{
/* tell IOREGSEL where we want to write to */
/* tell IOREGSEL where we want to write to */
Line 18: Line 20:
}
}
uint32_t read_ioapic_register(const ptr_t apic_base, const uint8_t offset)
uint32_t read_ioapic_register(const uintptr_t apic_base, const uint8_t offset)
{
{
/* tell IOREGSEL where we want to read from */
/* tell IOREGSEL where we want to read from */

Revision as of 17:41, 13 May 2012

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 8259 PIC. With the I/O APIC, interrupts can be distributed to physical or logical (clusters) of processors and can be prioritized. Each I/O APIC can handle up to 24 IRQs.

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, what are their APIC ID, base MMIO address and first IRQ (or GSI - Global System Interrupt). For more information of parsing the MP tables, see the External MP Tables Links section below. So you can have, say, 2 I/O APICs, the first handling IRQs 0 - 23 and the second 24 - 47.

Programming the I/O APIC

Each I/O APIC has a set of 3 32-bit registers and up to 24 64-bit registers (one per IRQ). The 64-bit registers have actually to be accessed as two 32-bit reads/writes. So here we have 51 registers. All registers are memory indexed. It means that you actually have only two 32-bit registers in memory, called IOREGSEL and IOREGWIN. You put the register index in IOREGSEL, and then you can read/write in IOREGWIN. The first three registers are: IOAPICID (index 0), which contains in bits 24 - 27 the APIC ID for this "device" (should be the same in MP/ACPI MADT Tables), IOAPICVER (index 1), which contains the I/O APIC Version in bits 0 - 8, and the Max Redirection Entry (how many IRQs can this handle - max 24) in bits 16 - 23, finally IOAPICARB (index 2), which contains in bits 24 - 27 the APIC Arbitration ID.

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.

 void write_ioapic_register(const uintptr_t apic_base, const uint8_t offset, const uint32_t val)
 {
     /* tell IOREGSEL where we want to write to */
     *(uint32_t*)(apic_base) = offset;
     /* write the value to IOWIN */
     *(uint32_t*)(apic_base + 0x10) = val;
 }
 
 uint32_t read_ioapic_register(const uintptr_t apic_base, const uint8_t offset)
 {
     /* tell IOREGSEL where we want to read from */
     *(uint32_t*)(apic_base) = offset;
     /* return the data from IOWIN */
     return *(uint32_t*)(apic_base + 0x10);
 }

Note: 'ptr_t' is the size of the default memory reference. If a 32-bit Protected Mode setup, it's equivalent to uint32_t, and uint64_t in 64-bit Long Mode environments. 'apic_base' is the memory base address for a selected IOAPIC, these can be found by enumerating them from the MP Tables.

External Links

MP Tables

I/O APIC