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