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