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