4 * Copyright (C) 2003 Eric Kohl
5 * Copyright (C) 2006 Colin Finck <mail@colinfinck.de>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #define MP_FP_SIGNATURE 0x5F504D5F /* "_MP_" */
28 #define MP_CT_SIGNATURE 0x504D4350 /* "PCMP" */
31 typedef struct _MP_FLOATING_POINT_TABLE
33 ULONG Signature
; /* "_MP_" */
34 ULONG PhysicalAddressPointer
;
39 } PACKED MP_FLOATING_POINT_TABLE
, *PMP_FLOATING_POINT_TABLE
;
42 typedef struct _MPS_CONFIG_TABLE_HEADER
44 ULONG Signature
; /* "PCMP" */
45 USHORT BaseTableLength
;
49 UCHAR ProductIdString
[12];
50 ULONG OemTablePointer
;
51 USHORT OemTableLength
;
53 ULONG AddressOfLocalAPIC
;
54 USHORT ExtendedTableLength
;
55 UCHAR ExtendedTableChecksum
;
57 } PACKED MP_CONFIGURATION_TABLE
, *PMP_CONFIGURATION_TABLE
;
60 typedef struct _MP_PROCESSOR_ENTRY
64 UCHAR LocalApicVersion
;
70 } PACKED MP_PROCESSOR_ENTRY
, *PMP_PROCESSOR_ENTRY
;
73 /* FUNCTIONS ****************************************************************/
82 /* Read TSC (Time Stamp Counter) */
85 /* Wait for 0.1 seconds (= 100 milliseconds = 100000 microseconds)*/
86 StallExecutionProcessor(100000);
88 /* Read TSC (Time Stamp Counter) again */
91 /* Calculate elapsed time (check for counter overrun) */
92 if (Timestamp2
> Timestamp1
)
94 Diff
= Timestamp2
- Timestamp1
;
98 Diff
= Timestamp2
+ (((ULONGLONG
)-1) - Timestamp1
);
101 return (ULONG
)(Diff
/ 100000);
106 DetectCPU(FRLDRHKEY CpuKey
,
109 WCHAR VendorIdentifier
[13];
110 WCHAR ProcessorNameString
[49];
111 CHAR tmpVendorIdentifier
[13];
112 CHAR tmpProcessorNameString
[49];
113 WCHAR Identifier
[64];
115 FRLDRHKEY CpuInstKey
;
116 FRLDRHKEY FpuInstKey
;
124 BOOLEAN SupportTSC
= FALSE
;
128 /* Create the CPU instance key */
129 Error
= RegCreateKey(CpuKey
,
132 if (Error
!= ERROR_SUCCESS
)
134 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
138 /* Create the FPU instance key */
139 Error
= RegCreateKey(FpuKey
,
142 if (Error
!= ERROR_SUCCESS
)
144 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
148 eax
= CpuidSupported();
151 DbgPrint((DPRINT_HWDETECT
, "CPUID supported\n"));
153 /* Get vendor identifier */
154 GetCpuid(0, &eax
, &ebx
, &ecx
, &edx
);
155 tmpVendorIdentifier
[12] = 0;
156 Ptr
= (ULONG
*)&tmpVendorIdentifier
[0];
162 swprintf(VendorIdentifier
, L
"%S", tmpVendorIdentifier
);
165 GetCpuid(1, &eax
, &ebx
, &ecx
, &edx
);
167 L
"x86 Family %u Model %u Stepping %u",
168 (unsigned int)((eax
>> 8) & 0x0F),
169 (unsigned int)((eax
>> 4) & 0x0F),
170 (unsigned int)(eax
& 0x0F));
172 if (((eax
>> 8) & 0x0F) >= 5)
175 /* Check if Extended CPUID information is supported */
176 GetCpuid(0x80000000, &eax
, &ebx
, &ecx
, &edx
);
178 if(eax
>= 0x80000004)
180 /* Get Processor Name String */
181 tmpProcessorNameString
[48] = 0;
182 Ptr
= (ULONG
*)&tmpProcessorNameString
[0];
184 for (i
= 0x80000002; i
<= 0x80000004; i
++)
186 GetCpuid(i
, &eax
, &ebx
, &ecx
, &edx
);
197 swprintf(ProcessorNameString
, L
"%S", tmpProcessorNameString
);
200 /* Set 'ProcessorNameString' value (CPU only) */
201 DbgPrint((DPRINT_HWDETECT
, "Processor Name String: %S\n", ProcessorNameString
));
203 Error
= RegSetValue(CpuInstKey
,
204 L
"ProcessorNameString",
206 (PCHAR
)ProcessorNameString
,
207 (wcslen(ProcessorNameString
) + 1) * sizeof(WCHAR
));
209 if (Error
!= ERROR_SUCCESS
)
210 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
215 DbgPrint((DPRINT_HWDETECT
, "CPUID not supported\n"));
217 wcscpy(VendorIdentifier
, L
"Unknown");
219 L
"x86 Family %u Model %u Stepping %u",
220 (unsigned int)((eax
>> 8) & 0x0F),
221 (unsigned int)((eax
>> 4) & 0x0F),
222 (unsigned int)(eax
& 0x0F));
226 /* Set 'Conmponent Information' value (CPU and FPU) */
227 SetComponentInformation(CpuInstKey
, 0, 0, 1);
228 SetComponentInformation(FpuInstKey
, 0, 0, 1);
230 /* Set 'FeatureSet' value (CPU only) */
231 DbgPrint((DPRINT_HWDETECT
, "FeatureSet: %x\n", FeatureSet
));
233 Error
= RegSetValue(CpuInstKey
,
238 if (Error
!= ERROR_SUCCESS
)
240 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
243 /* Set 'Identifier' value (CPU and FPU) */
244 DbgPrint((DPRINT_HWDETECT
, "Identifier: %S\n", Identifier
));
246 Error
= RegSetValue(CpuInstKey
,
250 (wcslen(Identifier
) + 1) * sizeof(WCHAR
));
251 if (Error
!= ERROR_SUCCESS
)
253 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
256 Error
= RegSetValue(FpuInstKey
,
260 (wcslen(Identifier
) + 1) * sizeof(WCHAR
));
261 if (Error
!= ERROR_SUCCESS
)
263 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
266 /* Set 'VendorIdentifier' value (CPU only) */
267 DbgPrint((DPRINT_HWDETECT
, "Vendor Identifier: %S\n", VendorIdentifier
));
269 Error
= RegSetValue(CpuInstKey
,
272 (PCHAR
)VendorIdentifier
,
273 (wcslen(VendorIdentifier
) + 1) * sizeof(WCHAR
));
274 if (Error
!= ERROR_SUCCESS
)
276 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
279 /* FIXME: Set 'Update Signature' value (CPU only) */
281 /* FIXME: Set 'Update Status' value (CPU only) */
283 /* Set '~MHz' value (CPU only) */
286 CpuSpeed
= GetCpuSpeed();
288 Error
= RegSetValue(CpuInstKey
,
293 if (Error
!= ERROR_SUCCESS
)
295 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
302 SetMpsProcessor(FRLDRHKEY CpuKey
,
304 PMP_PROCESSOR_ENTRY CpuEntry
)
306 WCHAR ProcessorNameString
[49];
307 WCHAR VendorIdentifier
[13];
308 CHAR tmpProcessorNameString
[49];
309 CHAR tmpVendorIdentifier
[13];
310 WCHAR Identifier
[64];
313 FRLDRHKEY CpuInstKey
;
314 FRLDRHKEY FpuInstKey
;
324 /* Get processor instance number */
325 swprintf(Buffer
, L
"%u", CpuEntry
->LocalApicId
);
327 /* Create the CPU instance key */
328 Error
= RegCreateKey(CpuKey
,
331 if (Error
!= ERROR_SUCCESS
)
333 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
337 /* Create the FPU instance key */
338 Error
= RegCreateKey(FpuKey
,
341 if (Error
!= ERROR_SUCCESS
)
343 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
347 /* Get 'VendorIdentifier' */
348 GetCpuid(0, &eax
, &ebx
, &ecx
, &edx
);
349 tmpVendorIdentifier
[12] = 0;
350 Ptr
= (ULONG
*)&tmpVendorIdentifier
[0];
356 swprintf(VendorIdentifier
, L
"%S", tmpVendorIdentifier
);
358 /* Get 'Identifier' */
360 L
"x86 Family %u Model %u Stepping %u",
361 (ULONG
)((CpuEntry
->CpuSignature
>> 8) & 0x0F),
362 (ULONG
)((CpuEntry
->CpuSignature
>> 4) & 0x0F),
363 (ULONG
)(CpuEntry
->CpuSignature
& 0x0F));
366 FeatureSet
= CpuEntry
->FeatureFlags
;
368 /* Check if Extended CPUID information is supported */
369 GetCpuid(0x80000000, &eax
, &ebx
, &ecx
, &edx
);
371 if(eax
>= 0x80000004)
373 /* Get 'ProcessorNameString' */
374 tmpProcessorNameString
[48] = 0;
375 Ptr
= (ULONG
*)&tmpProcessorNameString
[0];
377 for (i
= 0x80000002; i
<= 0x80000004; i
++)
379 GetCpuid(i
, &eax
, &ebx
, &ecx
, &edx
);
390 swprintf(ProcessorNameString
, L
"%S", tmpProcessorNameString
);
393 /* Set 'ProcessorNameString' value (CPU only) */
394 DbgPrint((DPRINT_HWDETECT
, "Processor Name String: %S\n", ProcessorNameString
));
396 Error
= RegSetValue(CpuInstKey
,
397 L
"ProcessorNameString",
399 (PCHAR
)ProcessorNameString
,
400 (wcslen(ProcessorNameString
) + 1) * sizeof(WCHAR
));
401 if (Error
!= ERROR_SUCCESS
)
402 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
405 /* Set 'Configuration Data' value (CPU and FPU) */
406 SetComponentInformation(CpuInstKey
,
408 CpuEntry
->LocalApicId
,
409 1 << CpuEntry
->LocalApicId
);
411 SetComponentInformation(FpuInstKey
,
413 CpuEntry
->LocalApicId
,
414 1 << CpuEntry
->LocalApicId
);
416 /* Set 'FeatureSet' value (CPU only) */
417 DbgPrint((DPRINT_HWDETECT
, "FeatureSet: %x\n", FeatureSet
));
419 Error
= RegSetValue(CpuInstKey
,
424 if (Error
!= ERROR_SUCCESS
)
426 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
429 /* Set 'Identifier' value (CPU and FPU) */
430 DbgPrint((DPRINT_HWDETECT
, "Identifier: %S\n", Identifier
));
432 Error
= RegSetValue(CpuInstKey
,
436 (wcslen(Identifier
) + 1) * sizeof(WCHAR
));
437 if (Error
!= ERROR_SUCCESS
)
439 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
442 Error
= RegSetValue(FpuInstKey
,
446 (wcslen(Identifier
) + 1) * sizeof(WCHAR
));
447 if (Error
!= ERROR_SUCCESS
)
449 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
452 /* Set 'VendorIdentifier' value (CPU only) */
453 DbgPrint((DPRINT_HWDETECT
, "Vendor Identifier: %S\n", VendorIdentifier
));
455 Error
= RegSetValue(CpuInstKey
,
458 (PCHAR
)VendorIdentifier
,
459 (wcslen(VendorIdentifier
) + 1) * sizeof(WCHAR
));
460 if (Error
!= ERROR_SUCCESS
)
462 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
465 /* FIXME: Set 'Update Signature' value (CPU only) */
467 /* FIXME: Set 'Update Status' value (CPU only) */
469 /* Set '~MHz' value (CPU only) */
470 if (((CpuEntry
->CpuSignature
>> 8) & 0x0F) >= 5)
472 CpuSpeed
= GetCpuSpeed();
474 Error
= RegSetValue(CpuInstKey
,
479 if (Error
!= ERROR_SUCCESS
)
481 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
487 static PMP_FLOATING_POINT_TABLE
488 GetMpFloatingPointTable(VOID
)
490 PMP_FLOATING_POINT_TABLE FpTable
;
496 FpTable
= (PMP_FLOATING_POINT_TABLE
)0xF0000;
497 while ((ULONG
)FpTable
< 0x100000)
499 if (FpTable
->Signature
== MP_FP_SIGNATURE
)
501 Length
= FpTable
->Length
* 0x10;
502 Ptr
= (char *)FpTable
;
504 for (i
= 0; i
< Length
; i
++)
508 DbgPrint((DPRINT_HWDETECT
,
514 DbgPrint((DPRINT_HWDETECT
,
515 "Invalid MP floating point checksum: %u\n",
523 FpTable
= (PMP_FLOATING_POINT_TABLE
)((ULONG
)FpTable
+ 0x10);
530 static PMP_CONFIGURATION_TABLE
531 GetMpConfigurationTable(PMP_FLOATING_POINT_TABLE FpTable
)
533 PMP_CONFIGURATION_TABLE ConfigTable
;
539 if (FpTable
->FeatureByte
[0] != 0 ||
540 FpTable
->PhysicalAddressPointer
== 0)
543 ConfigTable
= (PMP_CONFIGURATION_TABLE
)FpTable
->PhysicalAddressPointer
;
544 if (ConfigTable
->Signature
!= MP_CT_SIGNATURE
)
547 DbgPrint((DPRINT_HWDETECT
,
548 "MP Configuration Table at: %x\n",
549 (ULONG
)ConfigTable
));
551 /* Calculate base table checksum */
552 Length
= ConfigTable
->BaseTableLength
;
553 Ptr
= (char *)ConfigTable
;
555 for (i
= 0; i
< Length
; i
++)
559 DbgPrint((DPRINT_HWDETECT
,
560 "MP Configuration Table base checksum: %u\n",
565 DbgPrint((DPRINT_HWDETECT
,
566 "Invalid MP Configuration Table base checksum: %u\n",
571 if (ConfigTable
->ExtendedTableLength
!= 0)
573 /* FIXME: Check extended table */
581 DetectMps(FRLDRHKEY CpuKey
,
584 PMP_FLOATING_POINT_TABLE FpTable
;
585 PMP_CONFIGURATION_TABLE ConfigTable
;
586 PMP_PROCESSOR_ENTRY CpuEntry
;
590 /* Get floating point table */
591 FpTable
= GetMpFloatingPointTable();
595 DbgPrint((DPRINT_HWDETECT
,
596 "MP Floating Point Table at: %x\n",
599 if (FpTable
->FeatureByte
[0] == 0)
601 /* Get configuration table */
602 ConfigTable
= GetMpConfigurationTable(FpTable
);
603 if (ConfigTable
== NULL
)
605 DbgPrint((DPRINT_HWDETECT
,
606 "Failed to find the MP Configuration Table\n"));
610 Offset
= sizeof(MP_CONFIGURATION_TABLE
);
611 while (Offset
< ConfigTable
->BaseTableLength
)
613 Ptr
= (char*)((ULONG
)ConfigTable
+ Offset
);
618 CpuEntry
= (PMP_PROCESSOR_ENTRY
)Ptr
;
620 DbgPrint((DPRINT_HWDETECT
, "Processor Entry\n"));
621 DbgPrint((DPRINT_HWDETECT
,
622 "APIC Id %u APIC Version %u Flags %x Signature %x Feature %x\n",
623 CpuEntry
->LocalApicId
,
624 CpuEntry
->LocalApicVersion
,
626 CpuEntry
->CpuSignature
,
627 CpuEntry
->FeatureFlags
));
628 DbgPrint((DPRINT_HWDETECT
,
629 "Processor %u: x86 Family %u Model %u Stepping %u\n",
630 CpuEntry
->LocalApicId
,
631 (ULONG
)((CpuEntry
->CpuSignature
>> 8) & 0x0F),
632 (ULONG
)((CpuEntry
->CpuSignature
>> 4) & 0x0F),
633 (ULONG
)(CpuEntry
->CpuSignature
& 0x0F)));
635 SetMpsProcessor(CpuKey
, FpuKey
, CpuEntry
);
640 DbgPrint((DPRINT_HWDETECT
, "Bus Entry\n"));
645 DbgPrint((DPRINT_HWDETECT
, "I/0 APIC Entry\n"));
650 DbgPrint((DPRINT_HWDETECT
, "I/0 Interrupt Assignment Entry\n"));
655 DbgPrint((DPRINT_HWDETECT
, "Local Interrupt Assignment Entry\n"));
660 DbgPrint((DPRINT_HWDETECT
, "Unknown Entry %u\n",(ULONG
)*Ptr
));
667 DbgPrint((DPRINT_HWDETECT
,
668 "Unsupported MPS configuration: %x\n",
669 FpTable
->FeatureByte
[0]));
671 /* FIXME: Identify default configurations */
682 DetectCPUs(FRLDRHKEY SystemKey
)
688 /* Create the 'CentralProcessor' key */
689 Error
= RegCreateKey(SystemKey
,
692 if (Error
!= ERROR_SUCCESS
)
694 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
698 /* Create the 'FloatingPointProcessor' key */
699 Error
= RegCreateKey(SystemKey
,
700 L
"FloatingPointProcessor",
702 if (Error
!= ERROR_SUCCESS
)
704 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
709 if (!DetectMps(CpuKey
, FpuKey
))
711 DetectCPU(CpuKey
, FpuKey
);