I/O Advanced Programmable Interrupt Controller
Der I/O APIC (= I/O Advanced Programmable Interrupt Controller) löst den Programmable Interrupt Controller in einem SMP- bzw. NUMA-System ab. Da der PIC die IRQs ausschließlich an den BSP (= Bootstrap Processor) senden kann, ist in einem System mit mehreren Prozessoren ein I/O APIC notwendig. Darüber hinaus stellt der I/O APIC statt nur 16 IRQ-Leitungen wie der PIC normalerweise 24 IRQ-Leitungen zur Verfügung. Dies verringert die Anzahl der von mehreren Geräten gleichzeitig genutzten IRQs in Systemen mit sehr vielen Geräten. Außerdem ist die Programmierung des I/O APIC schneller, da sie nicht über I/O Ports, sondern über Speicherbereiche abläuft.
Inhaltsverzeichnis
Aufbau
memory-mapped Register
Die folgenden Register sind in den physischen Adressraum des Systems eingeblendet und dienen dazu auf die internen Register zuzugreifen:
Offset | Abkürzung | Beschreibung | Zugriffsart |
---|---|---|---|
0x00 | IOREGSEL | I/O Register Select | 8Bit, lesend/schreibend |
0x10 | IOWIN | I/O Window | 32Bit, lesend/schreibend |
Interne Register
Die folgenden Register dienen der Konfiguration des I/O APIC:
Index | Abkürzung | Beschreibung | Zugriffsart |
---|---|---|---|
0x00 | IOAPICID | I/O APIC ID | 32Bit, lesend/schreibend |
0x01 | IOAPICVER | I/O APIC Version | 32Bit, nur lesend |
0x02 | IOAPICARB | I/O APIC Arbitration ID | 32Bit, nur lesend |
0x10 - ? | IOREDTBL[0-23] | Redirection Table-Eintrag 0-? (jeweils 64bit) | 32Bit, lesend/schreibend |
I/O APIC ID
Bits | Beschreibung | Zugriffsart |
---|---|---|
28-31 | reserviert | |
24-27 | 4Bit ID des I/O APIC | lesend/schreibend |
0-23 | reserviert |
I/O APIC Version
Bits | Beschreibung | Zugriffsart |
---|---|---|
24-31 | reserviert | |
16-23 | maximaler Index eines gültigen Eintrags in der Redirection Table | nur lesend |
8-15 | reserviert | |
0-7 | I/O APIC Versionsnummer: 0x11 = 82093AA |
nur lesend |
I/O APIC Arbitration ID
Bits | Beschreibung | Zugriffsart |
---|---|---|
28-31 | reserviert | |
24-27 | 4Bit Arbitration ID des I/O APIC | lesend/schreibend |
0-23 | reserviert |
Redirection Table
Aufbau eines Eintrags
Bits | Abkürzung | Name | Beschreibung | Zugriffsart |
---|---|---|---|---|
56-63 | Destination | gibt den/die empfangenden Local APIC(s) an, Erklärung siehe Destination-Tabelle | lesend/schreibend | |
17-55 | reserviert | |||
16 | Interrupt Mask | Der Interrupt ist maskiert, falls der Wert 1 ist | lesend/schreibend | |
15 | Trigger Mode | 0b = edge sensitive 1b = level sensitive |
lesend/schreibend | |
14 | Remote IRR | Dieses Bit ist nur gültig, wenn der Trigger Mode edge ist: 0b = EOI mit passendem Interruptvektor wurde gesendet 1b = Interrupt wurde vom Local APIC bzw. den Local APICs angenommen |
nur lesend | |
13 | INTPOL | Interrupt Input Pin Polarity | 0b = high active 1b = low active |
lesend/schreibend |
12 | DELIVS | Delivery Status | Der Interrupt wird momentan ausgeliefert, falls der Wert 1 ist | nur lesend |
11 | DESTMOD | Destination Mode | Gibt an wie das Destination-Feld zur Adressierung der empfangenden Local APICs interpretiert wird, siehe Destination-Feld | lesend/schreiben |
8-10 | DELMOD | Delivery Mode | Gibt an wie die empfangenden Local APICs reagieren sollen, Erklärung siehe Delivery Mode-Tabelle | lesend/schreibend |
0-7 | INTVEC | Interrupt Vector | auszulösender Interruptvektor | lesend/schreibend |
Destination
Wert von DESTMOD | Modus | Beschreibung |
---|---|---|
0 | Physical Mode | Bits 56-59 enthalten eine APIC ID |
1 | Logical Mode | Bits 56-63 werden als Menge von Prozessoren interpretiert |
Delivery Mode
Wert | Modus | Beschreibung |
---|---|---|
000b | Fixed | Löst in den durch das Destination-Feld ausgewählten Prozessoren einen normalen Interrupt aus. |
001b | niedrigste Priorität | Löst in dem Prozessor mit der momentan geringsten Priorität der durch das Destination-Feld ausgewählten Prozessoren einen normalen Interrupt aus. |
010b | SMI | Es wird allen durch das Destination-Feld ausgewählten Prozessoren ein SMI signalisiert. Dabei wird der Interruptvektor ignoriert, sollte aber aus Kompatibilitätsgründen auf 0 gesetzt werden. Der Trigger Mode muss edge sein. |
011b | reserviert | |
100b | NMI | Es wird allen durch das Destination-Feld ausgewählten Prozessoren ein NMI signalisiert. Dabei wird der Interruptvektor ignoriert. Der Trigger Mode muss edge sein. |
101b | INIT | |
110b | reserviert | |
111b | ExtINT | Analog zu Fixed wird ein normaler Interrupt ausgelöst. Der Interruptvektor kommt allerdings nicht vom I/O APIC sondern wird von einem externen Controller (z.B. des PIC) geliefert. Der Trigger Mode muss edge sein. |
Programmierung
Basisadresse des I/O APIC
Die Basisadresse dieser Speicherbereiche kann im Allgemeinen über die SMP- bzw. die ACPI-Tabellen ausgelesen werden. Bei einem PIIX3 Chipsatz beginnt der Speicherbereich bei 0xFEC00xy00 (x und y werden mit dem APICBASE Register im PIIX3 festgelegt).
Lesen/Schreiben der internen Register
Der I/O APIC besitzt ein Indexregister (I/O Register Select bzw. IOREGSEL) und ein Datenregister (I/O Window bzw. IOWIN). Mit dem Indexregister wählt man ein internes Register des I/O APIC aus und kann anschließend über das Datenregister das interne Register auslesen bzw. beschreiben.
Folgender Code kann dazu verwendet werden auf die internen Register zuzugreifen: <c> /* Offset der memory-mapped Register */
- define IO_APIC_MMREG_IOREGSEL 0x00
- define IO_APIC_MMREG_IOWIN 0x10
/* Basisadresse, sollte vorher initialisiert werden */ volatile uint8_t * io_apic_base;
/* Lesen eines internen Registers */ uint32_t io_apic_read(uint8_t index) {
*(io_apic_base + IO_APIC_MMREG_IOREGSEL) = index; return *(volatile uint32_t *)(io_apic_base + IO_APIC_MMREG_IOWIN);
}
/* Schreiben eines internen Registers */ void io_apic_write(uint8_t index, uint32_t value) {
*(io_apic_base + IO_APIC_MMREG_IOREGSEL) = index; *(volatile uint32_t *)(io_apic_base + IO_APIC_MMREG_IOWIN) = value;
} </c>
Setzen der Einträge der Redirection Table
Die Einträge der Redirection Table werden basierend auf den Informationen, die die SMP-, die ACPI-Tabellen und vor allem das PCI Device PCI-to-ISA Bridge enthalten, gesetzt. Bei PIIX3 und ICH7/9 findet man z.B. die Vektoren für die PCI Lines A-D (IOAPIC redir table: 16-19) am offset 60h. Bei ICH7/9 gibt es am offset 68h die Informationen für die Vektoren der PCI Lines E-H (IOAPIC redir table: 20-23). Man findet die PCI-to-(E)ISA Bridge via:
<c>if ((PCIdev->classID == 0x06) && (PCIdev->subclassID == 0x01 || PCIdev->subclassID == 0x02) && (PCIdev->interfaceID == 0x00)) {/*...*/}</c>
Die enthaltenen unsigned 8-Bit-Integer in den vier Bytes am PCI offset 60h bzw. 68h setzt man als jeweiligen Vektor für die IOAPIC Redirection Table Einträge 16-23. In Bochs findet man das P2I routing z.B. hier:
[P2I] PCI IRQ routing: PIRQA# set to 0x0b
[P2I] PCI IRQ routing: PIRQB# set to 0x09
[P2I] PCI IRQ routing: PIRQC# set to 0x0b
[P2I] PCI IRQ routing: PIRQD# set to 0x09
Die Tabellen-Einträge 0-15 (ISA-IRQ) sollte man edge/high setzen und die Einträge 16-23 (PCI Lines A-H) auf level/low.