Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to.
This commit is contained in:
commit
d0f7acf9eb
275 changed files with 51417 additions and 0 deletions
102
kernel/arch/x86_64/ioapic.c
Normal file
102
kernel/arch/x86_64/ioapic.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// The I/O APIC manages hardware interrupts for an SMP system.
|
||||
// http://www.intel.com/design/chipsets/datashts/29056601.pdf
|
||||
// See also picirq.c.
|
||||
|
||||
#include "types.h"
|
||||
#include "defs.h"
|
||||
#include "traps.h"
|
||||
#include "memlayout.h"
|
||||
|
||||
#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 0x00010000 // 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)
|
||||
|
||||
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
|
||||
ioapicread(int reg)
|
||||
{
|
||||
ioapic->reg = reg;
|
||||
return ioapic->data;
|
||||
}
|
||||
|
||||
static void
|
||||
ioapicwrite(int reg, uint data)
|
||||
{
|
||||
ioapic->reg = reg;
|
||||
ioapic->data = data;
|
||||
}
|
||||
|
||||
void
|
||||
ioapicinit(void)
|
||||
{
|
||||
int i, id, maxintr;
|
||||
|
||||
ioapic = P2V((volatile struct ioapic*)IOAPIC);
|
||||
maxintr = (ioapicread(REG_VER) >> 16) & 0xFF;
|
||||
id = ioapicread(REG_ID) >> 24;
|
||||
if(id != ioapicid)
|
||||
cprintf("ioapicinit: id isn't equal to ioapicid; not a MP\n");
|
||||
|
||||
// Mark all interrupts edge-triggered, active high, disabled,
|
||||
// and not routed to any CPUs.
|
||||
for(i = 0; i <= maxintr; i++){
|
||||
ioapicwrite(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i));
|
||||
ioapicwrite(REG_TABLE+2*i+1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Route an interrupt to a CPU and unmask it.
|
||||
//
|
||||
// `level_low` picks PCI's signalling instead of ISA's. This distinction did
|
||||
// not matter while every interrupt in the kernel came from an ISA-era device
|
||||
// at a fixed pin, all of which are edge-triggered and active high -- which is
|
||||
// why the original ioapicenable() hardcoded exactly that. A PCI device wired
|
||||
// through an INTx pin is the opposite on both counts, and configuring it as
|
||||
// edge/high does not fail cleanly: the device raises the line, we take one
|
||||
// interrupt, and because the level never goes away there is no second edge
|
||||
// and the device is never heard from again.
|
||||
void
|
||||
ioapicroute(int irq, int cpunum, int level_low)
|
||||
{
|
||||
uint lo = T_IRQ0 + irq;
|
||||
|
||||
if(level_low)
|
||||
lo |= INT_LEVEL | INT_ACTIVELOW;
|
||||
|
||||
// Program the destination before unmasking, so the entry is never briefly
|
||||
// live pointing at CPU 0 when it was meant for another.
|
||||
ioapicwrite(REG_TABLE+2*irq+1, cpunum << 24);
|
||||
ioapicwrite(REG_TABLE+2*irq, lo);
|
||||
}
|
||||
|
||||
void
|
||||
ioapicmask(int irq)
|
||||
{
|
||||
ioapicwrite(REG_TABLE+2*irq, INT_DISABLED | (T_IRQ0 + irq));
|
||||
}
|
||||
|
||||
void
|
||||
ioapicenable(int irq, int cpunum)
|
||||
{
|
||||
ioapicroute(irq, cpunum, 0);
|
||||
}
|
||||
Loading…
Reference in a new issue