]> Devi Nivas Git - cs3210-lab0.git/commitdiff
start on MP; detect MP configuration
authorkaashoek <kaashoek>
Wed, 21 Jun 2006 01:53:07 +0000 (01:53 +0000)
committerkaashoek <kaashoek>
Wed, 21 Jun 2006 01:53:07 +0000 (01:53 +0000)
Makefile
defs.h
main.c
memlayout.h [new file with mode: 0644]
mp.c [new file with mode: 0644]
mp.h [new file with mode: 0644]
string.c

index 81241f4db97983983ae83168fe07156040bf95e3..936bc40ae8260eda2dd7427f14e41ba9907caa4b 100644 (file)
--- a/Makefile
+++ b/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
diff --git a/defs.h b/defs.h
index 199ea878088b52fb17da7e6f108c2750f54f7155..4e1e8a5355c051f2d62af9ab4a4d65a805b31def 100644 (file)
--- a/defs.h
+++ b/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);
+
diff --git a/main.c b/main.c
index 2f3b00e54523bbc82746d20726d1076962e4f2c5..07b3862bdbc8c56bfb58301a650b5cb6f054e35b 100644 (file)
--- a/main.c
+++ b/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
diff --git a/memlayout.h b/memlayout.h
new file mode 100644 (file)
index 0000000..a33f347
--- /dev/null
@@ -0,0 +1,3 @@
+#define EXTPHYSMEM 0x100000
+
+#define KADDR(a) ((void *) a)
diff --git a/mp.c b/mp.c
new file mode 100644 (file)
index 0000000..9d47e50
--- /dev/null
+++ b/mp.c
@@ -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);
+}
diff --git a/mp.h b/mp.h
new file mode 100644 (file)
index 0000000..df46574
--- /dev/null
+++ b/mp.h
@@ -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 */
+};
index f27b025fa8fb492605780becb659de9b639d7b1b..40019d557f2f77abf6afb0c2bcaea2248c41351c 100644 (file)
--- a/string.c
+++ b/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;
+}