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