1*99b11b6cSrsc // The I/O APIC manages hardware interrupts for an SMP system. 2*99b11b6cSrsc // http://www.intel.com/design/chipsets/datashts/29056601.pdf 3*99b11b6cSrsc 4c8b29f6dSkaashoek #include "types.h" 5c8b29f6dSkaashoek #include "mp.h" 6c8b29f6dSkaashoek #include "defs.h" 7c8b29f6dSkaashoek #include "x86.h" 8c8b29f6dSkaashoek #include "traps.h" 9c8b29f6dSkaashoek 10*99b11b6cSrsc #define IOAPIC 0xFEC00000 // Default physical address of IO APIC 11*99b11b6cSrsc 12*99b11b6cSrsc #define REG_ID 0x00 // Register index: ID 13*99b11b6cSrsc #define REG_VER 0x01 // Register index: version 14*99b11b6cSrsc #define REG_TABLE 0x10 // Redirection table base 15*99b11b6cSrsc 16*99b11b6cSrsc // The redirection table starts at REG_TABLE and uses 17*99b11b6cSrsc // two registers to configure each interrupt. 18*99b11b6cSrsc // The first (low) register in a pair contains configuration bits. 19*99b11b6cSrsc // The second (high) register contains a bitmask telling which 20*99b11b6cSrsc // CPUs can serve that interrupt. 21*99b11b6cSrsc #define INT_DISABLED 0x00100000 // Interrupt disabled 22*99b11b6cSrsc #define INT_LEVEL 0x00008000 // Level-triggered (vs edge-) 23*99b11b6cSrsc #define INT_ACTIVELOW 0x00002000 // Active low (vs high) 24*99b11b6cSrsc #define INT_LOGICAL 0x00000800 // Destination is CPU id (vs APIC ID) 25*99b11b6cSrsc 26*99b11b6cSrsc volatile struct ioapic *ioapic; 27*99b11b6cSrsc 28*99b11b6cSrsc // IO APIC MMIO structure: write reg, then read or write data. 29c8b29f6dSkaashoek struct ioapic { 30*99b11b6cSrsc uint reg; 31*99b11b6cSrsc uint pad[3]; 32*99b11b6cSrsc uint data; 33c8b29f6dSkaashoek }; 34c8b29f6dSkaashoek 35c8b29f6dSkaashoek static uint 36*99b11b6cSrsc ioapic_read(int reg) 37c8b29f6dSkaashoek { 38*99b11b6cSrsc ioapic->reg = reg; 39*99b11b6cSrsc return ioapic->data; 40c8b29f6dSkaashoek } 41c8b29f6dSkaashoek 42c8b29f6dSkaashoek static void 43*99b11b6cSrsc ioapic_write(int reg, uint data) 44c8b29f6dSkaashoek { 45*99b11b6cSrsc ioapic->reg = reg; 46*99b11b6cSrsc ioapic->data = data; 47c8b29f6dSkaashoek } 48c8b29f6dSkaashoek 49c8b29f6dSkaashoek void 50c8b29f6dSkaashoek ioapic_init(void) 51c8b29f6dSkaashoek { 52*99b11b6cSrsc int i, id, maxintr; 53c8b29f6dSkaashoek 545c596bb3Skaashoek if(!ismp) 555c596bb3Skaashoek return; 565c596bb3Skaashoek 57*99b11b6cSrsc ioapic = (volatile struct ioapic*)IOAPIC; 58*99b11b6cSrsc maxintr = (ioapic_read(REG_VER) >> 16) & 0xFF; 59*99b11b6cSrsc id = ioapic_read(REG_ID) >> 24; 60c8b29f6dSkaashoek if(id != ioapic_id) 61f7017212Skaashoek cprintf("ioapic_init: id isn't equal to ioapic_id; not a MP\n"); 62*99b11b6cSrsc 63*99b11b6cSrsc // Mark all interrupts edge-triggered, active high, disabled, 64*99b11b6cSrsc // and not routed to any CPUs. 65*99b11b6cSrsc for(i = 0; i <= maxintr; i++){ 66*99b11b6cSrsc ioapic_write(REG_TABLE+2*i, INT_DISABLED | (IRQ_OFFSET + i)); 67*99b11b6cSrsc ioapic_write(REG_TABLE+2*i+1, 0); 68c8b29f6dSkaashoek } 69c8b29f6dSkaashoek } 70c8b29f6dSkaashoek 71c8b29f6dSkaashoek void 720e84a0ecSrtm ioapic_enable(int irq, int cpunum) 73c8b29f6dSkaashoek { 745c596bb3Skaashoek if(!ismp) 755c596bb3Skaashoek return; 765c596bb3Skaashoek 77*99b11b6cSrsc // Mark interrupt edge-triggered, active high, 78*99b11b6cSrsc // enabled, and routed to the given cpunum, 79*99b11b6cSrsc // which happens to be that cpu's APIC ID. 80*99b11b6cSrsc ioapic_write(REG_TABLE+2*irq, IRQ_OFFSET + irq); 81*99b11b6cSrsc ioapic_write(REG_TABLE+2*irq+1, cpunum << 24); 82c8b29f6dSkaashoek } 83