Simplify MP hardware code.
Mainly delete unused constants and code. Move mp_startthem to main.c as bootothers.
This commit is contained in:
parent
b63bb0fd00
commit
99b11b6c64
97
ioapic.c
97
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 "types.h"
|
||||||
#include "mp.h"
|
#include "mp.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "x86.h"
|
#include "x86.h"
|
||||||
#include "traps.h"
|
#include "traps.h"
|
||||||
#include "ioapic.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 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)
|
||||||
|
|
||||||
|
volatile struct ioapic *ioapic;
|
||||||
|
|
||||||
|
// IO APIC MMIO structure: write reg, then read or write data.
|
||||||
struct ioapic {
|
struct ioapic {
|
||||||
uint ioregsel; uint p01; uint p02; uint p03;
|
uint reg;
|
||||||
uint iowin; uint p11; uint p12; uint p13;
|
uint pad[3];
|
||||||
|
uint data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define IOAPIC_REDTBL_LO(i) (IOAPIC_REDTBL + (i) * 2)
|
|
||||||
#define IOAPIC_REDTBL_HI(i) (IOAPIC_REDTBL_LO(i) + 1)
|
|
||||||
|
|
||||||
static uint
|
static uint
|
||||||
ioapic_read(struct ioapic *io, int reg)
|
ioapic_read(int reg)
|
||||||
{
|
{
|
||||||
io->ioregsel = reg;
|
ioapic->reg = reg;
|
||||||
return io->iowin;
|
return ioapic->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ioapic_write(struct ioapic *io, int reg, uint val)
|
ioapic_write(int reg, uint data)
|
||||||
{
|
{
|
||||||
io->ioregsel = reg;
|
ioapic->reg = reg;
|
||||||
io->iowin = val;
|
ioapic->data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ioapic_init(void)
|
ioapic_init(void)
|
||||||
{
|
{
|
||||||
struct ioapic *io;
|
int i, id, maxintr;
|
||||||
uint l, h;
|
|
||||||
int nintr;
|
|
||||||
uchar id;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if(!ismp)
|
if(!ismp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
io = (struct ioapic*) IO_APIC_BASE;
|
ioapic = (volatile struct ioapic*)IOAPIC;
|
||||||
l = ioapic_read(io, IOAPIC_VER);
|
maxintr = (ioapic_read(REG_VER) >> 16) & 0xFF;
|
||||||
nintr = ((l & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
|
id = ioapic_read(REG_ID) >> 24;
|
||||||
id = ioapic_read(io, IOAPIC_ID) >> APIC_ID_SHIFT;
|
|
||||||
if(id != ioapic_id)
|
if(id != ioapic_id)
|
||||||
cprintf("ioapic_init: id isn't equal to ioapic_id; not a MP\n");
|
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
|
// Mark all interrupts edge-triggered, active high, disabled,
|
||||||
// Assume that pin 0 on the first I/O APIC is an ExtINT pin.
|
// and not routed to any CPUs.
|
||||||
// Assume that pins 1-15 are ISA interrupts
|
for(i = 0; i <= maxintr; i++){
|
||||||
l = ioapic_read(io, IOAPIC_REDTBL_LO(i));
|
ioapic_write(REG_TABLE+2*i, INT_DISABLED | (IRQ_OFFSET + i));
|
||||||
l = l & ~IOART_INTMASK; // allow INTs
|
ioapic_write(REG_TABLE+2*i+1, 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ioapic_enable (int irq, int cpunum)
|
ioapic_enable(int irq, int cpunum)
|
||||||
{
|
{
|
||||||
uint l, h;
|
|
||||||
struct ioapic *io;
|
|
||||||
|
|
||||||
if(!ismp)
|
if(!ismp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
io = (struct ioapic*) IO_APIC_BASE;
|
// Mark interrupt edge-triggered, active high,
|
||||||
l = ioapic_read(io, IOAPIC_REDTBL_LO(irq));
|
// enabled, and routed to the given cpunum,
|
||||||
l = l & ~IOART_INTMASK; // allow INTs
|
// which happens to be that cpu's APIC ID.
|
||||||
ioapic_write(io, IOAPIC_REDTBL_LO(irq), l);
|
ioapic_write(REG_TABLE+2*irq, IRQ_OFFSET + irq);
|
||||||
h = ioapic_read(io, IOAPIC_REDTBL_HI(irq));
|
ioapic_write(REG_TABLE+2*irq+1, cpunum << 24);
|
||||||
h &= ~IOART_DEST;
|
|
||||||
h |= (cpunum << APIC_ID_SHIFT);
|
|
||||||
ioapic_write(io, IOAPIC_REDTBL_HI(irq), h);
|
|
||||||
}
|
}
|
||||||
|
|
88
ioapic.h
88
ioapic.h
|
@ -1,88 +0,0 @@
|
||||||
#define IO_APIC_BASE 0xFEC00000 // Default phys addr of IO APIC
|
|
||||||
#define IOAPIC_WINDOW 0x10 // Window register offset
|
|
||||||
|
|
||||||
// Constants relating to APIC ID registers
|
|
||||||
#define APIC_ID_MASK 0xff000000
|
|
||||||
#define APIC_ID_SHIFT 24
|
|
||||||
#define APIC_ID_CLUSTER 0xf0
|
|
||||||
#define APIC_ID_CLUSTER_ID 0x0f
|
|
||||||
#define APIC_MAX_CLUSTER 0xe
|
|
||||||
#define APIC_MAX_INTRACLUSTER_ID 3
|
|
||||||
#define APIC_ID_CLUSTER_SHIFT 4
|
|
||||||
|
|
||||||
// Fields in VER
|
|
||||||
#define APIC_VER_VERSION 0x000000ff
|
|
||||||
#define APIC_VER_MAXLVT 0x00ff0000
|
|
||||||
#define MAXLVTSHIFT 16
|
|
||||||
|
|
||||||
// Indexes into IO APIC
|
|
||||||
#define IOAPIC_ID 0x00
|
|
||||||
#define IOAPIC_VER 0x01
|
|
||||||
#define IOAPIC_ARB 0x02
|
|
||||||
#define IOAPIC_REDTBL 0x10
|
|
||||||
#define IOAPIC_REDTBL0 IOAPIC_REDTBL
|
|
||||||
#define IOAPIC_REDTBL1 (IOAPIC_REDTBL+0x02)
|
|
||||||
#define IOAPIC_REDTBL2 (IOAPIC_REDTBL+0x04)
|
|
||||||
#define IOAPIC_REDTBL3 (IOAPIC_REDTBL+0x06)
|
|
||||||
#define IOAPIC_REDTBL4 (IOAPIC_REDTBL+0x08)
|
|
||||||
#define IOAPIC_REDTBL5 (IOAPIC_REDTBL+0x0a)
|
|
||||||
#define IOAPIC_REDTBL6 (IOAPIC_REDTBL+0x0c)
|
|
||||||
#define IOAPIC_REDTBL7 (IOAPIC_REDTBL+0x0e)
|
|
||||||
#define IOAPIC_REDTBL8 (IOAPIC_REDTBL+0x10)
|
|
||||||
#define IOAPIC_REDTBL9 (IOAPIC_REDTBL+0x12)
|
|
||||||
#define IOAPIC_REDTBL10 (IOAPIC_REDTBL+0x14)
|
|
||||||
#define IOAPIC_REDTBL11 (IOAPIC_REDTBL+0x16)
|
|
||||||
#define IOAPIC_REDTBL12 (IOAPIC_REDTBL+0x18)
|
|
||||||
#define IOAPIC_REDTBL13 (IOAPIC_REDTBL+0x1a)
|
|
||||||
#define IOAPIC_REDTBL14 (IOAPIC_REDTBL+0x1c)
|
|
||||||
#define IOAPIC_REDTBL15 (IOAPIC_REDTBL+0x1e)
|
|
||||||
#define IOAPIC_REDTBL16 (IOAPIC_REDTBL+0x20)
|
|
||||||
#define IOAPIC_REDTBL17 (IOAPIC_REDTBL+0x22)
|
|
||||||
#define IOAPIC_REDTBL18 (IOAPIC_REDTBL+0x24)
|
|
||||||
#define IOAPIC_REDTBL19 (IOAPIC_REDTBL+0x26)
|
|
||||||
#define IOAPIC_REDTBL20 (IOAPIC_REDTBL+0x28)
|
|
||||||
#define IOAPIC_REDTBL21 (IOAPIC_REDTBL+0x2a)
|
|
||||||
#define IOAPIC_REDTBL22 (IOAPIC_REDTBL+0x2c)
|
|
||||||
#define IOAPIC_REDTBL23 (IOAPIC_REDTBL+0x2e)
|
|
||||||
|
|
||||||
// Fields in the IO APIC's redirection table entries
|
|
||||||
#define IOART_DEST APIC_ID_MASK // broadcast addr: all APICs
|
|
||||||
|
|
||||||
#define IOART_RESV 0x00fe0000 // reserved
|
|
||||||
|
|
||||||
#define IOART_INTMASK 0x00010000 // R/W: INTerrupt mask
|
|
||||||
#define IOART_INTMCLR 0x00000000 // clear, allow INTs
|
|
||||||
#define IOART_INTMSET 0x00010000 // set, inhibit INTs
|
|
||||||
|
|
||||||
#define IOART_TRGRMOD 0x00008000 // R/W: trigger mode
|
|
||||||
#define IOART_TRGREDG 0x00000000 // edge
|
|
||||||
#define IOART_TRGRLVL 0x00008000 // level
|
|
||||||
|
|
||||||
#define IOART_REM_IRR 0x00004000 // RO: remote IRR
|
|
||||||
|
|
||||||
#define IOART_INTPOL 0x00002000 // R/W: INT input pin polarity
|
|
||||||
#define IOART_INTAHI 0x00000000 // active high
|
|
||||||
#define IOART_INTALO 0x00002000 // active low
|
|
||||||
|
|
||||||
#define IOART_DELIVS 0x00001000 // RO: delivery status
|
|
||||||
|
|
||||||
#define IOART_DESTMOD 0x00000800 // R/W: destination mode
|
|
||||||
#define IOART_DESTPHY 0x00000000 // physical
|
|
||||||
#define IOART_DESTLOG 0x00000800 // logical
|
|
||||||
|
|
||||||
#define IOART_DELMOD 0x00000700 // R/W: delivery mode
|
|
||||||
#define IOART_DELFIXED 0x00000000 // fixed
|
|
||||||
#define IOART_DELLOPRI 0x00000100 // lowest priority
|
|
||||||
#define IOART_DELSMI 0x00000200 // System Management INT
|
|
||||||
#define IOART_DELRSV1 0x00000300 // reserved
|
|
||||||
#define IOART_DELNMI 0x00000400 // NMI signal
|
|
||||||
#define IOART_DELINIT 0x00000500 // INIT signal
|
|
||||||
#define IOART_DELRSV2 0x00000600 // reserved
|
|
||||||
#define IOART_DELEXINT 0x00000700 // External INTerrupt
|
|
||||||
|
|
||||||
#define IOART_INTVEC 0x000000ff // R/W: INTerrupt vector field
|
|
||||||
|
|
||||||
// Fields in VER
|
|
||||||
#define IOART_VER_VERSION 0x000000ff
|
|
||||||
#define IOART_VER_MAXREDIR 0x00ff0000
|
|
||||||
#define MAXREDIRSHIFT 16
|
|
155
lapic.c
155
lapic.c
|
@ -1,132 +1,91 @@
|
||||||
|
// The local APIC manages internal (non-I/O) interrupts.
|
||||||
|
// See Chapter 8 & Appendix C of Intel processor manual volume 3.
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "mp.h"
|
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "param.h"
|
#include "param.h"
|
||||||
#include "x86.h"
|
#include "x86.h"
|
||||||
#include "traps.h"
|
#include "traps.h"
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "lapic.h"
|
|
||||||
|
|
||||||
// Local APIC registers, divided by 4 for use as uint[] indices.
|
// Local APIC registers, divided by 4 for use as uint[] indices.
|
||||||
#define ID (0x0020/4) // ID
|
#define ID (0x0020/4) // ID
|
||||||
#define VER (0x0030/4) // Version
|
#define VER (0x0030/4) // Version
|
||||||
#define TPR (0x0080/4) // Task Priority
|
#define TPR (0x0080/4) // Task Priority
|
||||||
#define APR (0x0090/4) // Arbitration Priority
|
|
||||||
#define PPR (0x00A0/4) // Processor Priority
|
|
||||||
#define EOI (0x00B0/4) // EOI
|
#define EOI (0x00B0/4) // EOI
|
||||||
#define LDR (0x00D0/4) // Logical Destination
|
|
||||||
#define DFR (0x00E0/4) // Destination Format
|
|
||||||
#define SVR (0x00F0/4) // Spurious Interrupt Vector
|
#define SVR (0x00F0/4) // Spurious Interrupt Vector
|
||||||
#define ISR (0x0100/4) // Interrupt Status (8 registers)
|
#define ENABLE 0x00000100 // Unit Enable
|
||||||
#define TMR (0x0180/4) // Trigger Mode (8 registers)
|
|
||||||
#define IRR (0x0200/4) // Interrupt Request (8 registers)
|
|
||||||
#define ESR (0x0280/4) // Error Status
|
#define ESR (0x0280/4) // Error Status
|
||||||
#define ICRLO (0x0300/4) // Interrupt Command
|
#define ICRLO (0x0300/4) // Interrupt Command
|
||||||
|
#define INIT 0x00000500 // INIT/RESET
|
||||||
|
#define STARTUP 0x00000600 // Startup IPI
|
||||||
|
#define DELIVS 0x00001000 // Delivery status
|
||||||
|
#define ASSERT 0x00004000 // Assert interrupt (vs deassert)
|
||||||
|
#define LEVEL 0x00008000 // Level triggered
|
||||||
|
#define BCAST 0x00080000 // Send to all APICs, including self.
|
||||||
#define ICRHI (0x0310/4) // Interrupt Command [63:32]
|
#define ICRHI (0x0310/4) // Interrupt Command [63:32]
|
||||||
#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER)
|
#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER)
|
||||||
|
#define X1 0x0000000B // divide counts by 1
|
||||||
|
#define PERIODIC 0x00020000 // Periodic
|
||||||
#define PCINT (0x0340/4) // Performance Counter LVT
|
#define PCINT (0x0340/4) // Performance Counter LVT
|
||||||
#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0)
|
#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0)
|
||||||
#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1)
|
#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1)
|
||||||
#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR)
|
#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR)
|
||||||
|
#define MASKED 0x00010000 // Interrupt masked
|
||||||
#define TICR (0x0380/4) // Timer Initial Count
|
#define TICR (0x0380/4) // Timer Initial Count
|
||||||
#define TCCR (0x0390/4) // Timer Current Count
|
#define TCCR (0x0390/4) // Timer Current Count
|
||||||
#define TDCR (0x03E0/4) // Timer Divide Configuration
|
#define TDCR (0x03E0/4) // Timer Divide Configuration
|
||||||
|
|
||||||
// SVR
|
|
||||||
#define ENABLE 0x00000100 // Unit Enable
|
|
||||||
#define FOCUS 0x00000200 // Focus Processor Checking Disable
|
|
||||||
|
|
||||||
// ICRLO
|
|
||||||
// [14] IPI Trigger Mode Level (RW)
|
|
||||||
#define DEASSERT 0x00000000 // Deassert level-sensitive interrupt
|
|
||||||
#define ASSERT 0x00004000 // Assert level-sensitive interrupt
|
|
||||||
|
|
||||||
// [17:16] Remote Read Status
|
|
||||||
#define INVALID 0x00000000 // Invalid
|
|
||||||
#define WAIT 0x00010000 // In-Progress
|
|
||||||
#define VALID 0x00020000 // Valid
|
|
||||||
|
|
||||||
// [19:18] Destination Shorthand
|
|
||||||
#define FIELD 0x00000000 // No shorthand
|
|
||||||
#define SELF 0x00040000 // Self is single destination
|
|
||||||
#define ALLINC 0x00080000 // All including self
|
|
||||||
#define ALLEXC 0x000C0000 // All Excluding self
|
|
||||||
|
|
||||||
// ESR
|
|
||||||
#define SENDCS 0x00000001 // Send CS Error
|
|
||||||
#define RCVCS 0x00000002 // Receive CS Error
|
|
||||||
#define SENDACCEPT 0x00000004 // Send Accept Error
|
|
||||||
#define RCVACCEPT 0x00000008 // Receive Accept Error
|
|
||||||
#define SENDVECTOR 0x00000020 // Send Illegal Vector
|
|
||||||
#define RCVVECTOR 0x00000040 // Receive Illegal Vector
|
|
||||||
#define REGISTER 0x00000080 // Illegal Register Address
|
|
||||||
|
|
||||||
// [17] Timer Mode (RW)
|
|
||||||
#define ONESHOT 0x00000000 // One-shot
|
|
||||||
#define PERIODIC 0x00020000 // Periodic
|
|
||||||
|
|
||||||
// [19:18] Timer Base (RW)
|
|
||||||
#define CLKIN 0x00000000 // use CLKIN as input
|
|
||||||
#define TMBASE 0x00040000 // use TMBASE
|
|
||||||
#define DIVIDER 0x00080000 // use output of the divider
|
|
||||||
|
|
||||||
#define X2 0x00000000 // divide by 2
|
|
||||||
#define X4 0x00000001 // divide by 4
|
|
||||||
#define X8 0x00000002 // divide by 8
|
|
||||||
#define X16 0x00000003 // divide by 16
|
|
||||||
#define X32 0x00000008 // divide by 32
|
|
||||||
#define X64 0x00000009 // divide by 64
|
|
||||||
#define X128 0x0000000A // divide by 128
|
|
||||||
#define X1 0x0000000B // divide by 1
|
|
||||||
|
|
||||||
//PAGEBREAK!
|
|
||||||
volatile uint *lapic; // Initialized in mp.c
|
volatile uint *lapic; // Initialized in mp.c
|
||||||
|
|
||||||
|
//PAGEBREAK!
|
||||||
void
|
void
|
||||||
lapic_init(int c)
|
lapic_init(int c)
|
||||||
{
|
{
|
||||||
uint r, lvt;
|
|
||||||
|
|
||||||
if(!lapic)
|
if(!lapic)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lapic[DFR] = 0xFFFFFFFF; // Set dst format register
|
// Enable local APIC; set spurious interrupt vector.
|
||||||
r = (lapic[ID]>>24) & 0xFF; // Read APIC ID
|
|
||||||
lapic[LDR] = (1<<r) << 24;
|
|
||||||
lapic[TPR] = 0xFF; // No interrupts for now
|
|
||||||
|
|
||||||
// Enable APIC
|
|
||||||
lapic[SVR] = ENABLE | (IRQ_OFFSET+IRQ_SPURIOUS);
|
lapic[SVR] = ENABLE | (IRQ_OFFSET+IRQ_SPURIOUS);
|
||||||
|
|
||||||
// In virtual wire mode, set up the LINT0 and LINT1 as follows:
|
// The timer repeatedly counts down at bus frequency
|
||||||
lapic[LINT0] = APIC_IMASK | APIC_EXTINT;
|
// from lapic[TICR] and then issues an interrupt.
|
||||||
lapic[LINT1] = APIC_IMASK | APIC_NMI;
|
// Lapic[TCCR] is the current counter value.
|
||||||
|
// If xv6 cared more about precise timekeeping, the
|
||||||
|
// values of TICR and TCCR would be calibrated using
|
||||||
|
// an external time source.
|
||||||
|
lapic[TDCR] = X1;
|
||||||
|
lapic[TICR] = 10000000;
|
||||||
|
lapic[TCCR] = 10000000;
|
||||||
|
lapic[TIMER] = PERIODIC | (IRQ_OFFSET + IRQ_TIMER);
|
||||||
|
|
||||||
lapic[EOI] = 0; // Ack any outstanding interrupts.
|
// Disable logical interrupt lines.
|
||||||
|
lapic[LINT0] = MASKED;
|
||||||
|
lapic[LINT1] = MASKED;
|
||||||
|
|
||||||
lvt = (lapic[VER]>>16) & 0xFF;
|
// Disable performance counter overflow interrupts
|
||||||
if(lvt >= 4)
|
// on machines that provide that interrupt entry.
|
||||||
lapic[PCINT] = APIC_IMASK;
|
if(((lapic[VER]>>16) & 0xFF) >= 4)
|
||||||
|
lapic[PCINT] = MASKED;
|
||||||
|
|
||||||
|
// Map error interrupt to IRQ_ERROR.
|
||||||
lapic[ERROR] = IRQ_OFFSET+IRQ_ERROR;
|
lapic[ERROR] = IRQ_OFFSET+IRQ_ERROR;
|
||||||
lapic[ESR] = 0;
|
|
||||||
lapic[ESR];
|
|
||||||
|
|
||||||
// Issue an INIT Level De-Assert to synchronise arbitration ID's.
|
// Clear error status register (requires back-to-back writes).
|
||||||
|
lapic[ESR] = 0;
|
||||||
|
lapic[ESR] = 0;
|
||||||
|
|
||||||
|
// Ack any outstanding interrupts.
|
||||||
|
lapic[EOI] = 0;
|
||||||
|
|
||||||
|
// Send an Init Level De-Assert to synchronise arbitration ID's.
|
||||||
lapic[ICRHI] = 0;
|
lapic[ICRHI] = 0;
|
||||||
lapic[ICRLO] = ALLINC | APIC_LEVEL |
|
lapic[ICRLO] = BCAST | INIT | LEVEL;
|
||||||
DEASSERT | APIC_INIT;
|
while(lapic[ICRLO] & DELIVS)
|
||||||
while(lapic[ICRLO] & APIC_DELIVS)
|
|
||||||
;
|
;
|
||||||
|
|
||||||
// Initialize the interrupt timer.
|
// Enable interrupts on the APIC (but not on the processor).
|
||||||
// On real hardware would need to do more XXX.
|
|
||||||
lapic[TDCR] = X1;
|
|
||||||
lapic[TIMER] = CLKIN | PERIODIC | (IRQ_OFFSET + IRQ_TIMER);
|
|
||||||
lapic[TCCR] = 10000000;
|
|
||||||
lapic[TICR] = 10000000;
|
|
||||||
|
|
||||||
// Enable interrupts on the APIC (but not on processor).
|
|
||||||
lapic[TPR] = 0;
|
lapic[TPR] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,22 +105,34 @@ lapic_eoi(void)
|
||||||
lapic[EOI] = 0;
|
lapic[EOI] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Spin for a given number of microseconds.
|
||||||
|
// On real hardware would want to tune this dynamically.
|
||||||
|
static void
|
||||||
|
microdelay(int us)
|
||||||
|
{
|
||||||
|
volatile int j = 0;
|
||||||
|
|
||||||
|
while(us-- > 0)
|
||||||
|
for(j=0; j<10000; j++);
|
||||||
|
}
|
||||||
|
|
||||||
// Start additional processor running bootstrap code at addr.
|
// Start additional processor running bootstrap code at addr.
|
||||||
|
// See Appendix B of MultiProcessor Specification.
|
||||||
void
|
void
|
||||||
lapic_startap(uchar apicid, uint addr)
|
lapic_startap(uchar apicid, uint addr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
volatile int j = 0;
|
volatile int j = 0;
|
||||||
|
|
||||||
|
// Send INIT interrupt to reset other CPU.
|
||||||
lapic[ICRHI] = apicid<<24;
|
lapic[ICRHI] = apicid<<24;
|
||||||
lapic[ICRLO] = FIELD | APIC_LEVEL | ASSERT | APIC_INIT;
|
lapic[ICRLO] = INIT | LEVEL;
|
||||||
for(j=0; j<10000; j++); // 200us
|
microdelay(10);
|
||||||
lapic[ICRLO] = FIELD | APIC_LEVEL | DEASSERT | APIC_INIT;
|
|
||||||
for(j=0; j<1000000; j++); // 10ms
|
// Send startup IPI (twice!) to enter bootstrap code.
|
||||||
|
|
||||||
for(i = 0; i < 2; i++){
|
for(i = 0; i < 2; i++){
|
||||||
lapic[ICRHI] = apicid<<24;
|
lapic[ICRHI] = apicid<<24;
|
||||||
lapic[ICRLO] = FIELD | APIC_EDGE | APIC_STARTUP | (addr/4096);
|
lapic[ICRLO] = STARTUP | (addr>>12);
|
||||||
for(j=0; j<10000; j++); // 200us
|
for(j=0; j<10000; j++); // 200us
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
main.c
34
main.c
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
extern char edata[], end[];
|
extern char edata[], end[];
|
||||||
|
|
||||||
|
void bootothers(void);
|
||||||
|
|
||||||
// Bootstrap processor starts running C code here.
|
// Bootstrap processor starts running C code here.
|
||||||
// This is called main0 not main so that it can have
|
// This is called main0 not main so that it can have
|
||||||
// a void return type. Gcc can't handle functions named
|
// a void return type. Gcc can't handle functions named
|
||||||
|
@ -37,7 +39,7 @@ main0(void)
|
||||||
asm volatile("movl %0, %%ebp" : : "r" (cpus[bcpu].mpstack+MPSTACK));
|
asm volatile("movl %0, %%ebp" : : "r" (cpus[bcpu].mpstack+MPSTACK));
|
||||||
|
|
||||||
lapic_init(bcpu);
|
lapic_init(bcpu);
|
||||||
cprintf("\ncpu%d: starting xv6\n\n", cpu());
|
cprintf("\\ncpu%d: starting xv6\\n\\n", cpu());
|
||||||
|
|
||||||
pinit(); // process table
|
pinit(); // process table
|
||||||
binit(); // buffer cache
|
binit(); // buffer cache
|
||||||
|
@ -51,7 +53,7 @@ main0(void)
|
||||||
setupsegs(0); // segments & TSS
|
setupsegs(0); // segments & TSS
|
||||||
console_init(); // I/O devices & their interrupts
|
console_init(); // I/O devices & their interrupts
|
||||||
ide_init(); // disk
|
ide_init(); // disk
|
||||||
mp_startthem(); // other CPUs
|
bootothers(); // boot other CPUs
|
||||||
if(!ismp)
|
if(!ismp)
|
||||||
pit8253_timerinit(); // uniprocessor timer
|
pit8253_timerinit(); // uniprocessor timer
|
||||||
userinit(); // first user process
|
userinit(); // first user process
|
||||||
|
@ -67,7 +69,7 @@ main0(void)
|
||||||
void
|
void
|
||||||
mpmain(void)
|
mpmain(void)
|
||||||
{
|
{
|
||||||
cprintf("cpu%d: starting\n", cpu());
|
cprintf("cpu%d: starting\\n", cpu());
|
||||||
idtinit();
|
idtinit();
|
||||||
lapic_init(cpu());
|
lapic_init(cpu());
|
||||||
setupsegs(0);
|
setupsegs(0);
|
||||||
|
@ -82,3 +84,29 @@ mpmain(void)
|
||||||
scheduler();
|
scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bootothers(void)
|
||||||
|
{
|
||||||
|
extern uchar _binary_bootother_start[], _binary_bootother_size[];
|
||||||
|
uchar *code;
|
||||||
|
struct cpu *c;
|
||||||
|
|
||||||
|
// Write bootstrap code to unused memory at 0x7000.
|
||||||
|
code = (uchar*)0x7000;
|
||||||
|
memmove(code, _binary_bootother_start, (uint)_binary_bootother_size);
|
||||||
|
|
||||||
|
for(c = cpus; c < cpus+ncpu; c++){
|
||||||
|
if(c == cpus+cpu()) // We've started already.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Set target %esp, %eip
|
||||||
|
*(void**)(code-4) = c->mpstack + MPSTACK;
|
||||||
|
*(void**)(code-8) = mpmain;
|
||||||
|
lapic_startap(c->apicid, (uint)code);
|
||||||
|
|
||||||
|
// Wait for cpu to get through bootstrap.
|
||||||
|
while(c->booted == 0)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
208
mp.c
208
mp.c
|
@ -1,3 +1,5 @@
|
||||||
|
// http://developer.intel.com/design/pentium/datashts/24201606.pdf
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "mp.h"
|
#include "mp.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
@ -7,52 +9,39 @@
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
|
|
||||||
static char *buses[] = {
|
|
||||||
"CBUSI ",
|
|
||||||
"CBUSII",
|
|
||||||
"EISA ",
|
|
||||||
"FUTURE",
|
|
||||||
"INTERN",
|
|
||||||
"ISA ",
|
|
||||||
"MBI ",
|
|
||||||
"MBII ",
|
|
||||||
"MCA ",
|
|
||||||
"MPI ",
|
|
||||||
"MPSA ",
|
|
||||||
"NUBUS ",
|
|
||||||
"PCI ",
|
|
||||||
"PCMCIA",
|
|
||||||
"TC ",
|
|
||||||
"VL ",
|
|
||||||
"VME ",
|
|
||||||
"XPRESS",
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cpu cpus[NCPU];
|
struct cpu cpus[NCPU];
|
||||||
|
static struct cpu *bcpu;
|
||||||
int ismp;
|
int ismp;
|
||||||
int ncpu;
|
int ncpu;
|
||||||
uchar ioapic_id;
|
uchar ioapic_id;
|
||||||
|
|
||||||
static struct cpu *bcpu;
|
int
|
||||||
static struct mp *mp; // The floating MP structure
|
mp_bcpu(void)
|
||||||
|
|
||||||
static struct mp*
|
|
||||||
mp_scan(uchar *addr, int len)
|
|
||||||
{
|
{
|
||||||
uchar *e, *p, sum;
|
return bcpu-cpus;
|
||||||
int i;
|
}
|
||||||
|
|
||||||
|
static uchar
|
||||||
|
sum(uchar *addr, int len)
|
||||||
|
{
|
||||||
|
int i, sum;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
for(i=0; i<len; i++)
|
||||||
|
sum += addr[i];
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for an MP structure in the len bytes at addr.
|
||||||
|
static struct mp*
|
||||||
|
mp_search1(uchar *addr, int len)
|
||||||
|
{
|
||||||
|
uchar *e, *p;
|
||||||
|
|
||||||
e = addr+len;
|
e = addr+len;
|
||||||
for(p = addr; p < e; p += sizeof(struct mp)){
|
for(p = addr; p < e; p += sizeof(struct mp))
|
||||||
if(memcmp(p, "_MP_", 4))
|
if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
|
||||||
continue;
|
|
||||||
sum = 0;
|
|
||||||
for(i = 0; i < sizeof(struct mp); i++)
|
|
||||||
sum += p[i];
|
|
||||||
if(sum == 0)
|
|
||||||
return (struct mp*)p;
|
return (struct mp*)p;
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,110 +57,81 @@ mp_search(void)
|
||||||
uint p;
|
uint p;
|
||||||
struct mp *mp;
|
struct mp *mp;
|
||||||
|
|
||||||
bda = (uchar*) 0x400;
|
bda = (uchar*)0x400;
|
||||||
if((p = (bda[0x0F]<<8)|bda[0x0E])){
|
if((p = (bda[0x0F]<<8)|bda[0x0E])){
|
||||||
if((mp = mp_scan((uchar*) p, 1024)))
|
if((mp = mp_search1((uchar*)p, 1024)))
|
||||||
return mp;
|
return mp;
|
||||||
}else{
|
}else{
|
||||||
p = ((bda[0x14]<<8)|bda[0x13])*1024;
|
p = ((bda[0x14]<<8)|bda[0x13])*1024;
|
||||||
if((mp = mp_scan((uchar*)p-1024, 1024)))
|
if((mp = mp_search1((uchar*)p-1024, 1024)))
|
||||||
return mp;
|
return mp;
|
||||||
}
|
}
|
||||||
return mp_scan((uchar*)0xF0000, 0x10000);
|
return mp_search1((uchar*)0xF0000, 0x10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for an MP configuration table. For now,
|
// Search for an MP configuration table. For now,
|
||||||
// don't accept the default configurations (physaddr == 0).
|
// don't accept the default configurations (physaddr == 0).
|
||||||
// Check for correct signature, calculate the checksum and,
|
// Check for correct signature, calculate the checksum and,
|
||||||
// if correct, check the version.
|
// if correct, check the version.
|
||||||
// To do: check extended table checksum.
|
// To do: check extended table checksum.
|
||||||
static int
|
static struct mpconf*
|
||||||
mp_detect(void)
|
mp_config(struct mp **pmp)
|
||||||
{
|
{
|
||||||
struct mpctb *pcmp;
|
struct mpconf *conf;
|
||||||
uchar *p, sum;
|
struct mp *mp;
|
||||||
uint length;
|
|
||||||
|
|
||||||
if((mp = mp_search()) == 0 || mp->physaddr == 0)
|
if((mp = mp_search()) == 0 || mp->physaddr == 0)
|
||||||
return -1;
|
return 0;
|
||||||
|
conf = (struct mpconf*)mp->physaddr;
|
||||||
pcmp = (struct mpctb*) mp->physaddr;
|
if(memcmp(conf, "PCMP", 4) != 0)
|
||||||
if(memcmp(pcmp, "PCMP", 4) != 0)
|
return 0;
|
||||||
return -1;
|
if(conf->version != 1 && conf->version != 4)
|
||||||
if(pcmp->version != 1 && pcmp->version != 4)
|
return 0;
|
||||||
return -1;
|
if(sum((uchar*)conf, conf->length) != 0)
|
||||||
|
return 0;
|
||||||
length = pcmp->length;
|
*pmp = mp;
|
||||||
sum = 0;
|
return conf;
|
||||||
for(p = (uchar*)pcmp; length; length--)
|
|
||||||
sum += *p++;
|
|
||||||
if(sum != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mp_init(void)
|
mp_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
uchar *p, *e;
|
uchar *p, *e;
|
||||||
struct mpctb *mpctb;
|
struct mp *mp;
|
||||||
struct mppe *proc;
|
struct mpconf *conf;
|
||||||
struct mpbe *bus;
|
struct mpproc *proc;
|
||||||
struct mpioapic *ioapic;
|
struct mpioapic *ioapic;
|
||||||
struct mpie *intr;
|
|
||||||
|
|
||||||
ncpu = 0;
|
bcpu = &cpus[ncpu];
|
||||||
if(mp_detect() < 0)
|
if((conf = mp_config(&mp)) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ismp = 1;
|
ismp = 1;
|
||||||
|
lapic = (uint*)conf->lapicaddr;
|
||||||
|
|
||||||
// Run through the table saving information needed for starting
|
for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
|
||||||
// application processors and initialising any I/O APICs. The table
|
|
||||||
// is guaranteed to be in order such that only one pass is necessary.
|
|
||||||
|
|
||||||
mpctb = (struct mpctb*)mp->physaddr;
|
|
||||||
lapic = (uint*)mpctb->lapicaddr;
|
|
||||||
p = (uchar*)mpctb + sizeof(*mpctb);
|
|
||||||
e = (uchar*)mpctb + mpctb->length;
|
|
||||||
|
|
||||||
while(p < e) {
|
|
||||||
switch(*p){
|
switch(*p){
|
||||||
case MPPROCESSOR:
|
case MPPROC:
|
||||||
proc = (struct mppe*) p;
|
proc = (struct mpproc*)p;
|
||||||
cpus[ncpu].apicid = proc->apicid;
|
cpus[ncpu].apicid = proc->apicid;
|
||||||
if(proc->flags & MPBP) {
|
if(proc->flags & MPBOOT)
|
||||||
bcpu = &cpus[ncpu];
|
bcpu = &cpus[ncpu];
|
||||||
}
|
|
||||||
ncpu++;
|
ncpu++;
|
||||||
p += sizeof(struct mppe);
|
p += sizeof(struct mpproc);
|
||||||
continue;
|
|
||||||
case MPBUS:
|
|
||||||
bus = (struct mpbe*) p;
|
|
||||||
for(i = 0; buses[i]; i++){
|
|
||||||
if(strncmp(buses[i], bus->string, sizeof(bus->string)) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p += sizeof(struct mpbe);
|
|
||||||
continue;
|
continue;
|
||||||
case MPIOAPIC:
|
case MPIOAPIC:
|
||||||
ioapic = (struct mpioapic*) p;
|
ioapic = (struct mpioapic*)p;
|
||||||
ioapic_id = ioapic->apicno;
|
ioapic_id = ioapic->apicno;
|
||||||
p += sizeof(struct mpioapic);
|
p += sizeof(struct mpioapic);
|
||||||
continue;
|
continue;
|
||||||
|
case MPBUS:
|
||||||
case MPIOINTR:
|
case MPIOINTR:
|
||||||
intr = (struct mpie*) p;
|
case MPLINTR:
|
||||||
p += sizeof(struct mpie);
|
p += 8;
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
cprintf("mp_init: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p);
|
cprintf("mp_init: unknown config type %x\n", *p);
|
||||||
while(p < e){
|
panic("mp_init");
|
||||||
cprintf("%uX ", *p);
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,47 +142,3 @@ mp_init(void)
|
||||||
outb(0x23, inb(0x23) | 1); // Mask external interrupts.
|
outb(0x23, inb(0x23) | 1); // Mask external interrupts.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
mp_bcpu(void)
|
|
||||||
{
|
|
||||||
if(ismp)
|
|
||||||
return bcpu-cpus;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void mpmain(void);
|
|
||||||
|
|
||||||
// Write bootstrap code to unused memory at 0x7000.
|
|
||||||
#define APBOOTCODE 0x7000
|
|
||||||
|
|
||||||
void
|
|
||||||
mp_startthem(void)
|
|
||||||
{
|
|
||||||
extern uchar _binary_bootother_start[], _binary_bootother_size[];
|
|
||||||
extern int main();
|
|
||||||
int c;
|
|
||||||
|
|
||||||
memmove((void*) APBOOTCODE,_binary_bootother_start,
|
|
||||||
(uint) _binary_bootother_size);
|
|
||||||
|
|
||||||
for(c = 0; c < ncpu; c++){
|
|
||||||
// Our current cpu has already started.
|
|
||||||
if(c == cpu())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Set target %esp
|
|
||||||
*(uint*)(APBOOTCODE-4) = (uint) (cpus[c].mpstack) + MPSTACK;
|
|
||||||
|
|
||||||
// Set target %eip
|
|
||||||
*(uint*)(APBOOTCODE-8) = (uint)mpmain;
|
|
||||||
|
|
||||||
// Go!
|
|
||||||
lapic_startap(cpus[c].apicid, (uint)APBOOTCODE);
|
|
||||||
|
|
||||||
// Wait for cpu to get through bootstrap.
|
|
||||||
while(cpus[c].booted == 0)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
84
mp.h
84
mp.h
|
@ -1,4 +1,4 @@
|
||||||
// See MultiProcessor Specification Version 1.[14].
|
// See MultiProcessor Specification Version 1.[14]
|
||||||
|
|
||||||
struct mp { // floating pointer
|
struct mp { // floating pointer
|
||||||
uchar signature[4]; // "_MP_"
|
uchar signature[4]; // "_MP_"
|
||||||
|
@ -11,7 +11,7 @@ struct mp { // floating pointer
|
||||||
uchar reserved[3];
|
uchar reserved[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mpctb { // configuration table header
|
struct mpconf { // configuration table header
|
||||||
uchar signature[4]; // "PCMP"
|
uchar signature[4]; // "PCMP"
|
||||||
ushort length; // total table length
|
ushort length; // total table length
|
||||||
uchar version; // [14]
|
uchar version; // [14]
|
||||||
|
@ -26,22 +26,17 @@ struct mpctb { // configuration table header
|
||||||
uchar reserved;
|
uchar reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mppe { // processor table entry
|
struct mpproc { // processor table entry
|
||||||
uchar type; // entry type (0)
|
uchar type; // entry type (0)
|
||||||
uchar apicid; // local APIC id
|
uchar apicid; // local APIC id
|
||||||
uchar version; // local APIC verison
|
uchar version; // local APIC verison
|
||||||
uchar flags; // CPU flags
|
uchar flags; // CPU flags
|
||||||
|
#define MPBOOT 0x02 // This proc is the bootstrap processor.
|
||||||
uchar signature[4]; // CPU signature
|
uchar signature[4]; // CPU signature
|
||||||
uint feature; // feature flags from CPUID instruction
|
uint feature; // feature flags from CPUID instruction
|
||||||
uchar reserved[8];
|
uchar reserved[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mpbe { // bus table entry
|
|
||||||
uchar type; // entry type (1)
|
|
||||||
uchar busno; // bus id
|
|
||||||
char string[6]; // bus type string
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mpioapic { // I/O APIC table entry
|
struct mpioapic { // I/O APIC table entry
|
||||||
uchar type; // entry type (2)
|
uchar type; // entry type (2)
|
||||||
uchar apicno; // I/O APIC id
|
uchar apicno; // I/O APIC id
|
||||||
|
@ -50,69 +45,10 @@ struct mpioapic { // I/O APIC table entry
|
||||||
uint *addr; // I/O APIC address
|
uint *addr; // I/O APIC address
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mpie { // interrupt table entry
|
// Table entry types
|
||||||
uchar type; // entry type ([34])
|
#define MPPROC 0x00 // One per processor
|
||||||
uchar intr; // interrupt type
|
#define MPBUS 0x01 // One per bus
|
||||||
ushort flags; // interrupt flag
|
#define MPIOAPIC 0x02 // One per I/O APIC
|
||||||
uchar busno; // source bus id
|
#define MPIOINTR 0x03 // One per bus interrupt source
|
||||||
uchar irq; // source bus irq
|
#define MPLINTR 0x04 // One per system interrupt source
|
||||||
uchar apicno; // destination APIC id
|
|
||||||
uchar intin; // destination APIC [L]INTIN#
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { // table entry types
|
|
||||||
MPPROCESSOR = 0x00, // one entry per processor
|
|
||||||
MPBUS = 0x01, // one entry per bus
|
|
||||||
MPIOAPIC = 0x02, // one entry per I/O APIC
|
|
||||||
MPIOINTR = 0x03, // one entry per bus interrupt source
|
|
||||||
MPLINTR = 0x04, // one entry per system interrupt source
|
|
||||||
|
|
||||||
MPSASM = 0x80,
|
|
||||||
MPHIERARCHY = 0x81,
|
|
||||||
MPCBASM = 0x82,
|
|
||||||
|
|
||||||
// PCMPprocessor and PCMPioapic flags
|
|
||||||
MPEN = 0x01, // enabled
|
|
||||||
MPBP = 0x02, // bootstrap processor
|
|
||||||
|
|
||||||
// PCMPiointr and PCMPlintr flags
|
|
||||||
MPPOMASK = 0x03, // polarity conforms to bus specs
|
|
||||||
MPHIGH = 0x01, // active high
|
|
||||||
MPLOW = 0x03, // active low
|
|
||||||
MPELMASK = 0x0C, // trigger mode of APIC input signals
|
|
||||||
MPEDGE = 0x04, // edge-triggered
|
|
||||||
MPLEVEL = 0x0C, // level-triggered
|
|
||||||
|
|
||||||
// PCMPiointr and PCMPlintr interrupt type
|
|
||||||
MPINT = 0x00, // vectored interrupt from APIC Rdt
|
|
||||||
MPNMI = 0x01, // non-maskable interrupt
|
|
||||||
MPSMI = 0x02, // system management interrupt
|
|
||||||
MPExtINT = 0x03, // vectored interrupt from external PIC
|
|
||||||
};
|
|
||||||
|
|
||||||
// Common bits for
|
|
||||||
// I/O APIC Redirection Table Entry;
|
|
||||||
// Local APIC Local Interrupt Vector Table;
|
|
||||||
// Local APIC Inter-Processor Interrupt;
|
|
||||||
// Local APIC Timer Vector Table.
|
|
||||||
enum {
|
|
||||||
APIC_FIXED = 0x00000000, // [10:8] Delivery Mode
|
|
||||||
APIC_LOWEST = 0x00000100, // Lowest priority
|
|
||||||
APIC_SMI = 0x00000200, // System Management Interrupt
|
|
||||||
APIC_RR = 0x00000300, // Remote Read
|
|
||||||
APIC_NMI = 0x00000400,
|
|
||||||
APIC_INIT = 0x00000500, // INIT/RESET
|
|
||||||
APIC_STARTUP = 0x00000600, // Startup IPI
|
|
||||||
APIC_EXTINT = 0x00000700,
|
|
||||||
|
|
||||||
APIC_PHYSICAL = 0x00000000, // [11] Destination Mode (RW)
|
|
||||||
APIC_LOGICAL = 0x00000800,
|
|
||||||
|
|
||||||
APIC_DELIVS = 0x00001000, // [12] Delivery Status (RO)
|
|
||||||
APIC_HIGH = 0x00000000, // [13] Interrupt Input Pin Polarity (RW)
|
|
||||||
APIC_LOW = 0x00002000,
|
|
||||||
APIC_REMOTEIRR = 0x00004000, // [14] Remote IRR (RO)
|
|
||||||
APIC_EDGE = 0x00000000, // [15] Trigger Mode (RW)
|
|
||||||
APIC_LEVEL = 0x00008000,
|
|
||||||
APIC_IMASK = 0x00010000, // [16] Interrupt Mask
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in a new issue