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
					
				
					 6 changed files with 213 additions and 453 deletions
				
			
		
							
								
								
									
										95
									
								
								ioapic.c
									
										
									
									
									
								
							
							
						
						
									
										95
									
								
								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
 | 
					 | 
				
			||||||
							
								
								
									
										153
									
								
								lapic.c
									
										
									
									
									
								
							
							
						
						
									
										153
									
								
								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)
 | 
				
			||||||
 | 
					      ;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										200
									
								
								mp.c
									
										
									
									
									
								
							
							
						
						
									
										200
									
								
								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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,14 +59,14 @@ mp_search(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  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,
 | 
				
			||||||
| 
						 | 
					@ -85,93 +74,64 @@ mp_search(void)
 | 
				
			||||||
// 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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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
 | 
					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…
	
	Add table
		Add a link
		
	
		Reference in a new issue