summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsc <rsc>2007-08-27 22:53:31 +0000
committerrsc <rsc>2007-08-27 22:53:31 +0000
commit99b11b6c64c17b94288c659e9398261e69a0cf75 (patch)
treec45cb8b500f14dbe69c3cba41dfa66766e589a63
parentb63bb0fd00cb34ed1d776e6836f5a2bb90de98c1 (diff)
downloadxv6-labs-99b11b6c64c17b94288c659e9398261e69a0cf75.tar.gz
xv6-labs-99b11b6c64c17b94288c659e9398261e69a0cf75.tar.bz2
xv6-labs-99b11b6c64c17b94288c659e9398261e69a0cf75.zip
Simplify MP hardware code.
Mainly delete unused constants and code. Move mp_startthem to main.c as bootothers.
-rw-r--r--ioapic.c97
-rw-r--r--ioapic.h88
-rw-r--r--lapic.c153
-rw-r--r--main.c34
-rw-r--r--mp.c204
-rw-r--r--mp.h84
6 files changed, 210 insertions, 450 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);
}
diff --git a/ioapic.h b/ioapic.h
deleted file mode 100644
index a85f810..0000000
--- a/ioapic.h
+++ /dev/null
@@ -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
diff --git a/lapic.c b/lapic.c
index 7f2940c..6afc3b8 100644
--- a/lapic.c
+++ b/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 "mp.h"
#include "defs.h"
#include "param.h"
#include "x86.h"
#include "traps.h"
#include "mmu.h"
#include "proc.h"
-#include "lapic.h"
// Local APIC registers, divided by 4 for use as uint[] indices.
#define ID (0x0020/4) // ID
#define VER (0x0030/4) // Version
#define TPR (0x0080/4) // Task Priority
-#define APR (0x0090/4) // Arbitration Priority
-#define PPR (0x00A0/4) // Processor Priority
#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 ISR (0x0100/4) // Interrupt Status (8 registers)
-#define TMR (0x0180/4) // Trigger Mode (8 registers)
-#define IRR (0x0200/4) // Interrupt Request (8 registers)
+ #define ENABLE 0x00000100 // Unit Enable
#define ESR (0x0280/4) // Error Status
#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 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 LINT0 (0x0350/4) // Local Vector Table 1 (LINT0)
#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1)
#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR)
+ #define MASKED 0x00010000 // Interrupt masked
#define TICR (0x0380/4) // Timer Initial Count
#define TCCR (0x0390/4) // Timer Current Count
#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
+//PAGEBREAK!
void
lapic_init(int c)
{
- uint r, lvt;
-
if(!lapic)
return;
- lapic[DFR] = 0xFFFFFFFF; // Set dst format register
- r = (lapic[ID]>>24) & 0xFF; // Read APIC ID
- lapic[LDR] = (1<<r) << 24;
- lapic[TPR] = 0xFF; // No interrupts for now
-
- // Enable APIC
+ // Enable local APIC; set spurious interrupt vector.
lapic[SVR] = ENABLE | (IRQ_OFFSET+IRQ_SPURIOUS);
- // In virtual wire mode, set up the LINT0 and LINT1 as follows:
- lapic[LINT0] = APIC_IMASK | APIC_EXTINT;
- lapic[LINT1] = APIC_IMASK | APIC_NMI;
+ // The timer repeatedly counts down at bus frequency
+ // from lapic[TICR] and then issues an interrupt.
+ // 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;
- if(lvt >= 4)
- lapic[PCINT] = APIC_IMASK;
+ // Disable performance counter overflow interrupts
+ // on machines that provide that interrupt entry.
+ if(((lapic[VER]>>16) & 0xFF) >= 4)
+ lapic[PCINT] = MASKED;
+
+ // Map error interrupt to IRQ_ERROR.
lapic[ERROR] = IRQ_OFFSET+IRQ_ERROR;
+
+ // Clear error status register (requires back-to-back writes).
lapic[ESR] = 0;
- lapic[ESR];
+ lapic[ESR] = 0;
+
+ // Ack any outstanding interrupts.
+ lapic[EOI] = 0;
- // Issue an INIT Level De-Assert to synchronise arbitration ID's.
+ // Send an Init Level De-Assert to synchronise arbitration ID's.
lapic[ICRHI] = 0;
- lapic[ICRLO] = ALLINC | APIC_LEVEL |
- DEASSERT | APIC_INIT;
- while(lapic[ICRLO] & APIC_DELIVS)
+ lapic[ICRLO] = BCAST | INIT | LEVEL;
+ while(lapic[ICRLO] & DELIVS)
;
- // Initialize the interrupt timer.
- // 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).
+ // Enable interrupts on the APIC (but not on the processor).
lapic[TPR] = 0;
}
@@ -146,22 +105,34 @@ lapic_eoi(void)
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.
+// See Appendix B of MultiProcessor Specification.
void
lapic_startap(uchar apicid, uint addr)
{
int i;
volatile int j = 0;
+ // Send INIT interrupt to reset other CPU.
lapic[ICRHI] = apicid<<24;
- lapic[ICRLO] = FIELD | APIC_LEVEL | ASSERT | APIC_INIT;
- for(j=0; j<10000; j++); // 200us
- lapic[ICRLO] = FIELD | APIC_LEVEL | DEASSERT | APIC_INIT;
- for(j=0; j<1000000; j++); // 10ms
-
+ lapic[ICRLO] = INIT | LEVEL;
+ microdelay(10);
+
+ // Send startup IPI (twice!) to enter bootstrap code.
for(i = 0; i < 2; i++){
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
}
}
diff --git a/main.c b/main.c
index 29a8d34..a8b3f62 100644
--- a/main.c
+++ b/main.c
@@ -12,6 +12,8 @@
extern char edata[], end[];
+void bootothers(void);
+
// Bootstrap processor starts running C code here.
// This is called main0 not main so that it can have
// 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));
lapic_init(bcpu);
- cprintf("\ncpu%d: starting xv6\n\n", cpu());
+ cprintf("\\ncpu%d: starting xv6\\n\\n", cpu());
pinit(); // process table
binit(); // buffer cache
@@ -51,7 +53,7 @@ main0(void)
setupsegs(0); // segments & TSS
console_init(); // I/O devices & their interrupts
ide_init(); // disk
- mp_startthem(); // other CPUs
+ bootothers(); // boot other CPUs
if(!ismp)
pit8253_timerinit(); // uniprocessor timer
userinit(); // first user process
@@ -67,7 +69,7 @@ main0(void)
void
mpmain(void)
{
- cprintf("cpu%d: starting\n", cpu());
+ cprintf("cpu%d: starting\\n", cpu());
idtinit();
lapic_init(cpu());
setupsegs(0);
@@ -82,3 +84,29 @@ mpmain(void)
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)
+ ;
+ }
+}
+
diff --git a/mp.c b/mp.c
index 2cfea01..edd85df 100644
--- a/mp.c
+++ b/mp.c
@@ -1,3 +1,5 @@
+// http://developer.intel.com/design/pentium/datashts/24201606.pdf
+
#include "types.h"
#include "mp.h"
#include "defs.h"
@@ -7,52 +9,39 @@
#include "mmu.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];
+static struct cpu *bcpu;
int ismp;
int ncpu;
uchar ioapic_id;
-static struct cpu *bcpu;
-static struct mp *mp; // The floating MP structure
+int
+mp_bcpu(void)
+{
+ return bcpu-cpus;
+}
+
+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_scan(uchar *addr, int len)
+mp_search1(uchar *addr, int len)
{
- uchar *e, *p, sum;
- int i;
+ uchar *e, *p;
e = addr+len;
- for(p = addr; p < e; p += sizeof(struct mp)){
- if(memcmp(p, "_MP_", 4))
- continue;
- sum = 0;
- for(i = 0; i < sizeof(struct mp); i++)
- sum += p[i];
- if(sum == 0)
+ for(p = addr; p < e; p += sizeof(struct mp))
+ if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
return (struct mp*)p;
- }
return 0;
}
@@ -68,110 +57,81 @@ mp_search(void)
uint p;
struct mp *mp;
- bda = (uchar*) 0x400;
+ bda = (uchar*)0x400;
if((p = (bda[0x0F]<<8)|bda[0x0E])){
- if((mp = mp_scan((uchar*) p, 1024)))
+ if((mp = mp_search1((uchar*)p, 1024)))
return mp;
}else{
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_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).
// Check for correct signature, calculate the checksum and,
// if correct, check the version.
// To do: check extended table checksum.
-static int
-mp_detect(void)
+static struct mpconf*
+mp_config(struct mp **pmp)
{
- struct mpctb *pcmp;
- uchar *p, sum;
- uint length;
+ struct mpconf *conf;
+ struct mp *mp;
if((mp = mp_search()) == 0 || mp->physaddr == 0)
- return -1;
-
- pcmp = (struct mpctb*) mp->physaddr;
- if(memcmp(pcmp, "PCMP", 4) != 0)
- return -1;
- if(pcmp->version != 1 && pcmp->version != 4)
- return -1;
-
- length = pcmp->length;
- sum = 0;
- for(p = (uchar*)pcmp; length; length--)
- sum += *p++;
- if(sum != 0)
- return -1;
-
- return 0;
+ return 0;
+ conf = (struct mpconf*)mp->physaddr;
+ if(memcmp(conf, "PCMP", 4) != 0)
+ return 0;
+ if(conf->version != 1 && conf->version != 4)
+ return 0;
+ if(sum((uchar*)conf, conf->length) != 0)
+ return 0;
+ *pmp = mp;
+ return conf;
}
void
mp_init(void)
{
- int i;
uchar *p, *e;
- struct mpctb *mpctb;
- struct mppe *proc;
- struct mpbe *bus;
+ struct mp *mp;
+ struct mpconf *conf;
+ struct mpproc *proc;
struct mpioapic *ioapic;
- struct mpie *intr;
- ncpu = 0;
- if(mp_detect() < 0)
+ bcpu = &cpus[ncpu];
+ if((conf = mp_config(&mp)) == 0)
return;
ismp = 1;
+ lapic = (uint*)conf->lapicaddr;
- // Run through the table saving information needed for starting
- // 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) {
+ for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
switch(*p){
- case MPPROCESSOR:
- proc = (struct mppe*) p;
+ case MPPROC:
+ proc = (struct mpproc*)p;
cpus[ncpu].apicid = proc->apicid;
- if(proc->flags & MPBP) {
+ if(proc->flags & MPBOOT)
bcpu = &cpus[ncpu];
- }
ncpu++;
- p += sizeof(struct mppe);
- 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);
+ p += sizeof(struct mpproc);
continue;
case MPIOAPIC:
- ioapic = (struct mpioapic*) p;
+ ioapic = (struct mpioapic*)p;
ioapic_id = ioapic->apicno;
p += sizeof(struct mpioapic);
continue;
+ case MPBUS:
case MPIOINTR:
- intr = (struct mpie*) p;
- p += sizeof(struct mpie);
+ case MPLINTR:
+ p += 8;
continue;
default:
- cprintf("mp_init: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p);
- while(p < e){
- cprintf("%uX ", *p);
- p++;
- }
- break;
+ cprintf("mp_init: unknown config type %x\n", *p);
+ panic("mp_init");
}
}
@@ -182,47 +142,3 @@ mp_init(void)
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)
- ;
- }
-}
diff --git a/mp.h b/mp.h
index b7c72d8..6453f65 100644
--- a/mp.h
+++ b/mp.h
@@ -1,4 +1,4 @@
-// See MultiProcessor Specification Version 1.[14].
+// See MultiProcessor Specification Version 1.[14]
struct mp { // floating pointer
uchar signature[4]; // "_MP_"
@@ -11,7 +11,7 @@ struct mp { // floating pointer
uchar reserved[3];
};
-struct mpctb { // configuration table header
+struct mpconf { // configuration table header
uchar signature[4]; // "PCMP"
ushort length; // total table length
uchar version; // [14]
@@ -26,22 +26,17 @@ struct mpctb { // configuration table header
uchar reserved;
};
-struct mppe { // processor table entry
+struct mpproc { // processor table entry
uchar type; // entry type (0)
uchar apicid; // local APIC id
uchar version; // local APIC verison
uchar flags; // CPU flags
+ #define MPBOOT 0x02 // This proc is the bootstrap processor.
uchar signature[4]; // CPU signature
uint feature; // feature flags from CPUID instruction
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
uchar type; // entry type (2)
uchar apicno; // I/O APIC id
@@ -50,69 +45,10 @@ struct mpioapic { // I/O APIC table entry
uint *addr; // I/O APIC address
};
-struct mpie { // interrupt table entry
- uchar type; // entry type ([34])
- uchar intr; // interrupt type
- ushort flags; // interrupt flag
- uchar busno; // source bus id
- uchar irq; // source bus irq
- 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,
+// Table entry types
+#define MPPROC 0x00 // One per processor
+#define MPBUS 0x01 // One per bus
+#define MPIOAPIC 0x02 // One per I/O APIC
+#define MPIOINTR 0x03 // One per bus interrupt source
+#define MPLINTR 0x04 // One per system interrupt source
- 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
-};