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.
28 #include "../../reactos/registry.h"
32 #define MP_FP_SIGNATURE 0x5F504D5F /* "_MP_" */
33 #define MP_CT_SIGNATURE 0x504D4350 /* "PCMP" */
36 typedef struct _MP_FLOATING_POINT_TABLE
38 ULONG Signature
; /* "_MP_" */
39 ULONG PhysicalAddressPointer
;
44 } PACKED MP_FLOATING_POINT_TABLE
, *PMP_FLOATING_POINT_TABLE
;
47 typedef struct _MPS_CONFIG_TABLE_HEADER
49 ULONG Signature
; /* "PCMP" */
50 USHORT BaseTableLength
;
54 UCHAR ProductIdString
[12];
55 ULONG OemTablePointer
;
56 USHORT OemTableLength
;
58 ULONG AddressOfLocalAPIC
;
59 USHORT ExtendedTableLength
;
60 UCHAR ExtendedTableChecksum
;
62 } PACKED MP_CONFIGURATION_TABLE
, *PMP_CONFIGURATION_TABLE
;
65 typedef struct _MP_PROCESSOR_ENTRY
69 UCHAR LocalApicVersion
;
75 } PACKED MP_PROCESSOR_ENTRY
, *PMP_PROCESSOR_ENTRY
;
78 /* FUNCTIONS ****************************************************************/
87 /* Read TSC (Time Stamp Counter) */
90 /* Wait for 0.1 seconds (= 100 milliseconds = 100000 microseconds)*/
91 StallExecutionProcessor(100000);
93 /* Read TSC (Time Stamp Counter) again */
96 /* Calculate elapsed time (check for counter overrun) */
97 if (Timestamp2
> Timestamp1
)
99 Diff
= Timestamp2
- Timestamp1
;
103 Diff
= Timestamp2
+ (((ULONGLONG
)-1) - Timestamp1
);
106 return (ULONG
)(Diff
/ 100000);
111 DetectCPU(FRLDRHKEY CpuKey
,
114 CHAR VendorIdentifier
[13];
117 FRLDRHKEY CpuInstKey
;
118 FRLDRHKEY FpuInstKey
;
125 BOOL SupportTSC
= FALSE
;
129 /* Create the CPU instance key */
130 Error
= RegCreateKey(CpuKey
,
133 if (Error
!= ERROR_SUCCESS
)
135 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
139 /* Create the FPU instance key */
140 Error
= RegCreateKey(FpuKey
,
143 if (Error
!= ERROR_SUCCESS
)
145 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
149 eax
= CpuidSupported();
152 DbgPrint((DPRINT_HWDETECT
, "CPUID supported\n"));
154 /* Get vendor identifier */
155 GetCpuid(0, &eax
, &ebx
, &ecx
, &edx
);
156 VendorIdentifier
[12] = 0;
157 Ptr
= (ULONG
*)&VendorIdentifier
[0];
165 GetCpuid(1, &eax
, &ebx
, &ecx
, &edx
);
167 "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)
177 DbgPrint((DPRINT_HWDETECT
, "CPUID not supported\n"));
179 strcpy(VendorIdentifier
, "Unknown");
181 "x86 Family %u Model %u Stepping %u",
182 (unsigned int)((eax
>> 8) & 0x0F),
183 (unsigned int)((eax
>> 4) & 0x0F),
184 (unsigned int)(eax
& 0x0F));
188 /* Set 'Conmponent Information' value (CPU and FPU) */
189 SetComponentInformation(CpuInstKey
, 0, 0, 1);
190 SetComponentInformation(FpuInstKey
, 0, 0, 1);
192 /* Set 'FeatureSet' value (CPU only) */
193 DbgPrint((DPRINT_HWDETECT
, "FeatureSet: %x\n", FeatureSet
));
195 Error
= RegSetValue(CpuInstKey
,
200 if (Error
!= ERROR_SUCCESS
)
202 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
205 /* Set 'Identifier' value (CPU and FPU) */
206 DbgPrint((DPRINT_HWDETECT
, "Identifier: %s\n", Identifier
));
208 Error
= RegSetValue(CpuInstKey
,
212 strlen(Identifier
) + 1);
213 if (Error
!= ERROR_SUCCESS
)
215 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
218 Error
= RegSetValue(FpuInstKey
,
222 strlen(Identifier
) + 1);
223 if (Error
!= ERROR_SUCCESS
)
225 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
228 /* Set 'VendorIdentifier' value (CPU only) */
229 DbgPrint((DPRINT_HWDETECT
, "Vendor Identifier: %s\n", VendorIdentifier
));
231 Error
= RegSetValue(CpuInstKey
,
235 strlen(VendorIdentifier
) + 1);
236 if (Error
!= ERROR_SUCCESS
)
238 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
241 /* FIXME: Set 'Update Signature' value (CPU only) */
243 /* FIXME: Set 'Update Status' value (CPU only) */
245 /* Set '~MHz' value (CPU only) */
248 CpuSpeed
= GetCpuSpeed();
250 Error
= RegSetValue(CpuInstKey
,
255 if (Error
!= ERROR_SUCCESS
)
257 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
264 SetMpsProcessor(FRLDRHKEY CpuKey
,
266 PMP_PROCESSOR_ENTRY CpuEntry
)
268 char VendorIdentifier
[13];
272 FRLDRHKEY CpuInstKey
;
273 FRLDRHKEY FpuInstKey
;
282 /* Get processor instance number */
283 sprintf(Buffer
, "%u", CpuEntry
->LocalApicId
);
285 /* Create the CPU instance key */
286 Error
= RegCreateKey(CpuKey
,
289 if (Error
!= ERROR_SUCCESS
)
291 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
295 /* Create the FPU instance key */
296 Error
= RegCreateKey(FpuKey
,
299 if (Error
!= ERROR_SUCCESS
)
301 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
305 /* Get 'VendorIdentifier' */
306 GetCpuid(0, &eax
, &ebx
, &ecx
, &edx
);
307 VendorIdentifier
[12] = 0;
308 Ptr
= (ULONG
*)&VendorIdentifier
[0];
315 /* Get 'Identifier' */
317 "x86 Family %u Model %u Stepping %u",
318 (ULONG
)((CpuEntry
->CpuSignature
>> 8) & 0x0F),
319 (ULONG
)((CpuEntry
->CpuSignature
>> 4) & 0x0F),
320 (ULONG
)(CpuEntry
->CpuSignature
& 0x0F));
323 FeatureSet
= CpuEntry
->FeatureFlags
;
325 /* Set 'Configuration Data' value (CPU and FPU) */
326 SetComponentInformation(CpuInstKey
,
328 CpuEntry
->LocalApicId
,
329 1 << CpuEntry
->LocalApicId
);
331 SetComponentInformation(FpuInstKey
,
333 CpuEntry
->LocalApicId
,
334 1 << CpuEntry
->LocalApicId
);
336 /* Set 'FeatureSet' value (CPU only) */
337 DbgPrint((DPRINT_HWDETECT
, "FeatureSet: %x\n", FeatureSet
));
339 Error
= RegSetValue(CpuInstKey
,
344 if (Error
!= ERROR_SUCCESS
)
346 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
349 /* Set 'Identifier' value (CPU and FPU) */
350 DbgPrint((DPRINT_HWDETECT
, "Identifier: %s\n", Identifier
));
352 Error
= RegSetValue(CpuInstKey
,
356 strlen(Identifier
) + 1);
357 if (Error
!= ERROR_SUCCESS
)
359 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
362 Error
= RegSetValue(FpuInstKey
,
366 strlen(Identifier
) + 1);
367 if (Error
!= ERROR_SUCCESS
)
369 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
372 /* Set 'VendorIdentifier' value (CPU only) */
373 DbgPrint((DPRINT_HWDETECT
, "Vendor Identifier: %s\n", VendorIdentifier
));
375 Error
= RegSetValue(CpuInstKey
,
379 strlen(VendorIdentifier
) + 1);
380 if (Error
!= ERROR_SUCCESS
)
382 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
385 /* FIXME: Set 'Update Signature' value (CPU only) */
387 /* FIXME: Set 'Update Status' value (CPU only) */
389 /* Set '~MHz' value (CPU only) */
390 if (((CpuEntry
->CpuSignature
>> 8) & 0x0F) >= 5)
392 CpuSpeed
= GetCpuSpeed();
394 Error
= RegSetValue(CpuInstKey
,
399 if (Error
!= ERROR_SUCCESS
)
401 DbgPrint((DPRINT_HWDETECT
, "RegSetValue() failed (Error %u)\n", (int)Error
));
407 static PMP_FLOATING_POINT_TABLE
408 GetMpFloatingPointTable(VOID
)
410 PMP_FLOATING_POINT_TABLE FpTable
;
416 FpTable
= (PMP_FLOATING_POINT_TABLE
)0xF0000;
417 while ((ULONG
)FpTable
< 0x100000)
419 if (FpTable
->Signature
== MP_FP_SIGNATURE
)
421 Length
= FpTable
->Length
* 0x10;
422 Ptr
= (char *)FpTable
;
424 for (i
= 0; i
< Length
; i
++)
428 DbgPrint((DPRINT_HWDETECT
,
434 DbgPrint((DPRINT_HWDETECT
,
435 "Invalid MP floating point checksum: %u\n",
443 FpTable
= (PMP_FLOATING_POINT_TABLE
)((ULONG
)FpTable
+ 0x10);
450 static PMP_CONFIGURATION_TABLE
451 GetMpConfigurationTable(PMP_FLOATING_POINT_TABLE FpTable
)
453 PMP_CONFIGURATION_TABLE ConfigTable
;
459 if (FpTable
->FeatureByte
[0] != 0 ||
460 FpTable
->PhysicalAddressPointer
== 0)
463 ConfigTable
= (PMP_CONFIGURATION_TABLE
)FpTable
->PhysicalAddressPointer
;
464 if (ConfigTable
->Signature
!= MP_CT_SIGNATURE
)
467 DbgPrint((DPRINT_HWDETECT
,
468 "MP Configuration Table at: %x\n",
469 (ULONG
)ConfigTable
));
471 /* Calculate base table checksum */
472 Length
= ConfigTable
->BaseTableLength
;
473 Ptr
= (char *)ConfigTable
;
475 for (i
= 0; i
< Length
; i
++)
479 DbgPrint((DPRINT_HWDETECT
,
480 "MP Configuration Table base checksum: %u\n",
485 DbgPrint((DPRINT_HWDETECT
,
486 "Invalid MP Configuration Table base checksum: %u\n",
491 if (ConfigTable
->ExtendedTableLength
!= 0)
493 /* FIXME: Check extended table */
501 DetectMps(FRLDRHKEY CpuKey
,
504 PMP_FLOATING_POINT_TABLE FpTable
;
505 PMP_CONFIGURATION_TABLE ConfigTable
;
506 PMP_PROCESSOR_ENTRY CpuEntry
;
510 /* Get floating point table */
511 FpTable
= GetMpFloatingPointTable();
515 DbgPrint((DPRINT_HWDETECT
,
516 "MP Floating Point Table at: %x\n",
519 if (FpTable
->FeatureByte
[0] == 0)
521 /* Get configuration table */
522 ConfigTable
= GetMpConfigurationTable(FpTable
);
523 if (ConfigTable
== NULL
)
525 DbgPrint((DPRINT_HWDETECT
,
526 "Failed to find the MP Configuration Table\n"));
530 Offset
= sizeof(MP_CONFIGURATION_TABLE
);
531 while (Offset
< ConfigTable
->BaseTableLength
)
533 Ptr
= (char*)((ULONG
)ConfigTable
+ Offset
);
538 CpuEntry
= (PMP_PROCESSOR_ENTRY
)Ptr
;
540 DbgPrint((DPRINT_HWDETECT
, "Processor Entry\n"));
541 DbgPrint((DPRINT_HWDETECT
,
542 "APIC Id %u APIC Version %u Flags %x Signature %x Feature %x\n",
543 CpuEntry
->LocalApicId
,
544 CpuEntry
->LocalApicVersion
,
546 CpuEntry
->CpuSignature
,
547 CpuEntry
->FeatureFlags
));
548 DbgPrint((DPRINT_HWDETECT
,
549 "Processor %u: x86 Family %u Model %u Stepping %u\n",
550 CpuEntry
->LocalApicId
,
551 (ULONG
)((CpuEntry
->CpuSignature
>> 8) & 0x0F),
552 (ULONG
)((CpuEntry
->CpuSignature
>> 4) & 0x0F),
553 (ULONG
)(CpuEntry
->CpuSignature
& 0x0F)));
555 SetMpsProcessor(CpuKey
, FpuKey
, CpuEntry
);
560 DbgPrint((DPRINT_HWDETECT
, "Bus Entry\n"));
565 DbgPrint((DPRINT_HWDETECT
, "I/0 APIC Entry\n"));
570 DbgPrint((DPRINT_HWDETECT
, "I/0 Interrupt Assignment Entry\n"));
575 DbgPrint((DPRINT_HWDETECT
, "Local Interrupt Assignment Entry\n"));
580 DbgPrint((DPRINT_HWDETECT
, "Unknown Entry %u\n",(ULONG
)*Ptr
));
587 DbgPrint((DPRINT_HWDETECT
,
588 "Unsupported MPS configuration: %x\n",
589 FpTable
->FeatureByte
[0]));
591 /* FIXME: Identify default configurations */
602 DetectCPUs(FRLDRHKEY SystemKey
)
608 /* Create the 'CentralProcessor' key */
609 Error
= RegCreateKey(SystemKey
,
612 if (Error
!= ERROR_SUCCESS
)
614 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
618 /* Create the 'FloatingPointProcessor' key */
619 Error
= RegCreateKey(SystemKey
,
620 "FloatingPointProcessor",
622 if (Error
!= ERROR_SUCCESS
)
624 DbgPrint((DPRINT_HWDETECT
, "RegCreateKey() failed (Error %u)\n", (int)Error
));
629 if (!DetectMps(CpuKey
, FpuKey
))
631 DetectCPU(CpuKey
, FpuKey
);