xref: /xv6-public/ioapic.c (revision 4f14d8d1)
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
ioapicread(int reg)35 ioapicread(int reg)
36 {
37   ioapic->reg = reg;
38   return ioapic->data;
39 }
40 
41 static void
ioapicwrite(int reg,uint data)42 ioapicwrite(int reg, uint data)
43 {
44   ioapic->reg = reg;
45   ioapic->data = data;
46 }
47 
48 void
ioapicinit(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
ioapicenable(int irq,int cpunum)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