4 * Copyright (C) 2003 Eric Kohl
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #define MP_FP_SIGNATURE 0x5F504D5F /* "_MP_" */
27 #define MP_CT_SIGNATURE 0x504D4350 /* "PCMP" */
30 typedef struct _MP_FLOATING_POINT_TABLE
32 ULONG Signature
; /* "_MP_" */
33 ULONG PhysicalAddressPointer
;
38 } PACKED MP_FLOATING_POINT_TABLE
, *PMP_FLOATING_POINT_TABLE
;
41 typedef struct _MPS_CONFIG_TABLE_HEADER
43 ULONG Signature
; /* "PCMP" */
44 USHORT BaseTableLength
;
48 UCHAR ProductIdString
[12];
49 ULONG OemTablePointer
;
50 USHORT OemTableLength
;
52 ULONG AddressOfLocalAPIC
;
53 USHORT ExtendedTableLength
;
54 UCHAR ExtendedTableChecksum
;
56 } PACKED MP_CONFIGURATION_TABLE
, *PMP_CONFIGURATION_TABLE
;
59 typedef struct _MP_PROCESSOR_ENTRY
63 UCHAR LocalApicVersion
;
69 } PACKED MP_PROCESSOR_ENTRY
, *PMP_PROCESSOR_ENTRY
;
72 /* FUNCTIONS ****************************************************************/
81 /* Read TSC (Time Stamp Counter) */
84 /* Wait for 0.1 seconds (= 100 milliseconds = 100000 microseconds)*/
85 StallExecutionProcessor(100000);
87 /* Read TSC (Time Stamp Counter) again */
90 /* Calculate elapsed time (check for counter overrun) */
91 if (Timestamp2
> Timestamp1
)
93 Diff
= Timestamp2
- Timestamp1
;
97 Diff
= Timestamp2
+ (((ULONGLONG
)-1) - Timestamp1
);
100 return (ULONG
)(Diff
/ 100000);
105 DetectCPU(FRLDRHKEY CpuKey
,
108 WCHAR VendorIdentifier
[13];
109 CHAR tmpVendorIdentifier
[13];
110 WCHAR Identifier
[64];
112 FRLDRHKEY CpuInstKey
;
113 FRLDRHKEY FpuInstKey
;
120 BOOL SupportTSC
= FALSE
;
124 /* Create the CPU instance key */
125 Error
= RegCreateKey(CpuKey
,
128 if (Error
!= ERROR_SUCCESS
)
130 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
134 /* Create the FPU instance key */
135 Error
= RegCreateKey(FpuKey
,
138 if (Error
!= ERROR_SUCCESS
)
140 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
144 eax
= CpuidSupported();
147 DbgPrint((DPRINT_HWDETECT
, "CPUID supported\n"));
149 /* Get vendor identifier */
150 GetCpuid(0, &eax
, &ebx
, &ecx
, &edx
);
151 tmpVendorIdentifier
[12] = 0;
152 Ptr
= (ULONG
*)&tmpVendorIdentifier
[0];
158 swprintf(VendorIdentifier
, L
"%s", tmpVendorIdentifier
);
161 GetCpuid(1, &eax
, &ebx
, &ecx
, &edx
);
163 L
"x86 Family %u Model %u Stepping %u",
164 (unsigned int)((eax
>> 8) & 0x0F),
165 (unsigned int)((eax
>> 4) & 0x0F),
166 (unsigned int)(eax
& 0x0F));
168 if (((eax
>> 8) & 0x0F) >= 5)
173 DbgPrint((DPRINT_HWDETECT
, "CPUID not supported\n"));
175 wcscpy(VendorIdentifier
, L
"Unknown");
177 L
"x86 Family %u Model %u Stepping %u",
178 (unsigned int)((eax
>> 8) & 0x0F),
179 (unsigned int)((eax
>> 4) & 0x0F),
180 (unsigned int)(eax
& 0x0F));
184 /* Set 'Conmponent Information' value (CPU and FPU) */
185 SetComponentInformation(CpuInstKey
, 0, 0, 1);
186 SetComponentInformation(FpuInstKey
, 0, 0, 1);
188 /* Set 'FeatureSet' value (CPU only) */
189 DbgPrint((DPRINT_HWDETECT
, "FeatureSet: %x\n", FeatureSet
));
191 Error
= RegSetValue(CpuInstKey
,
196 if (Error
!= ERROR_SUCCESS
)
198 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
201 /* Set 'Identifier' value (CPU and FPU) */
202 DbgPrint((DPRINT_HWDETECT
, "Identifier: %S\n", Identifier
));
204 Error
= RegSetValue(CpuInstKey
,
208 (wcslen(Identifier
) + 1)* sizeof(WCHAR
));
209 if (Error
!= ERROR_SUCCESS
)
211 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
214 Error
= RegSetValue(FpuInstKey
,
218 (wcslen(Identifier
) + 1) * sizeof(WCHAR
));
219 if (Error
!= ERROR_SUCCESS
)
221 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
224 /* Set 'VendorIdentifier' value (CPU only) */
225 DbgPrint((DPRINT_HWDETECT
, "Vendor Identifier: %S\n", VendorIdentifier
));
227 Error
= RegSetValue(CpuInstKey
,
230 (PCHAR
)VendorIdentifier
,
231 (wcslen(VendorIdentifier
) + 1) * sizeof(WCHAR
));
232 if (Error
!= ERROR_SUCCESS
)
234 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
237 /* FIXME: Set 'Update Signature' value (CPU only) */
239 /* FIXME: Set 'Update Status' value (CPU only) */
241 /* Set '~MHz' value (CPU only) */
244 CpuSpeed
= GetCpuSpeed();
246 Error
= RegSetValue(CpuInstKey
,
251 if (Error
!= ERROR_SUCCESS
)
253 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
260 SetMpsProcessor(FRLDRHKEY CpuKey
,
262 PMP_PROCESSOR_ENTRY CpuEntry
)
264 WCHAR VendorIdentifier
[13];
265 CHAR tmpVendorIdentifier
[13];
266 WCHAR Identifier
[64];
269 FRLDRHKEY CpuInstKey
;
270 FRLDRHKEY FpuInstKey
;
279 /* Get processor instance number */
280 swprintf(Buffer
, L
"%u", CpuEntry
->LocalApicId
);
282 /* Create the CPU instance key */
283 Error
= RegCreateKey(CpuKey
,
286 if (Error
!= ERROR_SUCCESS
)
288 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
292 /* Create the FPU instance key */
293 Error
= RegCreateKey(FpuKey
,
296 if (Error
!= ERROR_SUCCESS
)
298 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
302 /* Get 'VendorIdentifier' */
303 GetCpuid(0, &eax
, &ebx
, &ecx
, &edx
);
304 tmpVendorIdentifier
[12] = 0;
305 Ptr
= (ULONG
*)&tmpVendorIdentifier
[0];
311 swprintf(VendorIdentifier
, L
"%s", tmpVendorIdentifier
);
313 /* Get 'Identifier' */
315 L
"x86 Family %u Model %u Stepping %u",
316 (ULONG
)((CpuEntry
->CpuSignature
>> 8) & 0x0F),
317 (ULONG
)((CpuEntry
->CpuSignature
>> 4) & 0x0F),
318 (ULONG
)(CpuEntry
->CpuSignature
& 0x0F));
321 FeatureSet
= CpuEntry
->FeatureFlags
;
323 /* Set 'Configuration Data' value (CPU and FPU) */
324 SetComponentInformation(CpuInstKey
,
326 CpuEntry
->LocalApicId
,
327 1 << CpuEntry
->LocalApicId
);
329 SetComponentInformation(FpuInstKey
,
331 CpuEntry
->LocalApicId
,
332 1 << CpuEntry
->LocalApicId
);
334 /* Set 'FeatureSet' value (CPU only) */
335 DbgPrint((DPRINT_HWDETECT
, "FeatureSet: %x\n", FeatureSet
));
337 Error
= RegSetValue(CpuInstKey
,
342 if (Error
!= ERROR_SUCCESS
)
344 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
347 /* Set 'Identifier' value (CPU and FPU) */
348 DbgPrint((DPRINT_HWDETECT
, "Identifier: %S\n", Identifier
));
350 Error
= RegSetValue(CpuInstKey
,
354 (wcslen(Identifier
) + 1) * sizeof(WCHAR
));
355 if (Error
!= ERROR_SUCCESS
)
357 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
360 Error
= RegSetValue(FpuInstKey
,
364 (wcslen(Identifier
) + 1) * sizeof(WCHAR
));
365 if (Error
!= ERROR_SUCCESS
)
367 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
370 /* Set 'VendorIdentifier' value (CPU only) */
371 DbgPrint((DPRINT_HWDETECT
, "Vendor Identifier: %S\n", VendorIdentifier
));
373 Error
= RegSetValue(CpuInstKey
,
376 (PCHAR
)VendorIdentifier
,
377 (wcslen(VendorIdentifier
) + 1) * sizeof(WCHAR
));
378 if (Error
!= ERROR_SUCCESS
)
380 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
383 /* FIXME: Set 'Update Signature' value (CPU only) */
385 /* FIXME: Set 'Update Status' value (CPU only) */
387 /* Set '~MHz' value (CPU only) */
388 if (((CpuEntry
->CpuSignature
>> 8) & 0x0F) >= 5)
390 CpuSpeed
= GetCpuSpeed();
392 Error
= RegSetValue(CpuInstKey
,
397 if (Error
!= ERROR_SUCCESS
)
399 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
405 static PMP_FLOATING_POINT_TABLE
406 GetMpFloatingPointTable(VOID
)
408 PMP_FLOATING_POINT_TABLE FpTable
;
414 FpTable
= (PMP_FLOATING_POINT_TABLE
)0xF0000;
415 while ((ULONG
)FpTable
< 0x100000)
417 if (FpTable
->Signature
== MP_FP_SIGNATURE
)
419 Length
= FpTable
->Length
* 0x10;
420 Ptr
= (char *)FpTable
;
422 for (i
= 0; i
< Length
; i
++)
426 DbgPrint((DPRINT_HWDETECT
,
432 DbgPrint((DPRINT_HWDETECT
,
433 "Invalid MP floating point checksum: %u\n",
441 FpTable
= (PMP_FLOATING_POINT_TABLE
)((ULONG
)FpTable
+ 0x10);
448 static PMP_CONFIGURATION_TABLE
449 GetMpConfigurationTable(PMP_FLOATING_POINT_TABLE FpTable
)
451 PMP_CONFIGURATION_TABLE ConfigTable
;
457 if (FpTable
->FeatureByte
[0] != 0 ||
458 FpTable
->PhysicalAddressPointer
== 0)
461 ConfigTable
= (PMP_CONFIGURATION_TABLE
)FpTable
->PhysicalAddressPointer
;
462 if (ConfigTable
->Signature
!= MP_CT_SIGNATURE
)
465 DbgPrint((DPRINT_HWDETECT
,
466 "MP Configuration Table at: %x\n",
467 (ULONG
)ConfigTable
));
469 /* Calculate base table checksum */
470 Length
= ConfigTable
->BaseTableLength
;
471 Ptr
= (char *)ConfigTable
;
473 for (i
= 0; i
< Length
; i
++)
477 DbgPrint((DPRINT_HWDETECT
,
478 "MP Configuration Table base checksum: %u\n",
483 DbgPrint((DPRINT_HWDETECT
,
484 "Invalid MP Configuration Table base checksum: %u\n",
489 if (ConfigTable
->ExtendedTableLength
!= 0)
491 /* FIXME: Check extended table */
499 DetectMps(FRLDRHKEY CpuKey
,
502 PMP_FLOATING_POINT_TABLE FpTable
;
503 PMP_CONFIGURATION_TABLE ConfigTable
;
504 PMP_PROCESSOR_ENTRY CpuEntry
;
508 /* Get floating point table */
509 FpTable
= GetMpFloatingPointTable();
513 DbgPrint((DPRINT_HWDETECT
,
514 "MP Floating Point Table at: %x\n",
517 if (FpTable
->FeatureByte
[0] == 0)
519 /* Get configuration table */
520 ConfigTable
= GetMpConfigurationTable(FpTable
);
521 if (ConfigTable
== NULL
)
523 DbgPrint((DPRINT_HWDETECT
,
524 "Failed to find the MP Configuration Table\n"));
528 Offset
= sizeof(MP_CONFIGURATION_TABLE
);
529 while (Offset
< ConfigTable
->BaseTableLength
)
531 Ptr
= (char*)((ULONG
)ConfigTable
+ Offset
);
536 CpuEntry
= (PMP_PROCESSOR_ENTRY
)Ptr
;
538 DbgPrint((DPRINT_HWDETECT
, "Processor Entry\n"));
539 DbgPrint((DPRINT_HWDETECT
,
540 "APIC Id %u APIC Version %u Flags %x Signature %x Feature %x\n",
541 CpuEntry
->LocalApicId
,
542 CpuEntry
->LocalApicVersion
,
544 CpuEntry
->CpuSignature
,
545 CpuEntry
->FeatureFlags
));
546 DbgPrint((DPRINT_HWDETECT
,
547 "Processor %u: x86 Family %u Model %u Stepping %u\n",
548 CpuEntry
->LocalApicId
,
549 (ULONG
)((CpuEntry
->CpuSignature
>> 8) & 0x0F),
550 (ULONG
)((CpuEntry
->CpuSignature
>> 4) & 0x0F),
551 (ULONG
)(CpuEntry
->CpuSignature
& 0x0F)));
553 SetMpsProcessor(CpuKey
, FpuKey
, CpuEntry
);
558 DbgPrint((DPRINT_HWDETECT
, "Bus Entry\n"));
563 DbgPrint((DPRINT_HWDETECT
, "I/0 APIC Entry\n"));
568 DbgPrint((DPRINT_HWDETECT
, "I/0 Interrupt Assignment Entry\n"));
573 DbgPrint((DPRINT_HWDETECT
, "Local Interrupt Assignment Entry\n"));
578 DbgPrint((DPRINT_HWDETECT
, "Unknown Entry %u\n",(ULONG
)*Ptr
));
585 DbgPrint((DPRINT_HWDETECT
,
586 "Unsupported MPS configuration: %x\n",
587 FpTable
->FeatureByte
[0]));
589 /* FIXME: Identify default configurations */
600 DetectCPUs(FRLDRHKEY SystemKey
)
606 /* Create the 'CentralProcessor' key */
607 Error
= RegCreateKey(SystemKey
,
610 if (Error
!= ERROR_SUCCESS
)
612 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
616 /* Create the 'FloatingPointProcessor' key */
617 Error
= RegCreateKey(SystemKey
,
618 L
"FloatingPointProcessor",
620 if (Error
!= ERROR_SUCCESS
)
622 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
627 if (!DetectMps(CpuKey
, FpuKey
))
629 DetectCPU(CpuKey
, FpuKey
);