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 CHAR VendorIdentifier
[13];
111 FRLDRHKEY CpuInstKey
;
112 FRLDRHKEY FpuInstKey
;
119 BOOL SupportTSC
= FALSE
;
123 /* Create the CPU instance key */
124 Error
= RegCreateKey(CpuKey
,
127 if (Error
!= ERROR_SUCCESS
)
129 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
133 /* Create the FPU instance key */
134 Error
= RegCreateKey(FpuKey
,
137 if (Error
!= ERROR_SUCCESS
)
139 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
143 eax
= CpuidSupported();
146 DbgPrint((DPRINT_HWDETECT
, "CPUID supported\n"));
148 /* Get vendor identifier */
149 GetCpuid(0, &eax
, &ebx
, &ecx
, &edx
);
150 VendorIdentifier
[12] = 0;
151 Ptr
= (ULONG
*)&VendorIdentifier
[0];
159 GetCpuid(1, &eax
, &ebx
, &ecx
, &edx
);
161 "x86 Family %u Model %u Stepping %u",
162 (unsigned int)((eax
>> 8) & 0x0F),
163 (unsigned int)((eax
>> 4) & 0x0F),
164 (unsigned int)(eax
& 0x0F));
166 if (((eax
>> 8) & 0x0F) >= 5)
171 DbgPrint((DPRINT_HWDETECT
, "CPUID not supported\n"));
173 strcpy(VendorIdentifier
, "Unknown");
175 "x86 Family %u Model %u Stepping %u",
176 (unsigned int)((eax
>> 8) & 0x0F),
177 (unsigned int)((eax
>> 4) & 0x0F),
178 (unsigned int)(eax
& 0x0F));
182 /* Set 'Conmponent Information' value (CPU and FPU) */
183 SetComponentInformation(CpuInstKey
, 0, 0, 1);
184 SetComponentInformation(FpuInstKey
, 0, 0, 1);
186 /* Set 'FeatureSet' value (CPU only) */
187 DbgPrint((DPRINT_HWDETECT
, "FeatureSet: %x\n", FeatureSet
));
189 Error
= RegSetValue(CpuInstKey
,
194 if (Error
!= ERROR_SUCCESS
)
196 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
199 /* Set 'Identifier' value (CPU and FPU) */
200 DbgPrint((DPRINT_HWDETECT
, "Identifier: %s\n", Identifier
));
202 Error
= RegSetValue(CpuInstKey
,
206 strlen(Identifier
) + 1);
207 if (Error
!= ERROR_SUCCESS
)
209 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
212 Error
= RegSetValue(FpuInstKey
,
216 strlen(Identifier
) + 1);
217 if (Error
!= ERROR_SUCCESS
)
219 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
222 /* Set 'VendorIdentifier' value (CPU only) */
223 DbgPrint((DPRINT_HWDETECT
, "Vendor Identifier: %s\n", VendorIdentifier
));
225 Error
= RegSetValue(CpuInstKey
,
229 strlen(VendorIdentifier
) + 1);
230 if (Error
!= ERROR_SUCCESS
)
232 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
235 /* FIXME: Set 'Update Signature' value (CPU only) */
237 /* FIXME: Set 'Update Status' value (CPU only) */
239 /* Set '~MHz' value (CPU only) */
242 CpuSpeed
= GetCpuSpeed();
244 Error
= RegSetValue(CpuInstKey
,
249 if (Error
!= ERROR_SUCCESS
)
251 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
258 SetMpsProcessor(FRLDRHKEY CpuKey
,
260 PMP_PROCESSOR_ENTRY CpuEntry
)
262 char VendorIdentifier
[13];
266 FRLDRHKEY CpuInstKey
;
267 FRLDRHKEY FpuInstKey
;
276 /* Get processor instance number */
277 sprintf(Buffer
, "%u", CpuEntry
->LocalApicId
);
279 /* Create the CPU instance key */
280 Error
= RegCreateKey(CpuKey
,
283 if (Error
!= ERROR_SUCCESS
)
285 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
289 /* Create the FPU instance key */
290 Error
= RegCreateKey(FpuKey
,
293 if (Error
!= ERROR_SUCCESS
)
295 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
299 /* Get 'VendorIdentifier' */
300 GetCpuid(0, &eax
, &ebx
, &ecx
, &edx
);
301 VendorIdentifier
[12] = 0;
302 Ptr
= (ULONG
*)&VendorIdentifier
[0];
309 /* Get 'Identifier' */
311 "x86 Family %u Model %u Stepping %u",
312 (ULONG
)((CpuEntry
->CpuSignature
>> 8) & 0x0F),
313 (ULONG
)((CpuEntry
->CpuSignature
>> 4) & 0x0F),
314 (ULONG
)(CpuEntry
->CpuSignature
& 0x0F));
317 FeatureSet
= CpuEntry
->FeatureFlags
;
319 /* Set 'Configuration Data' value (CPU and FPU) */
320 SetComponentInformation(CpuInstKey
,
322 CpuEntry
->LocalApicId
,
323 1 << CpuEntry
->LocalApicId
);
325 SetComponentInformation(FpuInstKey
,
327 CpuEntry
->LocalApicId
,
328 1 << CpuEntry
->LocalApicId
);
330 /* Set 'FeatureSet' value (CPU only) */
331 DbgPrint((DPRINT_HWDETECT
, "FeatureSet: %x\n", FeatureSet
));
333 Error
= RegSetValue(CpuInstKey
,
338 if (Error
!= ERROR_SUCCESS
)
340 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
343 /* Set 'Identifier' value (CPU and FPU) */
344 DbgPrint((DPRINT_HWDETECT
, "Identifier: %s\n", Identifier
));
346 Error
= RegSetValue(CpuInstKey
,
350 strlen(Identifier
) + 1);
351 if (Error
!= ERROR_SUCCESS
)
353 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
356 Error
= RegSetValue(FpuInstKey
,
360 strlen(Identifier
) + 1);
361 if (Error
!= ERROR_SUCCESS
)
363 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
366 /* Set 'VendorIdentifier' value (CPU only) */
367 DbgPrint((DPRINT_HWDETECT
, "Vendor Identifier: %s\n", VendorIdentifier
));
369 Error
= RegSetValue(CpuInstKey
,
373 strlen(VendorIdentifier
) + 1);
374 if (Error
!= ERROR_SUCCESS
)
376 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
379 /* FIXME: Set 'Update Signature' value (CPU only) */
381 /* FIXME: Set 'Update Status' value (CPU only) */
383 /* Set '~MHz' value (CPU only) */
384 if (((CpuEntry
->CpuSignature
>> 8) & 0x0F) >= 5)
386 CpuSpeed
= GetCpuSpeed();
388 Error
= RegSetValue(CpuInstKey
,
393 if (Error
!= ERROR_SUCCESS
)
395 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
401 static PMP_FLOATING_POINT_TABLE
402 GetMpFloatingPointTable(VOID
)
404 PMP_FLOATING_POINT_TABLE FpTable
;
410 FpTable
= (PMP_FLOATING_POINT_TABLE
)0xF0000;
411 while ((ULONG
)FpTable
< 0x100000)
413 if (FpTable
->Signature
== MP_FP_SIGNATURE
)
415 Length
= FpTable
->Length
* 0x10;
416 Ptr
= (char *)FpTable
;
418 for (i
= 0; i
< Length
; i
++)
422 DbgPrint((DPRINT_HWDETECT
,
428 DbgPrint((DPRINT_HWDETECT
,
429 "Invalid MP floating point checksum: %u\n",
437 FpTable
= (PMP_FLOATING_POINT_TABLE
)((ULONG
)FpTable
+ 0x10);
444 static PMP_CONFIGURATION_TABLE
445 GetMpConfigurationTable(PMP_FLOATING_POINT_TABLE FpTable
)
447 PMP_CONFIGURATION_TABLE ConfigTable
;
453 if (FpTable
->FeatureByte
[0] != 0 ||
454 FpTable
->PhysicalAddressPointer
== 0)
457 ConfigTable
= (PMP_CONFIGURATION_TABLE
)FpTable
->PhysicalAddressPointer
;
458 if (ConfigTable
->Signature
!= MP_CT_SIGNATURE
)
461 DbgPrint((DPRINT_HWDETECT
,
462 "MP Configuration Table at: %x\n",
463 (ULONG
)ConfigTable
));
465 /* Calculate base table checksum */
466 Length
= ConfigTable
->BaseTableLength
;
467 Ptr
= (char *)ConfigTable
;
469 for (i
= 0; i
< Length
; i
++)
473 DbgPrint((DPRINT_HWDETECT
,
474 "MP Configuration Table base checksum: %u\n",
479 DbgPrint((DPRINT_HWDETECT
,
480 "Invalid MP Configuration Table base checksum: %u\n",
485 if (ConfigTable
->ExtendedTableLength
!= 0)
487 /* FIXME: Check extended table */
495 DetectMps(FRLDRHKEY CpuKey
,
498 PMP_FLOATING_POINT_TABLE FpTable
;
499 PMP_CONFIGURATION_TABLE ConfigTable
;
500 PMP_PROCESSOR_ENTRY CpuEntry
;
504 /* Get floating point table */
505 FpTable
= GetMpFloatingPointTable();
509 DbgPrint((DPRINT_HWDETECT
,
510 "MP Floating Point Table at: %x\n",
513 if (FpTable
->FeatureByte
[0] == 0)
515 /* Get configuration table */
516 ConfigTable
= GetMpConfigurationTable(FpTable
);
517 if (ConfigTable
== NULL
)
519 DbgPrint((DPRINT_HWDETECT
,
520 "Failed to find the MP Configuration Table\n"));
524 Offset
= sizeof(MP_CONFIGURATION_TABLE
);
525 while (Offset
< ConfigTable
->BaseTableLength
)
527 Ptr
= (char*)((ULONG
)ConfigTable
+ Offset
);
532 CpuEntry
= (PMP_PROCESSOR_ENTRY
)Ptr
;
534 DbgPrint((DPRINT_HWDETECT
, "Processor Entry\n"));
535 DbgPrint((DPRINT_HWDETECT
,
536 "APIC Id %u APIC Version %u Flags %x Signature %x Feature %x\n",
537 CpuEntry
->LocalApicId
,
538 CpuEntry
->LocalApicVersion
,
540 CpuEntry
->CpuSignature
,
541 CpuEntry
->FeatureFlags
));
542 DbgPrint((DPRINT_HWDETECT
,
543 "Processor %u: x86 Family %u Model %u Stepping %u\n",
544 CpuEntry
->LocalApicId
,
545 (ULONG
)((CpuEntry
->CpuSignature
>> 8) & 0x0F),
546 (ULONG
)((CpuEntry
->CpuSignature
>> 4) & 0x0F),
547 (ULONG
)(CpuEntry
->CpuSignature
& 0x0F)));
549 SetMpsProcessor(CpuKey
, FpuKey
, CpuEntry
);
554 DbgPrint((DPRINT_HWDETECT
, "Bus Entry\n"));
559 DbgPrint((DPRINT_HWDETECT
, "I/0 APIC Entry\n"));
564 DbgPrint((DPRINT_HWDETECT
, "I/0 Interrupt Assignment Entry\n"));
569 DbgPrint((DPRINT_HWDETECT
, "Local Interrupt Assignment Entry\n"));
574 DbgPrint((DPRINT_HWDETECT
, "Unknown Entry %u\n",(ULONG
)*Ptr
));
581 DbgPrint((DPRINT_HWDETECT
,
582 "Unsupported MPS configuration: %x\n",
583 FpTable
->FeatureByte
[0]));
585 /* FIXME: Identify default configurations */
596 DetectCPUs(FRLDRHKEY SystemKey
)
602 /* Create the 'CentralProcessor' key */
603 Error
= RegCreateKey(SystemKey
,
606 if (Error
!= ERROR_SUCCESS
)
608 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
612 /* Create the 'FloatingPointProcessor' key */
613 Error
= RegCreateKey(SystemKey
,
614 "FloatingPointProcessor",
616 if (Error
!= ERROR_SUCCESS
)
618 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
623 if (!DetectMps(CpuKey
, FpuKey
))
625 DetectCPU(CpuKey
, FpuKey
);