xref: /reactos/hal/halx86/mp/mpconfig.c (revision 1734f297)
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
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
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
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
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
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
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
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
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 adresses\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
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
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
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
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
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