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