start on MP; detect MP configuration
This commit is contained in:
		
							parent
							
								
									ae6e8aa730
								
							
						
					
					
						commit
						7baa34a421
					
				
					 7 changed files with 323 additions and 2 deletions
				
			
		
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o \
 | 
			
		||||
       syscall.o ide.o picirq.o
 | 
			
		||||
       syscall.o ide.o picirq.o mp.o
 | 
			
		||||
 | 
			
		||||
CC = i386-jos-elf-gcc
 | 
			
		||||
LD = i386-jos-elf-ld
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								defs.h
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								defs.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -21,6 +21,7 @@ void tinit(void);
 | 
			
		|||
// string.c
 | 
			
		||||
void * memcpy(void *dst, void *src, unsigned n);
 | 
			
		||||
void * memset(void *dst, int c, unsigned n);
 | 
			
		||||
int memcmp(const void *v1, const void *v2, unsigned n);
 | 
			
		||||
 | 
			
		||||
// syscall.c
 | 
			
		||||
void syscall(void);
 | 
			
		||||
| 
						 | 
				
			
			@ -28,3 +29,7 @@ void syscall(void);
 | 
			
		|||
// picirq.c
 | 
			
		||||
void irq_setmask_8259A(uint16_t mask);
 | 
			
		||||
void pic_init(void);
 | 
			
		||||
 | 
			
		||||
// mp.c
 | 
			
		||||
void mpinit(void);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								main.c
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								main.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -22,6 +22,7 @@ main()
 | 
			
		|||
 | 
			
		||||
  cprintf("\nxV6\n\n");
 | 
			
		||||
 | 
			
		||||
  mpinit(); // multiprocessor
 | 
			
		||||
  kinit(); // physical memory allocator
 | 
			
		||||
  tinit(); // traps and interrupts
 | 
			
		||||
  pic_init();
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +48,7 @@ main()
 | 
			
		|||
  write_eflags(read_eflags() | FL_IF);
 | 
			
		||||
  irq_setmask_8259A(0);
 | 
			
		||||
 | 
			
		||||
#if 1
 | 
			
		||||
#if 0
 | 
			
		||||
  ide_read(0, buf, 1);
 | 
			
		||||
  cprintf("sec0.0 %x\n", buf[0] & 0xff);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								memlayout.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								memlayout.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
#define EXTPHYSMEM 0x100000
 | 
			
		||||
 | 
			
		||||
#define KADDR(a) ((void *) a)
 | 
			
		||||
							
								
								
									
										139
									
								
								mp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								mp.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,139 @@
 | 
			
		|||
#include "types.h"
 | 
			
		||||
#include "mp.h"
 | 
			
		||||
#include "defs.h"
 | 
			
		||||
#include "memlayout.h"
 | 
			
		||||
 | 
			
		||||
static struct _MP_* _mp_;  /* The MP floating point structure */
 | 
			
		||||
static int ncpu;
 | 
			
		||||
 | 
			
		||||
static struct _MP_*
 | 
			
		||||
mp_scan(uint8_t *addr, int len)
 | 
			
		||||
{
 | 
			
		||||
  uint8_t *e, *p, sum;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  cprintf("scanning: 0x%x\n", (uint32_t)addr);
 | 
			
		||||
  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)
 | 
			
		||||
      return (struct _MP_ *)p;
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct _MP_*
 | 
			
		||||
