| 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 | ioapic = (volatile struct ioapic*)IOAPIC; |
| 54 | maxintr = (ioapicread(REG_VER) >> 16) & 0xFF; |
| 55 | id = ioapicread(REG_ID) >> 24; |
| 56 | if(id != ioapicid) |
| 57 | cprintf("ioapicinit: id isn't equal to ioapicid; not a MP\n" ); |
| 58 | |
| 59 | // Mark all interrupts edge-triggered, active high, disabled, |
| 60 | // and not routed to any CPUs. |
| 61 | for(i = 0; i <= maxintr; i++){ |
| 62 | ioapicwrite(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i)); |
| 63 | ioapicwrite(REG_TABLE+2*i+1, 0); |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | void |
| 68 | ioapicenable(int irq, int cpunum) |
| 69 | { |
| 70 | // Mark interrupt edge-triggered, active high, |
| 71 | // enabled, and routed to the given cpunum, |
| 72 | // which happens to be that cpu's APIC ID. |
| 73 | ioapicwrite(REG_TABLE+2*irq, T_IRQ0 + irq); |
| 74 | ioapicwrite(REG_TABLE+2*irq+1, cpunum << 24); |
| 75 | } |
| 76 | |