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
25volatile struct ioapic *ioapic;
26
27// IO APIC MMIO structure: write reg, then read or write data.
28struct ioapic {
29 uint reg;
30 uint pad[3];
31 uint data;
32};
33
34static uint
35ioapicread(int reg)
36{
37 ioapic->reg = reg;
38 return ioapic->data;
39}
40
41static void
42ioapicwrite(int reg, uint data)
43{
44 ioapic->reg = reg;
45 ioapic->data = data;
46}
47
48void
49ioapicinit(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
67void
68ioapicenable(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