1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 #include "io.h"
8 #include "apic.h"
9 #include "mp.h"
10
11 /*
12 * MultiProcessor Specification Version 1.[14].
13 */
14 typedef struct { /* MP Floating Pointer */
15 u8int signature[4]; /* "_MP_" */
16 u8int addr[4]; /* PCMP */
17 u8int length; /* 1 */
18 u8int revision; /* [14] */
19 u8int checksum;
20 u8int feature[5];
21 } _MP_;
22
23 typedef struct { /* MP Configuration Table */
24 u8int signature[4]; /* "PCMP" */
25 u8int length[2];
26 u8int revision; /* [14] */
27 u8int checksum;
28 u8int string[20]; /* OEM + Product ID */
29 u8int oaddr[4]; /* OEM table pointer */
30 u8int olength[2]; /* OEM table length */
31 u8int entry[2]; /* entry count */
32 u8int apicpa[4]; /* local APIC address */
33 u8int xlength[2]; /* extended table length */
34 u8int xchecksum; /* extended table checksum */
35 u8int reserved;
36
37 u8int entries[];
38 } PCMP;
39
40 typedef struct {
41 char type[6];
42 int polarity; /* default for this bus */
43 int trigger; /* default for this bus */
44 } Mpbus;
45
46 static Mpbus mpbusdef[] = {
47 { "PCI ", IPlow, TMlevel, },
48 { "ISA ", IPhigh, TMedge, },
49 };
50 static Mpbus* mpbus[Nbus];
51 int mpisabusno = -1;
52
53 static void
mpintrprint(char * s,u8int * p)54 mpintrprint(char* s, u8int* p)
55 {
56 char buf[128], *b, *e;
57 char format[] = " type %d flags %#ux bus %d IRQ %d APIC %d INTIN %d\n";
58
59 b = buf;
60 e = b + sizeof(buf);
61 b = seprint(b, e, "mpparse: intr:");
62 if(s != nil)
63 b = seprint(b, e, " %s:", s);
64 seprint(b, e, format, p[1], l16get(p+2), p[4], p[5], p[6], p[7]);
65 print(buf);
66 }
67
68 static u32int
mpmkintr(u8int * p)69 mpmkintr(u8int* p)
70 {
71 u32int v;
72 Apic *apic;
73 int n, polarity, trigger;
74
75 /*
76 * Check valid bus, interrupt input pin polarity
77 * and trigger mode. If the APIC ID is 0xff it means
78 * all APICs of this type so those checks for useable
79 * APIC and valid INTIN must also be done later in
80 * the appropriate init routine in that case. It's hard
81 * to imagine routing a signal to all IOAPICs, the
82 * usual case is routing NMI and ExtINT to all LAPICs.
83 */
84 if(mpbus[p[4]] == nil){
85 mpintrprint("no source bus", p);
86 return 0;
87 }
88 if(p[6] != 0xff){
89 if(Napic < 256 && p[6] >= Napic){
90 mpintrprint("APIC ID out of range", p);
91 return 0;
92 }
93 switch(p[0]){
94 default:
95 mpintrprint("INTIN botch", p);
96 return 0;
97 case PcmpIOINTR:
98 apic = &ioapic[p[6]];
99 if(!apic->useable){
100 mpintrprint("unuseable APIC", p);
101 return 0;
102 }
103 if(p[7] >= apic->nrdt){
104 mpintrprint("IO INTIN out of range", p);
105 return 0;
106 }
107 break;
108 case PcmpLINTR:
109 apic = &xapic[p[6]];
110 if(!apic->useable){
111 mpintrprint("unuseable APIC", p);
112 return 0;
113 }
114 if(p[7] >= nelem(apic->lvt)){
115 mpintrprint("LOCAL INTIN out of range", p);
116 return 0;
117 }
118 break;
119 }
120 }
121 n = l16get(p+2);
122 if((polarity = (n & PcmpPOMASK)) == 2 || (trigger = ((n>>2) & PcmpPOMASK)) == 2){
123 mpintrprint("invalid polarity/trigger", p);
124 return 0;
125 }
126
127 /*
128 * Create the low half of the vector table entry (LVT or RDT).
129 * For the NMI, SMI and ExtINT cases, the polarity and trigger
130 * are fixed (but are not always consistent over IA-32 generations).
131 * For the INT case, either the polarity/trigger are given or
132 * it defaults to that of the source bus;
133 * whether INT is Fixed or Lowest Priority is left until later.
134 */
135 v = Im;
136 switch(p[1]){
137 default:
138 mpintrprint("invalid type", p);
139 return 0;
140 case PcmpINT:
141 switch(polarity){
142 case 0:
143 v |= mpbus[p[4]]->polarity;
144 break;
145 case PcmpHIGH:
146 v |= IPhigh;
147 break;
148 case PcmpLOW:
149 v |= IPlow;
150 break;
151 }
152 switch(trigger){
153 case 0:
154 v |= mpbus[p[4]]->trigger;
155 break;
156 case PcmpHIGH:
157 v |= TMedge;
158 break;
159 case PcmpLOW:
160 v |= TMlevel;
161 break;
162 }
163 break;
164 case PcmpNMI:
165 v |= TMedge|IPhigh|MTnmi;
166 break;
167 case PcmpSMI:
168 v |= TMedge|IPhigh|MTsmi;
169 break;
170 case PcmpExtINT:
171 v |= TMedge|IPhigh|MTei;
172 break;
173 }
174
175 return v;
176 }
177
178 static void
mpparse(PCMP * pcmp)179 mpparse(PCMP* pcmp)
180 {
181 u32int lo;
182 u8int *e, *p;
183 int i, n, bustype;
184
185 p = pcmp->entries;
186 e = ((uchar*)pcmp)+l16get(pcmp->length);
187 while(p < e) switch(*p){
188 default:
189 print("mpparse: unknown PCMP type %d (e-p %#ld)\n", *p, e-p);
190 for(i = 0; p < e; i++){
191 if(i && ((i & 0x0f) == 0))
192 print("\n");
193 print(" %#2.2ux", *p);
194 p++;
195 }
196 print("\n");
197 break;
198 case PcmpPROCESSOR:
199 /*
200 * Initialise the APIC if it is enabled (p[3] & 0x01).
201 * p[1] is the APIC ID, the memory mapped address comes
202 * from the PCMP structure as the addess is local to the
203 * CPU and identical for all. Indicate whether this is
204 * the bootstrap processor (p[3] & 0x02).
205 */
206 DBG("mpparse: APIC %d pa %#ux useable %d\n",
207 p[1], l32get(pcmp->apicpa), p[3] & 0x01);
208 if(p[3] & 0x01)
209 apicinit(p[1], l32get(pcmp->apicpa), p[3] & 0x02);
210 p += 20;
211 break;
212 case PcmpBUS:
213 DBG("mpparse: bus: %d type %6.6s\n", p[1], (char*)p+2);
214 if(mpbus[p[1]] != nil){
215 print("mpparse: bus %d already allocated\n", p[1]);
216 p += 8;
217 break;
218 }
219 for(i = 0; i < nelem(mpbusdef); i++){
220 if(memcmp(p+2, mpbusdef[i].type, 6) != 0)
221 continue;
222 if(memcmp(p+2, "ISA ", 6) == 0){
223 if(mpisabusno != -1){
224 print("mpparse: bus %d already have ISA bus %d\n",
225 p[1], mpisabusno);
226 continue;
227 }
228 mpisabusno = p[1];
229 }
230 mpbus[p[1]] = &mpbusdef[i];
231 break;
232 }
233 if(mpbus[p[1]] == nil)
234 print("mpparse: bus %d type %6.6s unknown\n",
235 p[1], (char*)p+2);
236
237 p += 8;
238 break;
239 case PcmpIOAPIC:
240 /*
241 * Initialise the IOAPIC if it is enabled (p[3] & 0x01).
242 * p[1] is the APIC ID, p[4-7] is the memory mapped address.
243 */
244 DBG("mpparse: IOAPIC %d pa %#ux useable %d\n",
245 p[1], l32get(p+4), p[3] & 0x01);
246 if(p[3] & 0x01)
247 ioapicinit(p[1], l32get(p+4));
248
249 p += 8;
250 break;
251 case PcmpIOINTR:
252 /*
253 * p[1] is the interrupt type;
254 * p[2-3] contains the polarity and trigger mode;
255 * p[4] is the source bus;
256 * p[5] is the IRQ on the source bus;
257 * p[6] is the destination APIC;
258 * p[7] is the INITIN pin on the destination APIC.
259 */
260 if(p[6] == 0xff){
261 mpintrprint("routed to all IOAPICs", p);
262 p += 8;
263 break;
264 }
265 if((lo = mpmkintr(p)) == 0){
266 p += 8;
267 break;
268 }
269 if(DBGFLG)
270 mpintrprint(nil, p);
271
272 /*
273 * Always present the device number in the style
274 * of a PCI Interrupt Assignment Entry. For the ISA
275 * bus the IRQ is the device number but unencoded.
276 * May need to handle other buses here in the future
277 * (but unlikely).
278 */
279 bustype = -1;
280 if(memcmp(mpbus[p[4]]->type, "PCI ", 6) == 0)
281 bustype = BusPCI;
282 else if(memcmp(mpbus[p[4]]->type, "ISA ", 6) == 0)
283 bustype = BusISA;
284 if(bustype != -1)
285 ioapicintrinit(bustype, p[4], p[6], p[7], p[5], lo);
286
287 p += 8;
288 break;
289 case PcmpLINTR:
290 /*
291 * Format is the same as IOINTR above.
292 */
293 if((lo = mpmkintr(p)) == 0){
294 p += 8;
295 break;
296 }
297 if(DBGFLG)
298 mpintrprint(nil, p);
299
300 /*
301 * Everything was checked in mpmkintr above.
302 */
303 if(p[6] == 0xff){
304 for(i = 0; i < Napic; i++){
305 if(!ioapic[i].useable || ioapic[i].addr != nil)
306 continue;
307 ioapic[i].lvt[p[7]] = lo;
308 }
309 }
310 else
311 ioapic[p[6]].lvt[p[7]] = lo;
312 p += 8;
313 break;
314 }
315
316 /*
317 * There's nothing of real interest in the extended table,
318 * should just move along, but check it for consistency.
319 */
320 p = e;
321 e = p + l16get(pcmp->xlength);
322 while(p < e) switch(*p){
323 default:
324 n = p[1];
325 print("mpparse: unknown extended entry %d length %d\n", *p, n);
326 for(i = 0; i < n; i++){
327 if(i && ((i & 0x0f) == 0))
328 print("\n");
329 print(" %#2.2ux", *p);
330 p++;
331 }
332 print("\n");
333 break;
334 case PcmpSASM:
335 DBG("address space mapping\n");
336 DBG(" bus %d type %d base %#llux length %#llux\n",
337 p[2], p[3], l64get(p+4), l64get(p+12));
338 p += p[1];
339 break;
340 case PcmpHIERARCHY:
341 DBG("bus hierarchy descriptor\n");
342 DBG(" bus %d sd %d parent bus %d\n",
343 p[2], p[3], p[4]);
344 p += p[1];
345 break;
346 case PcmpCBASM:
347 DBG("compatibility bus address space modifier\n");
348 DBG(" bus %d pr %d range list %d\n",
349 p[2], p[3], l32get(p+4));
350 p += p[1];
351 break;
352 }
353 }
354
355 static int
sigchecksum(void * address,int length)356 sigchecksum(void* address, int length)
357 {
358 u8int *p, sum;
359
360 sum = 0;
361 for(p = address; length-- > 0; p++)
362 sum += *p;
363
364 return sum;
365 }
366
367 static void*
sigscan(u8int * address,int length,char * signature)368 sigscan(u8int* address, int length, char* signature)
369 {
370 u8int *e, *p;
371 int siglength;
372
373 DBG("check for %s in system base memory @ %#p\n", signature, address);
374
375 e = address+length;
376 siglength = strlen(signature);
377 for(p = address; p+siglength < e; p += 16){
378 if(memcmp(p, signature, siglength))
379 continue;
380 return p;
381 }
382
383 return nil;
384 }
385
386 static void*
sigsearch(char * signature)387 sigsearch(char* signature)
388 {
389 uintptr p;
390 u8int *bda;
391 void *r;
392
393 /*
394 * Search for the data structure:
395 * 1) within the first KiB of the Extended BIOS Data Area (EBDA), or
396 * 2) within the last KiB of system base memory if the EBDA segment
397 * is undefined, or
398 * 3) within the BIOS ROM address space between 0xf0000 and 0xfffff
399 * (but will actually check 0xe0000 to 0xfffff).
400 */
401 bda = BIOSSEG(0x40);
402 if(memcmp(KADDR(0xfffd9), "EISA", 4) == 0){
403 if((p = (bda[0x0f]<<8)|bda[0x0e]) != 0){
404 if((r = sigscan(BIOSSEG(p), 1024, signature)) != nil)
405 return r;
406 }
407 }
408
409 if((p = ((bda[0x14]<<8)|bda[0x13])*1024) != 0){
410 if((r = sigscan(KADDR(p-1024), 1024, signature)) != nil)
411 return r;
412 }
413 if((r = sigscan(KADDR(0xa0000-1024), 1024, signature)) != nil)
414 return r;
415
416 return sigscan(BIOSSEG(0xe000), 0x20000, signature);
417 }
418
419 void
mpsinit(void)420 mpsinit(void)
421 {
422 u8int *p;
423 int i, n;
424 _MP_ *mp;
425 PCMP *pcmp;
426
427 if((mp = sigsearch("_MP_")) == nil)
428 return;
429 if(DBGFLG){
430 DBG("_MP_ @ %#p, addr %#ux length %ud rev %d",
431 mp, l32get(mp->addr), mp->length, mp->revision);
432 for(i = 0; i < sizeof(mp->feature); i++)
433 DBG(" %2.2#ux", mp->feature[i]);
434 DBG("\n");
435 }
436 if(mp->revision != 1 && mp->revision != 4)
437 return;
438 if(sigchecksum(mp, mp->length*16) != 0)
439 return;
440
441 if((pcmp = vmap(l32get(mp->addr), sizeof(PCMP))) == nil)
442 return;
443 if(pcmp->revision != 1 && pcmp->revision != 4){
444 vunmap(pcmp, sizeof(PCMP));
445 return;
446 }
447 n = l16get(pcmp->length) + l16get(pcmp->xlength);
448 vunmap(pcmp, sizeof(PCMP));
449 if((pcmp = vmap(l32get(mp->addr), n)) == nil)
450 return;
451 if(sigchecksum(pcmp, l16get(pcmp->length)) != 0){
452 vunmap(pcmp, n);
453 return;
454 }
455 if(DBGFLG){
456 DBG("PCMP @ %#p length %#ux revision %d\n",
457 pcmp, l16get(pcmp->length), pcmp->revision);
458 DBG(" %20.20s oaddr %#ux olength %#ux\n",
459 (char*)pcmp->string, l32get(pcmp->oaddr),
460 l16get(pcmp->olength));
461 DBG(" entry %d apicpa %#ux\n",
462 l16get(pcmp->entry), l32get(pcmp->apicpa));
463
464 DBG(" xlength %#ux xchecksum %#ux\n",
465 l16get(pcmp->xlength), pcmp->xchecksum);
466 }
467 if(pcmp->xchecksum != 0){
468 p = ((u8int*)pcmp) + l16get(pcmp->length);
469 i = sigchecksum(p, l16get(pcmp->xlength));
470 if(((i+pcmp->xchecksum) & 0xff) != 0){
471 print("extended table checksums to %#ux\n", i);
472 vunmap(pcmp, n);
473 return;
474 }
475 }
476
477 /*
478 * Parse the PCMP table and set up the datastructures
479 * for later interrupt enabling and application processor
480 * startup.
481 */
482 mpparse(pcmp);
483 mpacpi();
484
485 apicdump();
486 ioapicdump();
487 }
488