summaryrefslogtreecommitdiff
path: root/ioapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'ioapic.c')
-rw-r--r--ioapic.c97
1 files changed, 47 insertions, 50 deletions
diff --git a/ioapic.c b/ioapic.c
index aae49b5..a009ca8 100644
--- a/ioapic.c
+++ b/ioapic.c
@@ -1,85 +1,82 @@
+// The I/O APIC manages hardware interrupts for an SMP system.
+// http://www.intel.com/design/chipsets/datashts/29056601.pdf
+
#include "types.h"
#include "mp.h"
#include "defs.h"
#include "x86.h"
#include "traps.h"
-#include "ioapic.h"
-struct ioapic {
- uint ioregsel; uint p01; uint p02; uint p03;
- uint iowin; uint p11; uint p12; uint p13;
-};
+#define IOAPIC 0xFEC00000 // Default physical address of IO APIC
+
+#define REG_ID 0x00 // Register index: ID
+#define REG_VER 0x01 // Register index: version
+#define REG_TABLE 0x10 // Redirection table base
+// The redirection table starts at REG_TABLE and uses
+// two registers to configure each interrupt.
+// The first (low) register in a pair contains configuration bits.
+// The second (high) register contains a bitmask telling which
+// CPUs can serve that interrupt.
+#define INT_DISABLED 0x00100000 // Interrupt disabled
+#define INT_LEVEL 0x00008000 // Level-triggered (vs edge-)
+#define INT_ACTIVELOW 0x00002000 // Active low (vs high)
+#define INT_LOGICAL 0x00000800 // Destination is CPU id (vs APIC ID)
-#define IOAPIC_REDTBL_LO(i) (IOAPIC_REDTBL + (i) * 2)
-#define IOAPIC_REDTBL_HI(i) (IOAPIC_REDTBL_LO(i) + 1)
+volatile struct ioapic *ioapic;
+
+// IO APIC MMIO structure: write reg, then read or write data.
+struct ioapic {
+ uint reg;
+ uint pad[3];
+ uint data;
+};
static uint
-ioapic_read(struct ioapic *io, int reg)
+ioapic_read(int reg)
{
- io->ioregsel = reg;
- return io->iowin;
+ ioapic->reg = reg;
+ return ioapic->data;
}
static void
-ioapic_write(struct ioapic *io, int reg, uint val)
+ioapic_write(int reg, uint data)
{
- io->ioregsel = reg;
- io->iowin = val;
+ ioapic->reg = reg;
+ ioapic->data = data;
}
void
ioapic_init(void)
{
- struct ioapic *io;
- uint l, h;
- int nintr;
- uchar id;
- int i;
+ int i, id, maxintr;
if(!ismp)
return;
- io = (struct ioapic*) IO_APIC_BASE;
- l = ioapic_read(io, IOAPIC_VER);
- nintr = ((l & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
- id = ioapic_read(io, IOAPIC_ID) >> APIC_ID_SHIFT;
+ ioapic = (volatile struct ioapic*)IOAPIC;
+ maxintr = (ioapic_read(REG_VER) >> 16) & 0xFF;
+ id = ioapic_read(REG_ID) >> 24;
if(id != ioapic_id)
cprintf("ioapic_init: id isn't equal to ioapic_id; not a MP\n");
- for(i = 0; i < nintr; i++) {
- // active-hi and edge-triggered for ISA interrupts
- // Assume that pin 0 on the first I/O APIC is an ExtINT pin.
- // Assume that pins 1-15 are ISA interrupts
- l = ioapic_read(io, IOAPIC_REDTBL_LO(i));
- l = l & ~IOART_INTMASK; // allow INTs
- l |= IOART_INTMSET;
- l = l & ~IOART_INTPOL; // active hi
- l = l & ~IOART_TRGRMOD; // edgee triggered
- l = l & ~IOART_DELMOD; // fixed
- l = l & ~IOART_DESTMOD; // physical mode
- l = l | (IRQ_OFFSET + i); // vector
- ioapic_write(io, IOAPIC_REDTBL_LO(i), l);
- h = ioapic_read(io, IOAPIC_REDTBL_HI(i));
- h &= ~IOART_DEST;
- ioapic_write(io, IOAPIC_REDTBL_HI(i), h);
+
+ // Mark all interrupts edge-triggered, active high, disabled,
+ // and not routed to any CPUs.
+ for(i = 0; i <= maxintr; i++){
+ ioapic_write(REG_TABLE+2*i, INT_DISABLED | (IRQ_OFFSET + i));
+ ioapic_write(REG_TABLE+2*i+1, 0);
}
}
void
-ioapic_enable (int irq, int cpunum)
+ioapic_enable(int irq, int cpunum)
{
- uint l, h;
- struct ioapic *io;
-
if(!ismp)
return;
- io = (struct ioapic*) IO_APIC_BASE;
- l = ioapic_read(io, IOAPIC_REDTBL_LO(irq));
- l = l & ~IOART_INTMASK; // allow INTs
- ioapic_write(io, IOAPIC_REDTBL_LO(irq), l);
- h = ioapic_read(io, IOAPIC_REDTBL_HI(irq));
- h &= ~IOART_DEST;
- h |= (cpunum << APIC_ID_SHIFT);
- ioapic_write(io, IOAPIC_REDTBL_HI(irq), h);
+ // Mark interrupt edge-triggered, active high,
+ // enabled, and routed to the given cpunum,
+ // which happens to be that cpu's APIC ID.
+ ioapic_write(REG_TABLE+2*irq, IRQ_OFFSET + irq);
+ ioapic_write(REG_TABLE+2*irq+1, cpunum << 24);
}