199b11b6cSrsc // The I/O APIC manages hardware interrupts for an SMP system. 299b11b6cSrsc // http://www.intel.com/design/chipsets/datashts/29056601.pdf 3eb52c7deSrsc // See also picirq.c. 499b11b6cSrsc 5c8b29f6dSkaashoek #include "types.h" 6c8b29f6dSkaashoek #include "defs.h" 7c8b29f6dSkaashoek #include "traps.h" 8c8b29f6dSkaashoek 999b11b6cSrsc #define IOAPIC 0xFEC00000 // Default physical address of IO APIC 1099b11b6cSrsc 1199b11b6cSrsc #define REG_ID 0x00 // Register index: ID 1299b11b6cSrsc #define REG_VER 0x01 // Register index: version 1399b11b6cSrsc #define REG_TABLE 0x10 // Redirection table base 1499b11b6cSrsc 1599b11b6cSrsc // The redirection table starts at REG_TABLE and uses 1699b11b6cSrsc // two registers to configure each interrupt. 1799b11b6cSrsc // The first (low) register in a pair contains configuration bits. 1899b11b6cSrsc // The second (high) register contains a bitmask telling which 1999b11b6cSrsc // CPUs can serve that interrupt. 20eadbd55aSrsc #define INT_DISABLED 0x00010000 // Interrupt disabled 2199b11b6cSrsc #define INT_LEVEL 0x00008000 // Level-triggered (vs edge-) 2299b11b6cSrsc #define INT_ACTIVELOW 0x00002000 // Active low (vs high) 2399b11b6cSrsc #define INT_LOGICAL 0x00000800 // Destination is CPU id (vs APIC ID) 2499b11b6cSrsc 2599b11b6cSrsc volatile struct ioapic *ioapic; 2699b11b6cSrsc 2799b11b6cSrsc // IO APIC MMIO structure: write reg, then read or write data. 28c8b29f6dSkaashoek struct ioapic { 2999b11b6cSrsc uint reg; 3099b11b6cSrsc uint pad[3]; 3199b11b6cSrsc uint data; 32c8b29f6dSkaashoek }; 33c8b29f6dSkaashoek 34c8b29f6dSkaashoek static uint 3521575761Srsc ioapicread(int reg) 36c8b29f6dSkaashoek { 3799b11b6cSrsc ioapic->reg = reg; 3899b11b6cSrsc return ioapic->data; 39c8b29f6dSkaashoek } 40c8b29f6dSkaashoek 41c8b29f6dSkaashoek static void 4221575761Srsc ioapicwrite(int reg, uint data) 43c8b29f6dSkaashoek { 4499b11b6cSrsc ioapic->reg = reg; 4599b11b6cSrsc ioapic->data = data; 46c8b29f6dSkaashoek } 47c8b29f6dSkaashoek 48c8b29f6dSkaashoek void 4921575761Srsc ioapicinit(void) 50c8b29f6dSkaashoek { 5199b11b6cSrsc int i, id, maxintr; 52c8b29f6dSkaashoek 535c596bb3Skaashoek if(!ismp) 545c596bb3Skaashoek return; 555c596bb3Skaashoek 5699b11b6cSrsc ioapic = (volatile struct ioapic*)IOAPIC; 5721575761Srsc maxintr = (ioapicread(REG_VER) >> 16) & 0xFF; 5821575761Srsc id = ioapicread(REG_ID) >> 24; 5921575761Srsc if(id != ioapicid) 6021575761Srsc cprintf("ioapicinit: id isn't equal to ioapicid; not a MP\n"); 6199b11b6cSrsc 6299b11b6cSrsc // Mark all interrupts edge-triggered, active high, disabled, 6399b11b6cSrsc // and not routed to any CPUs. 6499b11b6cSrsc for(i = 0; i <= maxintr; i++){ 65*2de1c550SRuss Cox ioapicwrite(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i)); 6621575761Srsc ioapicwrite(REG_TABLE+2*i+1, 0); 67c8b29f6dSkaashoek } 68c8b29f6dSkaashoek } 69c8b29f6dSkaashoek 70c8b29f6dSkaashoek void 7121575761Srsc ioapicenable(int irq, int cpunum) 72c8b29f6dSkaashoek { 735c596bb3Skaashoek if(!ismp) 745c596bb3Skaashoek return; 755c596bb3Skaashoek 7699b11b6cSrsc // Mark interrupt edge-triggered, active high, 7799b11b6cSrsc // enabled, and routed to the given cpunum, 7899b11b6cSrsc // which happens to be that cpu's APIC ID. 79*2de1c550SRuss Cox ioapicwrite(REG_TABLE+2*irq, T_IRQ0 + irq); 8021575761Srsc ioapicwrite(REG_TABLE+2*irq+1, cpunum << 24); 81c8b29f6dSkaashoek } 82