mp_search(void)
 | 
			
		||||
{
 | 
			
		||||
  uint8_t *bda;
 | 
			
		||||
  uint32_t p;
 | 
			
		||||
  struct _MP_ *mp;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Search for the MP Floating Pointer Structure, which according to the
 | 
			
		||||
   * spec is in one of the following three locations:
 | 
			
		||||
   * 1) in the first KB of the EBDA;
 | 
			
		||||
   * 2) in the last KB of system base memory;
 | 
			
		||||
   * 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
 | 
			
		||||
   */
 | 
			
		||||
  bda = KADDR(0x400);
 | 
			
		||||
  if((p = (bda[0x0F]<<8)|bda[0x0E])){
 | 
			
		||||
    if((mp = mp_scan(KADDR(p), 1024)))
 | 
			
		||||
      return mp;
 | 
			
		||||
  }
 | 
			
		||||
  else{
 | 
			
		||||
    p = ((bda[0x14]<<8)|bda[0x13])*1024;
 | 
			
		||||
    if((mp = mp_scan(KADDR(p-1024), 1024)))
 | 
			
		||||
      return mp;
 | 
			
		||||
  }
 | 
			
		||||
  return mp_scan(KADDR(0xF0000), 0x10000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int 
 | 
			
		||||
mp_detect(void)
 | 
			
		||||
{
 | 
			
		||||
  struct PCMP *pcmp;
 | 
			
		||||
  uint8_t *p, sum;
 | 
			
		||||
  uint32_t length;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * 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.
 | 
			
		||||
   */
 | 
			
		||||
  if((_mp_ = mp_search()) == 0 || _mp_->physaddr == 0)
 | 
			
		||||
    return 1;
 | 
			
		||||
 | 
			
		||||
  pcmp = KADDR(_mp_->physaddr);
 | 
			
		||||
  if(memcmp(pcmp, "PCMP", 4))
 | 
			
		||||
    return 2;
 | 
			
		||||
 | 
			
		||||
  length = pcmp->length;
 | 
			
		||||
  sum = 0;
 | 
			
		||||
  for(p = (uint8_t*)pcmp; length; length--)
 | 
			
		||||
    sum += *p++;
 | 
			
		||||
 | 
			
		||||
  if(sum || (pcmp->version != 1 && pcmp->version != 4))
 | 
			
		||||
    return 3;
 | 
			
		||||
 | 
			
		||||
  cprintf("MP spec rev #: %x\n", _mp_->specrev);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
mpinit()
 | 
			
		||||
{ 
 | 
			
		||||
  int r;
 | 
			
		||||
  uint8_t *p, *e;
 | 
			
		||||
  struct PCMP *pcmp;
 | 
			
		||||
 | 
			
		||||
  ncpu = 0;
 | 
			
		||||
  if ((r = mp_detect()) != 0) return;
 | 
			
		||||
  cprintf ("This computer is multiprocessor!\n");
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * 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.
 | 
			
		||||
   */
 | 
			
		||||
  pcmp = KADDR(_mp_->physaddr);
 | 
			
		||||
  p = ((uint8_t*)pcmp)+sizeof(struct PCMP);
 | 
			
		||||
  e = ((uint8_t*)pcmp)+pcmp->length;
 | 
			
		||||
 | 
			
		||||
  while(p < e) {
 | 
			
		||||
    switch(*p){
 | 
			
		||||
    case PcmpPROCESSOR:
 | 
			
		||||
      cprintf("a processor\n");
 | 
			
		||||
      ncpu++;
 | 
			
		||||
      p += sizeof(struct PCMPprocessor);
 | 
			
		||||
      continue;
 | 
			
		||||
    case PcmpBUS:
 | 
			
		||||
      cprintf("a bus\n");
 | 
			
		||||
      p += sizeof(struct PCMPbus);
 | 
			
		||||
      continue;
 | 
			
		||||
    case PcmpIOAPIC:
 | 
			
		||||
      cprintf("an IO APIC\n");
 | 
			
		||||
      p += sizeof(struct PCMPioapic);
 | 
			
		||||
      continue;
 | 
			
		||||
    case PcmpIOINTR:
 | 
			
		||||
      cprintf("an IO interrupt assignment\n");
 | 
			
		||||
      p += sizeof(struct PCMPintr);
 | 
			
		||||
      continue;
 | 
			
		||||
    default:
 | 
			
		||||
      cprintf("mpinit: unknown PCMP type 0x%x (e-p 0x%x)\n", *p, e-p);
 | 
			
		||||
      while(p < e){
 | 
			
		||||
	cprintf("%uX ", *p);
 | 
			
		||||
	p++;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cprintf("ncpu: %d\n", ncpu);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										158
									
								
								mp.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								mp.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,158 @@
 | 
			
		|||
/*
 | 
			
		||||
 * MultiProcessor Specification Version 1.[14].
 | 
			
		||||
 */
 | 
			
		||||
struct _MP_ {			/* floating pointer */
 | 
			
		||||
  uint8_t signature[4];		/* "_MP_" */
 | 
			
		||||
  physaddr_t physaddr;	        /* physical address of MP configuration table */
 | 
			
		||||
  uint8_t length;		/* 1 */
 | 
			
		||||
  uint8_t specrev;		/* [14] */
 | 
			
		||||
  uint8_t checksum;		/* all bytes must add up to 0 */
 | 
			
		||||
  uint8_t type;			/* MP system configuration type */
 | 
			
		||||
  uint8_t imcrp;
 | 
			
		||||
  uint8_t reserved[3];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PCMP {			/* configuration table header */
 | 
			
		||||
  uint8_t signature[4];		/* "PCMP" */
 | 
			
		||||
  uint16_t length;		/* total table length */
 | 
			
		||||
  uint8_t version;		/* [14] */
 | 
			
		||||
  uint8_t checksum;		/* all bytes must add up to 0 */
 | 
			
		||||
  uint8_t product[20];		/* product id */
 | 
			
		||||
  uintptr_t oemtable;		/* OEM table pointer */
 | 
			
		||||
  uint16_t oemlength;		/* OEM table length */
 | 
			
		||||
  uint16_t entry;		/* entry count */
 | 
			
		||||
  uintptr_t lapicbase;		/* address of local APIC */
 | 
			
		||||
  uint16_t xlength;		/* extended table length */
 | 
			
		||||
  uint8_t xchecksum;		/* extended table checksum */
 | 
			
		||||
  uint8_t reserved;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PCMPprocessor {		/* processor table entry */
 | 
			
		||||
  uint8_t type;			/* entry type (0) */
 | 
			
		||||
  uint8_t apicno;		/* local APIC id */
 | 
			
		||||
  uint8_t version;		/* local APIC verison */
 | 
			
		||||
  uint8_t flags;		/* CPU flags */
 | 
			
		||||
  uint8_t signature[4];		/* CPU signature */
 | 
			
		||||
  uint32_t feature;		/* feature flags from CPUID instruction */
 | 
			
		||||
  uint8_t reserved[8];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PCMPbus {		/* bus table entry */
 | 
			
		||||
  uint8_t type;			/* entry type (1) */
 | 
			
		||||
  uint8_t busno;		/* bus id */
 | 
			
		||||
  char string[6];		/* bus type string */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PCMPioapic {		/* I/O APIC table entry */
 | 
			
		||||
  uint8_t type;			/* entry type (2) */
 | 
			
		||||
  uint8_t apicno;		/* I/O APIC id */
 | 
			
		||||
  uint8_t version;		/* I/O APIC version */
 | 
			
		||||
  uint8_t flags;		/* I/O APIC flags */
 | 
			
		||||
  uintptr_t addr;		/* I/O APIC address */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PCMPintr {		/* interrupt table entry */
 | 
			
		||||
  uint8_t type;			/* entry type ([34]) */
 | 
			
		||||
  uint8_t intr;			/* interrupt type */
 | 
			
		||||
  uint16_t flags;		/* interrupt flag */
 | 
			
		||||
  uint8_t busno;		/* source bus id */
 | 
			
		||||
  uint8_t irq;			/* source bus irq */
 | 
			
		||||
  uint8_t apicno;		/* destination APIC id */
 | 
			
		||||
  uint8_t intin;		/* destination APIC [L]INTIN# */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PCMPsasm {		/* system address space mapping entry */
 | 
			
		||||
  uint8_t type;			/* entry type (128) */
 | 
			
		||||
  uint8_t length;		/* of this entry (20) */
 | 
			
		||||
  uint8_t busno;		/* bus id */
 | 
			
		||||
  uint8_t addrtype;
 | 
			
		||||
  uintptr_t addrbase[2];
 | 
			
		||||
  uint32_t addrlength[2];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PCMPhierarchy {		/* bus hierarchy descriptor entry */
 | 
			
		||||
  uint8_t type;			/* entry type (129) */
 | 
			
		||||
  uint8_t length;		/* of this entry (8) */
 | 
			
		||||
  uint8_t busno;		/* bus id */
 | 
			
		||||
  uint8_t info;			/* bus info */
 | 
			
		||||
  uint8_t parent;		/* parent bus */
 | 
			
		||||
  uint8_t reserved[3];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PCMPcbasm {		/* compatibility bus address space modifier entry */
 | 
			
		||||
  uint8_t type;			/* entry type (130) */
 | 
			
		||||
  uint8_t length;		/* of this entry (8) */
 | 
			
		||||
  uint8_t busno;		/* bus id */
 | 
			
		||||
  uint8_t modifier;		/* address modifier */
 | 
			
		||||
  uint32_t range;		/* predefined range list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {				/* table entry types */
 | 
			
		||||
  PcmpPROCESSOR	= 0x00,		/* one entry per processor */
 | 
			
		||||
  PcmpBUS = 0x01,		/* one entry per bus */
 | 
			
		||||
  PcmpIOAPIC = 0x02,		/* one entry per I/O APIC */
 | 
			
		||||
  PcmpIOINTR = 0x03,		/* one entry per bus interrupt source */
 | 
			
		||||
  PcmpLINTR = 0x04,		/* one entry per system interrupt source */
 | 
			
		||||
 | 
			
		||||
  PcmpSASM = 0x80,
 | 
			
		||||
  PcmpHIERARCHY	= 0x81,
 | 
			
		||||
  PcmpCBASM = 0x82,
 | 
			
		||||
 | 
			
		||||
  /* PCMPprocessor and PCMPioapic flags */
 | 
			
		||||
  PcmpEN = 0x01,		/* enabled */
 | 
			
		||||
  PcmpBP = 0x02,		/* bootstrap processor */
 | 
			
		||||
 | 
			
		||||
				/* PCMPiointr and PCMPlintr flags */
 | 
			
		||||
  PcmpPOMASK = 0x03,		/* polarity conforms to specifications of bus */
 | 
			
		||||
  PcmpHIGH = 0x01,		/* active high */
 | 
			
		||||
  PcmpLOW = 0x03,		/* active low */
 | 
			
		||||
  PcmpELMASK = 0x0C,		/* trigger mode of APIC input signals */
 | 
			
		||||
  PcmpEDGE = 0x04,		/* edge-triggered */
 | 
			
		||||
  PcmpLEVEL = 0x0C,		/* level-triggered */
 | 
			
		||||
 | 
			
		||||
  /* PCMPiointr and PCMPlintr interrupt type */
 | 
			
		||||
  PcmpINT = 0x00,		/* vectored interrupt from APIC Rdt */
 | 
			
		||||
  PcmpNMI = 0x01,		/* non-maskable interrupt */
 | 
			
		||||
  PcmpSMI = 0x02,		/* system management interrupt */
 | 
			
		||||
  PcmpExtINT = 0x03,		/* vectored interrupt from external PIC */
 | 
			
		||||
 | 
			
		||||
  /* PCMPsasm addrtype */
 | 
			
		||||
  PcmpIOADDR = 0x00,		/* I/O address */
 | 
			
		||||
  PcmpMADDR = 0x01,		/* memory address */
 | 
			
		||||
  PcmpPADDR = 0x02,		/* prefetch address */
 | 
			
		||||
 | 
			
		||||
  /* PCMPhierarchy info */
 | 
			
		||||
  PcmpSD = 0x01,		/* subtractive decode bus */
 | 
			
		||||
 | 
			
		||||
				/* PCMPcbasm modifier */
 | 
			
		||||
  PcmpPR = 0x01,		/* predefined range list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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 {
 | 
			
		||||
  ApicFIXED = 0x00000000,	/* [10:8] Delivery Mode */
 | 
			
		||||
  ApicLOWEST = 0x00000100,	/* Lowest priority */
 | 
			
		||||
  ApicSMI = 0x00000200,	        /* System Management Interrupt */
 | 
			
		||||
  ApicRR = 0x00000300,	        /* Remote Read */
 | 
			
		||||
  ApicNMI = 0x00000400,
 | 
			
		||||
  ApicINIT = 0x00000500,	/* INIT/RESET */
 | 
			
		||||
  ApicSTARTUP = 0x00000600,	/* Startup IPI */
 | 
			
		||||
  ApicExtINT = 0x00000700,
 | 
			
		||||
 | 
			
		||||
  ApicPHYSICAL = 0x00000000,	/* [11] Destination Mode (RW) */
 | 
			
		||||
  ApicLOGICAL = 0x00000800,
 | 
			
		||||
 | 
			
		||||
  ApicDELIVS = 0x00001000,	/* [12] Delivery Status (RO) */
 | 
			
		||||
  ApicHIGH = 0x00000000,	/* [13] Interrupt Input Pin Polarity (RW) */
 | 
			
		||||
  ApicLOW = 0x00002000,
 | 
			
		||||
  ApicRemoteIRR	= 0x00004000,	/* [14] Remote IRR (RO) */
 | 
			
		||||
  ApicEDGE = 0x00000000,	/* [15] Trigger Mode (RW) */
 | 
			
		||||
  ApicLEVEL = 0x00008000,
 | 
			
		||||
  ApicIMASK = 0x00010000,	/* [16] Interrupt Mask */
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										15
									
								
								string.c
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								string.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -23,3 +23,18 @@ memset(void *dst, int c, unsigned n)
 | 
			
		|||
 | 
			
		||||
  return dst;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
memcmp(const void *v1, const void *v2, unsigned n)
 | 
			
		||||
{
 | 
			
		||||
  const uint8_t *s1 = (const uint8_t *) v1;
 | 
			
		||||
  const uint8_t *s2 = (const uint8_t *) v2;
 | 
			
		||||
 | 
			
		||||
  while (n-- > 0) {
 | 
			
		||||
    if (*s1 != *s2)
 | 
			
		||||
      return (int) *s1 - (int) *s2;
 | 
			
		||||
    s1++, s2++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue