From 99b11b6c64c17b94288c659e9398261e69a0cf75 Mon Sep 17 00:00:00 2001 From: rsc Date: Mon, 27 Aug 2007 22:53:31 +0000 Subject: [PATCH] Simplify MP hardware code. Mainly delete unused constants and code. Move mp_startthem to main.c as bootothers. --- ioapic.c | 97 +++++++++++++------------- ioapic.h | 88 ----------------------- lapic.c | 155 +++++++++++++++++------------------------ main.c | 34 ++++++++- mp.c | 208 +++++++++++++++++-------------------------------------- mp.h | 84 +++------------------- 6 files changed, 213 insertions(+), 453 deletions(-) delete mode 100644 ioapic.h 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" +#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 { - uint ioregsel; uint p01; uint p02; uint p03; - uint iowin; uint p11; uint p12; uint p13; + uint reg; + 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 -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<>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; - 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[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 - -static struct mp* -mp_scan(uchar *addr, int len) +int +mp_bcpu(void) { - uchar *e, *p, sum; - int i; + return bcpu-cpus; +} + +static uchar +sum(uchar *addr, int len) +{ + int i, sum; + + sum = 0; + for(i=0; iphysaddr == 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; papicid; - 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# -}; +// 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 -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 -};