xv6

port of xv6 to x86-64
git clone http://frotz.net/git/xv6.git
Log | Files | Refs | README | LICENSE

mp.c (3427B)


      1 // Multiprocessor support
      2 // Search memory for MP description structures.
      3 // http://developer.intel.com/design/pentium/datashts/24201606.pdf
      4 
      5 #include "types.h"
      6 #include "defs.h"
      7 #include "param.h"
      8 #include "memlayout.h"
      9 #include "mp.h"
     10 #include "x86.h"
     11 #include "mmu.h"
     12 #include "proc.h"
     13 
     14 struct cpu cpus[NCPU];
     15 static struct cpu *bcpu;
     16 int ismp;
     17 int ncpu;
     18 uchar ioapicid;
     19 
     20 int
     21 mpbcpu(void)
     22 {
     23   return bcpu-cpus;
     24 }
     25 
     26 static uchar
     27 sum(uchar *addr, int len)
     28 {
     29   int i, sum;
     30   
     31   sum = 0;
     32   for(i=0; i<len; i++)
     33     sum += addr[i];
     34   return sum;
     35 }
     36 
     37 // Look for an MP structure in the len bytes at addr.
     38 static struct mp*
     39 mpsearch1(uint a, int len)
     40 {
     41   uchar *e, *p, *addr;
     42 
     43   addr = p2v(a);
     44   e = addr+len;
     45   for(p = addr; p < e; p += sizeof(struct mp))
     46     if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
     47       return (struct mp*)p;
     48   return 0;
     49 }
     50 
     51 // Search for the MP Floating Pointer Structure, which according to the
     52 // spec is in one of the following three locations:
     53 // 1) in the first KB of the EBDA;
     54 // 2) in the last KB of system base memory;
     55 // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
     56 static struct mp*
     57 mpsearch(void)
     58 {
     59   uchar *bda;
     60   uint p;
     61   struct mp *mp;
     62 
     63   bda = (uchar *) P2V(0x400);
     64   if((p = ((bda[0x0F]<<8)| bda[0x0E]) << 4)){
     65     if((mp = mpsearch1(p, 1024)))
     66       return mp;
     67   } else {
     68     p = ((bda[0x14]<<8)|bda[0x13])*1024;
     69     if((mp = mpsearch1(p-1024, 1024)))
     70       return mp;
     71   }
     72   return mpsearch1(0xF0000, 0x10000);
     73 }
     74 
     75 // Search for an MP configuration table.  For now,
     76 // don't accept the default configurations (physaddr == 0).
     77 // Check for correct signature, calculate the checksum and,
     78 // if correct, check the version.
     79 // To do: check extended table checksum.
     80 static struct mpconf*
     81 mpconfig(struct mp **pmp)
     82 {
     83   struct mpconf *conf;
     84   struct mp *mp;
     85 
     86   if((mp = mpsearch()) == 0 || mp->physaddr == 0)
     87     return 0;
     88   conf = (struct mpconf*) p2v((uintp) mp->physaddr);
     89   if(memcmp(conf, "PCMP", 4) != 0)
     90     return 0;
     91   if(conf->version != 1 && conf->version != 4)
     92     return 0;
     93   if(sum((uchar*)conf, conf->length) != 0)
     94     return 0;
     95   *pmp = mp;
     96   return conf;
     97 }
     98 
     99 void
    100 mpinit(void)
    101 {
    102   uchar *p, *e;
    103   struct mp *mp;
    104   struct mpconf *conf;
    105   struct mpproc *proc;
    106   struct mpioapic *ioapic;
    107 
    108   bcpu = &cpus[0];
    109   if((conf = mpconfig(&mp)) == 0)
    110     return;
    111   ismp = 1;
    112   lapic = IO2V((uintp)conf->lapicaddr);
    113   for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
    114     switch(*p){
    115     case MPPROC:
    116       proc = (struct mpproc*)p;
    117       cprintf("mpinit ncpu=%d apicid=%d\n", ncpu, proc->apicid);
    118       if(proc->flags & MPBOOT)
    119         bcpu = &cpus[ncpu];
    120       cpus[ncpu].id = ncpu;
    121       cpus[ncpu].apicid = proc->apicid;
    122       ncpu++;
    123       p += sizeof(struct mpproc);
    124       continue;
    125     case MPIOAPIC:
    126       ioapic = (struct mpioapic*)p;
    127       ioapicid = ioapic->apicno;
    128       p += sizeof(struct mpioapic);
    129       continue;
    130     case MPBUS:
    131     case MPIOINTR:
    132     case MPLINTR:
    133       p += 8;
    134       continue;
    135     default:
    136       cprintf("mpinit: unknown config type %x\n", *p);
    137       ismp = 0;
    138     }
    139   }
    140   if(!ismp){
    141     // Didn't like what we found; fall back to no MP.
    142     ncpu = 1;
    143     lapic = 0;
    144     ioapicid = 0;
    145     return;
    146   }
    147 
    148   if(mp->imcrp){
    149     // Bochs doesn't support IMCR, so this doesn't run on Bochs.
    150     // But it would on real hardware.
    151     outb(0x22, 0x70);   // Select IMCR
    152     outb(0x23, inb(0x23) | 1);  // Mask external interrupts.
    153   }
    154 }