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 | |