1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: hal/halx86/mp/mpconfig.c
5 * PURPOSE:
6 * PROGRAMMER:
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ******************************************************************/
16
17 MP_FLOATING_POINTER* Mpf = NULL;
18
19 /* FUNCTIONS ****************************************************************/
20
21 static UCHAR
MPChecksum(PUCHAR Base,ULONG Size)22 MPChecksum(PUCHAR Base,
23 ULONG Size)
24 /*
25 * Checksum an MP configuration block
26 */
27 {
28 UCHAR Sum = 0;
29
30 while (Size--)
31 Sum += *Base++;
32
33 return Sum;
34 }
35
36 static VOID
HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m)37 HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m)
38 {
39 DPRINT("Int: type %d, pol %d, trig %d, bus %d,"
40 " IRQ %02x, APIC ID %x, APIC INT %02x\n",
41 m->IrqType, m->IrqFlag & 3,
42 (m->IrqFlag >> 2) & 3, m->SrcBusId,
43 m->SrcBusIrq, m->DstApicId, m->DstApicInt);
44 if (IRQCount > MAX_IRQ_SOURCE)
45 {
46 DPRINT1("Max # of irq sources exceeded!!\n");
47 ASSERT(FALSE);
48 }
49
50 IRQMap[IRQCount] = *m;
51 IRQCount++;
52 }
53
54 PCHAR
HaliMPFamily(ULONG Family,ULONG Model)55 HaliMPFamily(ULONG Family,
56 ULONG Model)
57 {
58 static CHAR str[64];
59 static PCHAR CPUs[] =
60 {
61 "80486DX", "80486DX",
62 "80486SX", "80486DX/2 or 80487",
63 "80486SL", "Intel5X2(tm)",
64 "Unknown", "Unknown",
65 "80486DX/4"
66 };
67 if (Family == 0x6)
68 return ("Pentium(tm) Pro");
69 if (Family == 0x5)
70 return ("Pentium(tm)");
71 if (Family == 0x0F && Model == 0x0F)
72 return("Special controller");
73 if (Family == 0x0F && Model == 0x00)
74 return("Pentium 4(tm)");
75 if (Family == 0x04 && Model < 9)
76 return CPUs[Model];
77 sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model);
78 return str;
79 }
80
81
82 static VOID
HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m)83 HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m)
84 {
85 UCHAR ver;
86
87 if (!(m->CpuFlags & CPU_FLAG_ENABLED))
88 return;
89
90 DPRINT("Processor #%d %s APIC version %d\n",
91 m->ApicId,
92 HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8,
93 (m->FeatureFlags & CPU_MODEL_MASK) >> 4),
94 m->ApicVersion);
95
96 if (m->FeatureFlags & (1 << 0))
97 DPRINT(" Floating point unit present.\n");
98 if (m->FeatureFlags & (1 << 7))
99 DPRINT(" Machine Exception supported.\n");
100 if (m->FeatureFlags & (1 << 8))
101 DPRINT(" 64 bit compare & exchange supported.\n");
102 if (m->FeatureFlags & (1 << 9))
103 DPRINT(" Internal APIC present.\n");
104 if (m->FeatureFlags & (1 << 11))
105 DPRINT(" SEP present.\n");
106 if (m->FeatureFlags & (1 << 12))
107 DPRINT(" MTRR present.\n");
108 if (m->FeatureFlags & (1 << 13))
109 DPRINT(" PGE present.\n");
110 if (m->FeatureFlags & (1 << 14))
111 DPRINT(" MCA present.\n");
112 if (m->FeatureFlags & (1 << 15))
113 DPRINT(" CMOV present.\n");
114 if (m->FeatureFlags & (1 << 16))
115 DPRINT(" PAT present.\n");
116 if (m->FeatureFlags & (1 << 17))
117 DPRINT(" PSE present.\n");
118 if (m->FeatureFlags & (1 << 18))
119 DPRINT(" PSN present.\n");
120 if (m->FeatureFlags & (1 << 19))
121 DPRINT(" Cache Line Flush Instruction present.\n");
122 /* 20 Reserved */
123 if (m->FeatureFlags & (1 << 21))
124 DPRINT(" Debug Trace and EMON Store present.\n");
125 if (m->FeatureFlags & (1 << 22))
126 DPRINT(" ACPI Thermal Throttle Registers present.\n");
127 if (m->FeatureFlags & (1 << 23))
128 DPRINT(" MMX present.\n");
129 if (m->FeatureFlags & (1 << 24))
130 DPRINT(" FXSR present.\n");
131 if (m->FeatureFlags & (1 << 25))
132 DPRINT(" XMM present.\n");
133 if (m->FeatureFlags & (1 << 26))
134 DPRINT(" Willamette New Instructions present.\n");
135 if (m->FeatureFlags & (1 << 27))
136 DPRINT(" Self Snoop present.\n");
137 /* 28 Reserved */
138 if (m->FeatureFlags & (1 << 29))
139 DPRINT(" Thermal Monitor present.\n");
140 /* 30, 31 Reserved */
141
142 CPUMap[CPUCount].APICId = m->ApicId;
143
144 CPUMap[CPUCount].Flags = CPU_USABLE;
145
146 if (m->CpuFlags & CPU_FLAG_BSP)
147 {
148 DPRINT(" Bootup CPU\n");
149 CPUMap[CPUCount].Flags |= CPU_BSP;
150 BootCPU = m->ApicId;
151 }
152
153 if (m->ApicId > MAX_CPU)
154 {
155 DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU);
156 return;
157 }
158 ver = m->ApicVersion;
159
160 /*
161 * Validate version
162 */
163 if (ver == 0x0)
164 {
165 DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId);
166 ver = 0x10;
167 }
168 // ApicVersion[m->ApicId] = Ver;
169 // BiosCpuApicId[CPUCount] = m->ApicId;
170 CPUMap[CPUCount].APICVersion = ver;
171
172 CPUCount++;
173 }
174
175 static VOID
HaliMPBusInfo(PMP_CONFIGURATION_BUS m)176 HaliMPBusInfo(PMP_CONFIGURATION_BUS m)
177 {
178 static UCHAR CurrentPCIBusId = 0;
179
180 DPRINT("Bus #%d is %.*s\n", m->BusId, 6, m->BusType);
181
182 if (strncmp(m->BusType, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0)
183 {
184 BUSMap[m->BusId] = MP_BUS_ISA;
185 }
186 else if (strncmp(m->BusType, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0)
187 {
188 BUSMap[m->BusId] = MP_BUS_EISA;
189 }
190 else if (strncmp(m->BusType, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0)
191 {
192 BUSMap[m->BusId] = MP_BUS_PCI;
193 PCIBUSMap[m->BusId] = CurrentPCIBusId;
194 CurrentPCIBusId++;
195 }
196 else if (strncmp(m->BusType, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0)
197 {
198 BUSMap[m->BusId] = MP_BUS_MCA;
199 }
200 else
201 {
202 DPRINT("Unknown bustype %.*s - ignoring\n", 6, m->BusType);
203 }
204 }
205
206 static VOID
HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m)207 HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m)
208 {
209 if (!(m->ApicFlags & CPU_FLAG_ENABLED))
210 return;
211
212 DPRINT("I/O APIC #%d Version %d at 0x%lX.\n",
213 m->ApicId, m->ApicVersion, m->ApicAddress);
214 if (IOAPICCount > MAX_IOAPIC)
215 {
216 DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n",
217 MAX_IOAPIC, IOAPICCount);
218 DPRINT1("Recompile with bigger MAX_IOAPIC!.\n");
219 ASSERT(FALSE);
220 }
221
222 IOAPICMap[IOAPICCount].ApicId = m->ApicId;
223 IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion;
224 IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress;
225 IOAPICCount++;
226 }
227
228
229 static VOID
HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m)230 HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m)
231 {
232 DPRINT("Lint: type %d, pol %d, trig %d, bus %d,"
233 " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
234 m->IrqType, m->SrcBusIrq & 3,
235 (m->SrcBusIrq >> 2) & 3, m->SrcBusId,
236 m->SrcBusIrq, m->DstApicId, m->DstApicLInt);
237 /*
238 * Well it seems all SMP boards in existence
239 * use ExtINT/LVT1 == LINT0 and
240 * NMI/LVT2 == LINT1 - the following check
241 * will show us if this assumptions is false.
242 * Until then we do not have to add baggage.
243 */
244 if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0))
245 {
246 DPRINT1("Invalid MP table!\n");
247 ASSERT(FALSE);
248 }
249 if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1))
250 {
251 DPRINT1("Invalid MP table!\n");
252 ASSERT(FALSE);
253 }
254 }
255
256
257 static BOOLEAN
HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table)258 HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table)
259 /*
260 PARAMETERS:
261 Table = Pointer to MP configuration table
262 */
263 {
264 PUCHAR Entry;
265 ULONG Count;
266
267 if (Table->Signature != MPC_SIGNATURE)
268 {
269 PUCHAR pc = (PUCHAR)&Table->Signature;
270
271 DPRINT1("Bad MP configuration block signature: %c%c%c%c\n",
272 pc[0], pc[1], pc[2], pc[3]);
273 KeBugCheckEx(HAL_INITIALIZATION_FAILED, pc[0], pc[1], pc[2], pc[3]);
274 return FALSE;
275 }
276
277 if (MPChecksum((PUCHAR)Table, Table->Length))
278 {
279 DPRINT1("Bad MP configuration block checksum\n");
280 ASSERT(FALSE);
281 return FALSE;
282 }
283
284 if (Table->Specification != 0x01 && Table->Specification != 0x04)
285 {
286 DPRINT1("Bad MP configuration table version (%d)\n",
287 Table->Specification);
288 ASSERT(FALSE);
289 return FALSE;
290 }
291
292 if (Table->LocalAPICAddress != APIC_DEFAULT_BASE)
293 {
294 DPRINT1("APIC base address is at 0x%X. I cannot handle non-standard addresses\n",
295 Table->LocalAPICAddress);
296 ASSERT(FALSE);
297 return FALSE;
298 }
299
300 DPRINT("Oem: %.*s, ProductId: %.*s\n", 8, Table->Oem, 12, Table->ProductId);
301 DPRINT("APIC at: %08x\n", Table->LocalAPICAddress);
302
303
304 Entry = (PUCHAR)((ULONG_PTR)Table + sizeof(MP_CONFIGURATION_TABLE));
305 Count = 0;
306 while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE)))
307 {
308 /* Switch on type */
309 switch (*Entry)
310 {
311 case MPCTE_PROCESSOR:
312 {
313 HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry);
314 Entry += sizeof(MP_CONFIGURATION_PROCESSOR);
315 Count += sizeof(MP_CONFIGURATION_PROCESSOR);
316 break;
317 }
318 case MPCTE_BUS:
319 {
320 HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry);
321 Entry += sizeof(MP_CONFIGURATION_BUS);
322 Count += sizeof(MP_CONFIGURATION_BUS);
323 break;
324 }
325 case MPCTE_IOAPIC:
326 {
327 HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry);
328 Entry += sizeof(MP_CONFIGURATION_IOAPIC);
329 Count += sizeof(MP_CONFIGURATION_IOAPIC);
330 break;
331 }
332 case MPCTE_INTSRC:
333 {
334 HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry);
335 Entry += sizeof(MP_CONFIGURATION_INTSRC);
336 Count += sizeof(MP_CONFIGURATION_INTSRC);
337 break;
338 }
339 case MPCTE_LINTSRC:
340 {
341 HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry);
342 Entry += sizeof(MP_CONFIGURATION_INTLOCAL);
343 Count += sizeof(MP_CONFIGURATION_INTLOCAL);
344 break;
345 }
346 default:
347 DPRINT1("Unknown entry in MPC table\n");
348 ASSERT(FALSE);
349 return FALSE;
350 }
351 }
352 return TRUE;
353 }
354
355 static VOID
HaliConstructDefaultIOIrqMPTable(ULONG Type)356 HaliConstructDefaultIOIrqMPTable(ULONG Type)
357 {
358 MP_CONFIGURATION_INTSRC intsrc;
359 UCHAR i;
360
361 intsrc.Type = MPCTE_INTSRC;
362 intsrc.IrqFlag = 0; /* conforming */
363 intsrc.SrcBusId = 0;
364 intsrc.DstApicId = IOAPICMap[0].ApicId;
365
366 intsrc.IrqType = INT_VECTORED;
367 for (i = 0; i < 16; i++) {
368 switch (Type) {
369 case 2:
370 if (i == 0 || i == 13)
371 continue; /* IRQ0 & IRQ13 not connected */
372 /* Fall through */
373 default:
374 if (i == 2)
375 continue; /* IRQ2 is never connected */
376 }
377
378 intsrc.SrcBusIrq = i;
379 intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */
380 HaliMPIntSrcInfo(&intsrc);
381 }
382
383 intsrc.IrqType = INT_EXTINT;
384 intsrc.SrcBusIrq = 0;
385 intsrc.DstApicInt = 0; /* 8259A to INTIN0 */
386 HaliMPIntSrcInfo(&intsrc);
387 }
388
389 static VOID
HaliConstructDefaultISAMPTable(ULONG Type)390 HaliConstructDefaultISAMPTable(ULONG Type)
391 {
392 MP_CONFIGURATION_PROCESSOR processor;
393 MP_CONFIGURATION_BUS bus;
394 MP_CONFIGURATION_IOAPIC ioapic;
395 MP_CONFIGURATION_INTLOCAL lintsrc;
396 UCHAR linttypes[2] = { INT_EXTINT, INT_NMI };
397 UCHAR i;
398
399 /*
400 * 2 CPUs, numbered 0 & 1.
401 */
402 processor.Type = MPCTE_PROCESSOR;
403 /* Either an integrated APIC or a discrete 82489DX. */
404 processor.ApicVersion = Type > 4 ? 0x10 : 0x01;
405 processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP;
406 /* FIXME: Get this from the bootstrap processor */
407 processor.CpuSignature = 0;
408 processor.FeatureFlags = 0;
409 processor.Reserved[0] = 0;
410 processor.Reserved[1] = 0;
411 for (i = 0; i < 2; i++)
412 {
413 processor.ApicId = i;
414 HaliMPProcessorInfo(&processor);
415 processor.CpuFlags &= ~CPU_FLAG_BSP;
416 }
417
418 bus.Type = MPCTE_BUS;
419 bus.BusId = 0;
420 switch (Type)
421 {
422 default:
423 DPRINT("Unknown standard configuration %d\n", Type);
424 /* Fall through */
425 case 1:
426 case 5:
427 memcpy(bus.BusType, "ISA ", 6);
428 break;
429 case 2:
430 case 6:
431 case 3:
432 memcpy(bus.BusType, "EISA ", 6);
433 break;
434 case 4:
435 case 7:
436 memcpy(bus.BusType, "MCA ", 6);
437 }
438 HaliMPBusInfo(&bus);
439 if (Type > 4)
440 {
441 bus.Type = MPCTE_BUS;
442 bus.BusId = 1;
443 memcpy(bus.BusType, "PCI ", 6);
444 HaliMPBusInfo(&bus);
445 }
446
447 ioapic.Type = MPCTE_IOAPIC;
448 ioapic.ApicId = 2;
449 ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01;
450 ioapic.ApicFlags = MP_IOAPIC_USABLE;
451 ioapic.ApicAddress = IOAPIC_DEFAULT_BASE;
452 HaliMPIOApicInfo(&ioapic);
453
454 /*
455 * We set up most of the low 16 IO-APIC pins according to MPS rules.
456 */
457 HaliConstructDefaultIOIrqMPTable(Type);
458
459 lintsrc.Type = MPCTE_LINTSRC;
460 lintsrc.IrqType = 0;
461 lintsrc.IrqFlag = 0; /* conforming */
462 lintsrc.SrcBusId = 0;
463 lintsrc.SrcBusIrq = 0;
464 lintsrc.DstApicId = MP_APIC_ALL;
465 for (i = 0; i < 2; i++)
466 {
467 lintsrc.IrqType = linttypes[i];
468 lintsrc.DstApicLInt = i;
469 HaliMPIntLocalInfo(&lintsrc);
470 }
471 }
472
473
474 static BOOLEAN
HaliScanForMPConfigTable(ULONG Base,ULONG Size)475 HaliScanForMPConfigTable(ULONG Base,
476 ULONG Size)
477 {
478 /*
479 PARAMETERS:
480 Base = Base address of region
481 Size = Length of region to check
482 RETURNS:
483 TRUE if a valid MP configuration table was found
484 */
485
486 PULONG bp = (PULONG)Base;
487 MP_FLOATING_POINTER* mpf;
488 UCHAR Checksum;
489
490 while (Size > 0)
491 {
492 mpf = (MP_FLOATING_POINTER*)bp;
493 if (mpf->Signature == MPF_SIGNATURE)
494 {
495 Checksum = MPChecksum((PUCHAR)bp, 16);
496 DPRINT("Found MPF signature at %x, checksum %x\n", bp, Checksum);
497 if (Checksum == 0 &&
498 mpf->Length == 1)
499 {
500 DPRINT("Intel MultiProcessor Specification v1.%d compliant system.\n",
501 mpf->Specification);
502
503 if (mpf->Feature2 & FEATURE2_IMCRP)
504 {
505 DPRINT("Running in IMCR and PIC compatibility mode.\n");
506 }
507 else
508 {
509 DPRINT("Running in Virtual Wire compatibility mode.\n");
510 }
511
512
513 switch (mpf->Feature1)
514 {
515 case 0:
516 /* Non standard configuration */
517 break;
518 case 1:
519 DPRINT("ISA\n");
520 break;
521 case 2:
522 DPRINT("EISA with no IRQ8 chaining\n");
523 break;
524 case 3:
525 DPRINT("EISA\n");
526 break;
527 case 4:
528 DPRINT("MCA\n");
529 break;
530 case 5:
531 DPRINT("ISA and PCI\n");
532 break;
533 case 6:
534 DPRINT("EISA and PCI\n");
535 break;
536 case 7:
537 DPRINT("MCA and PCI\n");
538 break;
539 default:
540 DPRINT("Unknown standard configuration %d\n", mpf->Feature1);
541 return FALSE;
542 }
543 Mpf = mpf;
544 return TRUE;
545 }
546 }
547 bp += 4;
548 Size -= 16;
549 }
550 return FALSE;
551 }
552
553 static BOOLEAN
HaliGetSmpConfig(VOID)554 HaliGetSmpConfig(VOID)
555 {
556 if (Mpf == NULL)
557 {
558 return FALSE;
559 }
560
561 if (Mpf->Feature2 & FEATURE2_IMCRP)
562 {
563 DPRINT("Running in IMCR and PIC compatibility mode.\n");
564 APICMode = amPIC;
565 }
566 else
567 {
568 DPRINT("Running in Virtual Wire compatibility mode.\n");
569 APICMode = amVWIRE;
570 }
571
572 if (Mpf->Feature1 == 0 && Mpf->Address)
573 {
574 if(!HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)Mpf->Address))
575 {
576 DPRINT("BIOS bug, MP table errors detected!...\n");
577 DPRINT("... disabling SMP support. (tell your hw vendor)\n");
578 return FALSE;
579 }
580 if (IRQCount == 0)
581 {
582 MP_CONFIGURATION_BUS bus;
583
584 DPRINT("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n");
585
586 bus.BusId = 1;
587 memcpy(bus.BusType, "ISA ", 6);
588 HaliMPBusInfo(&bus);
589 HaliConstructDefaultIOIrqMPTable(bus.BusId);
590 }
591
592 }
593 else if(Mpf->Feature1 != 0)
594 {
595 HaliConstructDefaultISAMPTable(Mpf->Feature1);
596 }
597 else
598 {
599 ASSERT(FALSE);
600 }
601 return TRUE;
602 }
603
604 BOOLEAN
HaliFindSmpConfig(VOID)605 HaliFindSmpConfig(VOID)
606 {
607 /*
608 Scan the system memory for an MP configuration table
609 1) Scan the first KB of system base memory
610 2) Scan the last KB of system base memory
611 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh
612 4) Scan the first KB from the Extended BIOS Data Area
613 */
614
615 if (!HaliScanForMPConfigTable(0x0, 0x400))
616 {
617 if (!HaliScanForMPConfigTable(0x9FC00, 0x400))
618 {
619 if (!HaliScanForMPConfigTable(0xF0000, 0x10000))
620 {
621 if (!HaliScanForMPConfigTable(*((PUSHORT)0x040E) << 4, 0x400))
622 {
623 DPRINT("No multiprocessor compliant system found.\n");
624 return FALSE;
625 }
626 }
627 }
628 }
629
630 if (HaliGetSmpConfig())
631 {
632 return TRUE;
633 }
634 else
635 {
636 DPRINT("No MP config table found\n");
637 return FALSE;
638 }
639
640 }
641
642 /* EOF */
643