xref: /xv6-public/mp.c (revision 4f14d8d1)
1a4b213cfSFrans Kaashoek // Multiprocessor support
2eb52c7deSrsc // Search memory for MP description structures.
399b11b6cSrsc // http://developer.intel.com/design/pentium/datashts/24201606.pdf
499b11b6cSrsc 
57baa34a4Skaashoek #include "types.h"
67baa34a4Skaashoek #include "defs.h"
721a88fd4Skaashoek #include "param.h"
89aa0337dSFrans Kaashoek #include "memlayout.h"
9558ab49fSrsc #include "mp.h"
1021a88fd4Skaashoek #include "x86.h"
1121a88fd4Skaashoek #include "mmu.h"
128b4e2a08Srtm #include "proc.h"
137baa34a4Skaashoek 
148b4e2a08Srtm struct cpu cpus[NCPU];
158b4e2a08Srtm int ncpu;
1621575761Srsc uchar ioapicid;
17c8b29f6dSkaashoek 
1899b11b6cSrsc static uchar
sum(uchar * addr,int len)1999b11b6cSrsc sum(uchar *addr, int len)
2099b11b6cSrsc {
2199b11b6cSrsc   int i, sum;
2299b11b6cSrsc 
2399b11b6cSrsc   sum = 0;
2499b11b6cSrsc   for(i=0; i<len; i++)
2599b11b6cSrsc     sum += addr[i];
2699b11b6cSrsc   return sum;
2799b11b6cSrsc }
2899b11b6cSrsc 
2999b11b6cSrsc // Look for an MP structure in the len bytes at addr.
3099b11b6cSrsc static struct mp*
mpsearch1(uint a,int len)313a038106SFrans Kaashoek mpsearch1(uint a, int len)
3299b11b6cSrsc {
333a038106SFrans Kaashoek   uchar *e, *p, *addr;
347baa34a4Skaashoek 
35a7c03bd9SRobert Morris   addr = P2V(a);
367baa34a4Skaashoek   e = addr+len;
3799b11b6cSrsc   for(p = addr; p < e; p += sizeof(struct mp))
3899b11b6cSrsc     if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
39b5f17007Srsc       return (struct mp*)p;
407baa34a4Skaashoek   return 0;
417baa34a4Skaashoek }
427baa34a4Skaashoek 
43f5527388Srsc // Search for the MP Floating Pointer Structure, which according to the
44f5527388Srsc // spec is in one of the following three locations:
45f5527388Srsc // 1) in the first KB of the EBDA;
46f5527388Srsc // 2) in the last KB of system base memory;
47f5527388Srsc // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
48b5f17007Srsc static struct mp*
mpsearch(void)4921575761Srsc mpsearch(void)
507baa34a4Skaashoek {
5129270816Srtm   uchar *bda;
5229270816Srtm   uint p;
53b5f17007Srsc   struct mp *mp;
547baa34a4Skaashoek 
553a038106SFrans Kaashoek   bda = (uchar *) P2V(0x400);
56a6c4711aSrsc   if((p = ((bda[0x0F]<<8)| bda[0x0E]) << 4)){
573a038106SFrans Kaashoek     if((mp = mpsearch1(p, 1024)))
587baa34a4Skaashoek       return mp;
59da942337Srsc   } else {
607baa34a4Skaashoek     p = ((bda[0x14]<<8)|bda[0x13])*1024;
613a038106SFrans Kaashoek     if((mp = mpsearch1(p-1024, 1024)))
627baa34a4Skaashoek       return mp;
637baa34a4Skaashoek   }
643a038106SFrans Kaashoek   return mpsearch1(0xF0000, 0x10000);
657baa34a4Skaashoek }
667baa34a4Skaashoek 
67f5527388Srsc // Search for an MP configuration table.  For now,
68f5527388Srsc // don't accept the default configurations (physaddr == 0).
69f5527388Srsc // Check for correct signature, calculate the checksum and,
70f5527388Srsc // if correct, check the version.
71f5527388Srsc // To do: check extended table checksum.
7299b11b6cSrsc static struct mpconf*
mpconfig(struct mp ** pmp)7321575761Srsc mpconfig(struct mp **pmp)
747baa34a4Skaashoek {
7599b11b6cSrsc   struct mpconf *conf;
7699b11b6cSrsc   struct mp *mp;
777baa34a4Skaashoek 
7821575761Srsc   if((mp = mpsearch()) == 0 || mp->physaddr == 0)
797baa34a4Skaashoek     return 0;
80a7c03bd9SRobert Morris   conf = (struct mpconf*) P2V((uint) mp->physaddr);
8199b11b6cSrsc   if(memcmp(conf, "PCMP", 4) != 0)
8299b11b6cSrsc     return 0;
8399b11b6cSrsc   if(conf->version != 1 && conf->version != 4)
8499b11b6cSrsc     return 0;
8599b11b6cSrsc   if(sum((uchar*)conf, conf->length) != 0)
8699b11b6cSrsc     return 0;
8799b11b6cSrsc   *pmp = mp;
8899b11b6cSrsc   return conf;
897baa34a4Skaashoek }
907baa34a4Skaashoek 
917baa34a4Skaashoek void
mpinit(void)9221575761Srsc mpinit(void)
937baa34a4Skaashoek {
9429270816Srtm   uchar *p, *e;
95*4f14d8d1SFrans Kaashoek   int ismp;
9699b11b6cSrsc   struct mp *mp;
9799b11b6cSrsc   struct mpconf *conf;
9899b11b6cSrsc   struct mpproc *proc;
99c8b29f6dSkaashoek   struct mpioapic *ioapic;
1007baa34a4Skaashoek 
10121575761Srsc   if((conf = mpconfig(&mp)) == 0)
102*4f14d8d1SFrans Kaashoek     panic("Expect to run on an SMP");
103f7017212Skaashoek   ismp = 1;
10499b11b6cSrsc   lapic = (uint*)conf->lapicaddr;
10599b11b6cSrsc   for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
1067baa34a4Skaashoek     switch(*p){
10799b11b6cSrsc     case MPPROC:
10899b11b6cSrsc       proc = (struct mpproc*)p;
109ae15515dSFrans Kaashoek       if(ncpu < NCPU) {
110ae15515dSFrans Kaashoek         cpus[ncpu].apicid = proc->apicid;  // apicid may differ from ncpu
1117baa34a4Skaashoek         ncpu++;
112ae15515dSFrans Kaashoek       }
11399b11b6cSrsc       p += sizeof(struct mpproc);
1147baa34a4Skaashoek       continue;
11521a88fd4Skaashoek     case MPIOAPIC:
116c8b29f6dSkaashoek       ioapic = (struct mpioapic*)p;
11721575761Srsc       ioapicid = ioapic->apicno;
118b5f17007Srsc       p += sizeof(struct mpioapic);
1197baa34a4Skaashoek       continue;
12099b11b6cSrsc     case MPBUS:
12121a88fd4Skaashoek     case MPIOINTR:
12299b11b6cSrsc     case MPLINTR:
12399b11b6cSrsc       p += 8;
1247baa34a4Skaashoek       continue;
1257baa34a4Skaashoek     default:
126af6a6a47SRuss Cox       ismp = 0;
127ae15515dSFrans Kaashoek       break;
1287baa34a4Skaashoek     }
1297baa34a4Skaashoek   }
130*4f14d8d1SFrans Kaashoek   if(!ismp)
131*4f14d8d1SFrans Kaashoek     panic("Didn't find a suitable machine");
132af6a6a47SRuss Cox 
1330cfc7290Srsc   if(mp->imcrp){
134da942337Srsc     // Bochs doesn't support IMCR, so this doesn't run on Bochs.
135da942337Srsc     // But it would on real hardware.
1360cfc7290Srsc     outb(0x22, 0x70);   // Select IMCR
137da942337Srsc     outb(0x23, inb(0x23) | 1);  // Mask external interrupts.
138c8b29f6dSkaashoek   }
1398148b6eeSrtm }
140