- PCHify freeldr and cleanup some headers (just a start).
[reactos.git] / reactos / boot / freeldr / freeldr / arch / i386 / hwcpu.c
1 /*
2 * FreeLoader
3 *
4 * Copyright (C) 2003 Eric Kohl
5 *
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.
10 *
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.
15 *
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.
19 */
20
21 #include <freeldr.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 #define MP_FP_SIGNATURE 0x5F504D5F /* "_MP_" */
27 #define MP_CT_SIGNATURE 0x504D4350 /* "PCMP" */
28
29
30 typedef struct _MP_FLOATING_POINT_TABLE
31 {
32 ULONG Signature; /* "_MP_" */
33 ULONG PhysicalAddressPointer;
34 UCHAR Length;
35 UCHAR SpecRev;
36 UCHAR Checksum;
37 UCHAR FeatureByte[5];
38 } PACKED MP_FLOATING_POINT_TABLE, *PMP_FLOATING_POINT_TABLE;
39
40
41 typedef struct _MPS_CONFIG_TABLE_HEADER
42 {
43 ULONG Signature; /* "PCMP" */
44 USHORT BaseTableLength;
45 UCHAR SpecRev;
46 UCHAR Checksum;
47 UCHAR OemIdString[8];
48 UCHAR ProductIdString[12];
49 ULONG OemTablePointer;
50 USHORT OemTableLength;
51 USHORT EntryCount;
52 ULONG AddressOfLocalAPIC;
53 USHORT ExtendedTableLength;
54 UCHAR ExtendedTableChecksum;
55 UCHAR Reserved;
56 } PACKED MP_CONFIGURATION_TABLE, *PMP_CONFIGURATION_TABLE;
57
58
59 typedef struct _MP_PROCESSOR_ENTRY
60 {
61 UCHAR EntryType;
62 UCHAR LocalApicId;
63 UCHAR LocalApicVersion;
64 UCHAR CpuFlags;
65 ULONG CpuSignature;
66 ULONG FeatureFlags;
67 ULONG Reserved1;
68 ULONG Reserved2;
69 } PACKED MP_PROCESSOR_ENTRY, *PMP_PROCESSOR_ENTRY;
70
71
72 /* FUNCTIONS ****************************************************************/
73
74 static ULONG
75 GetCpuSpeed(VOID)
76 {
77 ULONGLONG Timestamp1;
78 ULONGLONG Timestamp2;
79 ULONGLONG Diff;
80
81 /* Read TSC (Time Stamp Counter) */
82 Timestamp1 = RDTSC();
83
84 /* Wait for 0.1 seconds (= 100 milliseconds = 100000 microseconds)*/
85 StallExecutionProcessor(100000);
86
87 /* Read TSC (Time Stamp Counter) again */
88 Timestamp2 = RDTSC();
89
90 /* Calculate elapsed time (check for counter overrun) */
91 if (Timestamp2 > Timestamp1)
92 {
93 Diff = Timestamp2 - Timestamp1;
94 }
95 else
96 {
97 Diff = Timestamp2 + (((ULONGLONG)-1) - Timestamp1);
98 }
99
100 return (ULONG)(Diff / 100000);
101 }
102
103
104 static VOID
105 DetectCPU(FRLDRHKEY CpuKey,
106 FRLDRHKEY FpuKey)
107 {
108 CHAR VendorIdentifier[13];
109 CHAR Identifier[64];
110 ULONG FeatureSet;
111 FRLDRHKEY CpuInstKey;
112 FRLDRHKEY FpuInstKey;
113 ULONG eax = 0;
114 ULONG ebx = 0;
115 ULONG ecx = 0;
116 ULONG edx = 0;
117 ULONG *Ptr;
118 LONG Error;
119 BOOL SupportTSC = FALSE;
120 ULONG CpuSpeed;
121
122
123 /* Create the CPU instance key */
124 Error = RegCreateKey(CpuKey,
125 "0",
126 &CpuInstKey);
127 if (Error != ERROR_SUCCESS)
128 {
129 DbgPrint((DPRINT_HWDETECT, "RegCreateKey() failed (Error %u)\n", (int)Error));
130 return;
131 }
132
133 /* Create the FPU instance key */
134 Error = RegCreateKey(FpuKey,
135 "0",
136 &FpuInstKey);
137 if (Error != ERROR_SUCCESS)
138 {
139 DbgPrint((DPRINT_HWDETECT, "RegCreateKey() failed (Error %u)\n", (int)Error));
140 return;
141 }
142
143 eax = CpuidSupported();
144 if (eax & 1)
145 {
146 DbgPrint((DPRINT_HWDETECT, "CPUID supported\n"));
147
148 /* Get vendor identifier */
149 GetCpuid(0, &eax, &ebx, &ecx, &edx);
150 VendorIdentifier[12] = 0;
151 Ptr = (ULONG*)&VendorIdentifier[0];
152 *Ptr = ebx;
153 Ptr++;
154 *Ptr = edx;
155 Ptr++;
156 *Ptr = ecx;
157
158 /* Get Identifier */
159 GetCpuid(1, &eax, &ebx, &ecx, &edx);
160 sprintf(Identifier,
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));
165 FeatureSet = edx;
166 if (((eax >> 8) & 0x0F) >= 5)
167 SupportTSC = TRUE;
168 }
169 else
170 {
171 DbgPrint((DPRINT_HWDETECT, "CPUID not supported\n"));
172
173 strcpy(VendorIdentifier, "Unknown");
174 sprintf(Identifier,
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));
179 FeatureSet = 0;
180 }
181
182 /* Set 'Conmponent Information' value (CPU and FPU) */
183 SetComponentInformation(CpuInstKey, 0, 0, 1);
184 SetComponentInformation(FpuInstKey, 0, 0, 1);
185
186 /* Set 'FeatureSet' value (CPU only) */
187 DbgPrint((DPRINT_HWDETECT, "FeatureSet: %x\n", FeatureSet));
188
189 Error = RegSetValue(CpuInstKey,
190 "FeatureSet",
191 REG_DWORD,
192 (PCHAR)&FeatureSet,
193 sizeof(ULONG));
194 if (Error != ERROR_SUCCESS)
195 {
196 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
197 }
198
199 /* Set 'Identifier' value (CPU and FPU) */
200 DbgPrint((DPRINT_HWDETECT, "Identifier: %s\n", Identifier));
201
202 Error = RegSetValue(CpuInstKey,
203 "Identifier",
204 REG_SZ,
205 Identifier,
206 strlen(Identifier) + 1);
207 if (Error != ERROR_SUCCESS)
208 {
209 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
210 }
211
212 Error = RegSetValue(FpuInstKey,
213 "Identifier",
214 REG_SZ,
215 Identifier,
216 strlen(Identifier) + 1);
217 if (Error != ERROR_SUCCESS)
218 {
219 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
220 }
221
222 /* Set 'VendorIdentifier' value (CPU only) */
223 DbgPrint((DPRINT_HWDETECT, "Vendor Identifier: %s\n", VendorIdentifier));
224
225 Error = RegSetValue(CpuInstKey,
226 "VendorIdentifier",
227 REG_SZ,
228 VendorIdentifier,
229 strlen(VendorIdentifier) + 1);
230 if (Error != ERROR_SUCCESS)
231 {
232 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
233 }
234
235 /* FIXME: Set 'Update Signature' value (CPU only) */
236
237 /* FIXME: Set 'Update Status' value (CPU only) */
238
239 /* Set '~MHz' value (CPU only) */
240 if (SupportTSC)
241 {
242 CpuSpeed = GetCpuSpeed();
243
244 Error = RegSetValue(CpuInstKey,
245 "~MHz",
246 REG_DWORD,
247 (PCHAR)&CpuSpeed,
248 sizeof(ULONG));
249 if (Error != ERROR_SUCCESS)
250 {
251 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
252 }
253 }
254 }
255
256
257 static VOID
258 SetMpsProcessor(FRLDRHKEY CpuKey,
259 FRLDRHKEY FpuKey,
260 PMP_PROCESSOR_ENTRY CpuEntry)
261 {
262 char VendorIdentifier[13];
263 char Identifier[64];
264 char Buffer[8];
265 ULONG FeatureSet;
266 FRLDRHKEY CpuInstKey;
267 FRLDRHKEY FpuInstKey;
268 ULONG eax = 0;
269 ULONG ebx = 0;
270 ULONG ecx = 0;
271 ULONG edx = 0;
272 ULONG *Ptr;
273 LONG Error;
274 ULONG CpuSpeed;
275
276 /* Get processor instance number */
277 sprintf(Buffer, "%u", CpuEntry->LocalApicId);
278
279 /* Create the CPU instance key */
280 Error = RegCreateKey(CpuKey,
281 Buffer,
282 &CpuInstKey);
283 if (Error != ERROR_SUCCESS)
284 {
285 DbgPrint((DPRINT_HWDETECT, "RegCreateKey() failed (Error %u)\n", (int)Error));
286 return;
287 }
288
289 /* Create the FPU instance key */
290 Error = RegCreateKey(FpuKey,
291 Buffer,
292 &FpuInstKey);
293 if (Error != ERROR_SUCCESS)
294 {
295 DbgPrint((DPRINT_HWDETECT, "RegCreateKey() failed (Error %u)\n", (int)Error));
296 return;
297 }
298
299 /* Get 'VendorIdentifier' */
300 GetCpuid(0, &eax, &ebx, &ecx, &edx);
301 VendorIdentifier[12] = 0;
302 Ptr = (ULONG*)&VendorIdentifier[0];
303 *Ptr = ebx;
304 Ptr++;
305 *Ptr = edx;
306 Ptr++;
307 *Ptr = ecx;
308
309 /* Get 'Identifier' */
310 sprintf(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));
315
316 /* Get FeatureSet */
317 FeatureSet = CpuEntry->FeatureFlags;
318
319 /* Set 'Configuration Data' value (CPU and FPU) */
320 SetComponentInformation(CpuInstKey,
321 0,
322 CpuEntry->LocalApicId,
323 1 << CpuEntry->LocalApicId);
324
325 SetComponentInformation(FpuInstKey,
326 0,
327 CpuEntry->LocalApicId,
328 1 << CpuEntry->LocalApicId);
329
330 /* Set 'FeatureSet' value (CPU only) */
331 DbgPrint((DPRINT_HWDETECT, "FeatureSet: %x\n", FeatureSet));
332
333 Error = RegSetValue(CpuInstKey,
334 "FeatureSet",
335 REG_DWORD,
336 (PCHAR)&FeatureSet,
337 sizeof(ULONG));
338 if (Error != ERROR_SUCCESS)
339 {
340 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
341 }
342
343 /* Set 'Identifier' value (CPU and FPU) */
344 DbgPrint((DPRINT_HWDETECT, "Identifier: %s\n", Identifier));
345
346 Error = RegSetValue(CpuInstKey,
347 "Identifier",
348 REG_SZ,
349 Identifier,
350 strlen(Identifier) + 1);
351 if (Error != ERROR_SUCCESS)
352 {
353 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
354 }
355
356 Error = RegSetValue(FpuInstKey,
357 "Identifier",
358 REG_SZ,
359 Identifier,
360 strlen(Identifier) + 1);
361 if (Error != ERROR_SUCCESS)
362 {
363 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
364 }
365
366 /* Set 'VendorIdentifier' value (CPU only) */
367 DbgPrint((DPRINT_HWDETECT, "Vendor Identifier: %s\n", VendorIdentifier));
368
369 Error = RegSetValue(CpuInstKey,
370 "VendorIdentifier",
371 REG_SZ,
372 VendorIdentifier,
373 strlen(VendorIdentifier) + 1);
374 if (Error != ERROR_SUCCESS)
375 {
376 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
377 }
378
379 /* FIXME: Set 'Update Signature' value (CPU only) */
380
381 /* FIXME: Set 'Update Status' value (CPU only) */
382
383 /* Set '~MHz' value (CPU only) */
384 if (((CpuEntry->CpuSignature >> 8) & 0x0F) >= 5)
385 {
386 CpuSpeed = GetCpuSpeed();
387
388 Error = RegSetValue(CpuInstKey,
389 "~MHz",
390 REG_DWORD,
391 (PCHAR)&CpuSpeed,
392 sizeof(ULONG));
393 if (Error != ERROR_SUCCESS)
394 {
395 DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error));
396 }
397 }
398 }
399
400
401 static PMP_FLOATING_POINT_TABLE
402 GetMpFloatingPointTable(VOID)
403 {
404 PMP_FLOATING_POINT_TABLE FpTable;
405 char *Ptr;
406 UCHAR Sum;
407 ULONG Length;
408 ULONG i;
409
410 FpTable = (PMP_FLOATING_POINT_TABLE)0xF0000;
411 while ((ULONG)FpTable < 0x100000)
412 {
413 if (FpTable->Signature == MP_FP_SIGNATURE)
414 {
415 Length = FpTable->Length * 0x10;
416 Ptr = (char *)FpTable;
417 Sum = 0;
418 for (i = 0; i < Length; i++)
419 {
420 Sum += Ptr[i];
421 }
422 DbgPrint((DPRINT_HWDETECT,
423 "Checksum: %u\n",
424 Sum));
425
426 if (Sum != 0)
427 {
428 DbgPrint((DPRINT_HWDETECT,
429 "Invalid MP floating point checksum: %u\n",
430 Sum));
431 return NULL;
432 }
433
434 return FpTable;
435 }
436
437 FpTable = (PMP_FLOATING_POINT_TABLE)((ULONG)FpTable + 0x10);
438 }
439
440 return NULL;
441 }
442
443
444 static PMP_CONFIGURATION_TABLE
445 GetMpConfigurationTable(PMP_FLOATING_POINT_TABLE FpTable)
446 {
447 PMP_CONFIGURATION_TABLE ConfigTable;
448 char *Ptr;
449 UCHAR Sum;
450 ULONG Length;
451 ULONG i;
452
453 if (FpTable->FeatureByte[0] != 0 ||
454 FpTable->PhysicalAddressPointer == 0)
455 return NULL;
456
457 ConfigTable = (PMP_CONFIGURATION_TABLE)FpTable->PhysicalAddressPointer;
458 if (ConfigTable->Signature != MP_CT_SIGNATURE)
459 return NULL;
460
461 DbgPrint((DPRINT_HWDETECT,
462 "MP Configuration Table at: %x\n",
463 (ULONG)ConfigTable));
464
465 /* Calculate base table checksum */
466 Length = ConfigTable->BaseTableLength;
467 Ptr = (char *)ConfigTable;
468 Sum = 0;
469 for (i = 0; i < Length; i++)
470 {
471 Sum += Ptr[i];
472 }
473 DbgPrint((DPRINT_HWDETECT,
474 "MP Configuration Table base checksum: %u\n",
475 Sum));
476
477 if (Sum != 0)
478 {
479 DbgPrint((DPRINT_HWDETECT,
480 "Invalid MP Configuration Table base checksum: %u\n",
481 Sum));
482 return NULL;
483 }
484
485 if (ConfigTable->ExtendedTableLength != 0)
486 {
487 /* FIXME: Check extended table */
488 }
489
490 return ConfigTable;
491 }
492
493
494 static BOOL
495 DetectMps(FRLDRHKEY CpuKey,
496 FRLDRHKEY FpuKey)
497 {
498 PMP_FLOATING_POINT_TABLE FpTable;
499 PMP_CONFIGURATION_TABLE ConfigTable;
500 PMP_PROCESSOR_ENTRY CpuEntry;
501 char *Ptr;
502 ULONG Offset;
503
504 /* Get floating point table */
505 FpTable = GetMpFloatingPointTable();
506 if (FpTable == NULL)
507 return FALSE;
508
509 DbgPrint((DPRINT_HWDETECT,
510 "MP Floating Point Table at: %x\n",
511 (ULONG)FpTable));
512
513 if (FpTable->FeatureByte[0] == 0)
514 {
515 /* Get configuration table */
516 ConfigTable = GetMpConfigurationTable(FpTable);
517 if (ConfigTable == NULL)
518 {
519 DbgPrint((DPRINT_HWDETECT,
520 "Failed to find the MP Configuration Table\n"));
521 return FALSE;
522 }
523
524 Offset = sizeof(MP_CONFIGURATION_TABLE);
525 while (Offset < ConfigTable->BaseTableLength)
526 {
527 Ptr = (char*)((ULONG)ConfigTable + Offset);
528
529 switch (*Ptr)
530 {
531 case 0:
532 CpuEntry = (PMP_PROCESSOR_ENTRY)Ptr;
533
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,
539 CpuEntry->CpuFlags,
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)));
548
549 SetMpsProcessor(CpuKey, FpuKey, CpuEntry);
550 Offset += 0x14;
551 break;
552
553 case 1:
554 DbgPrint((DPRINT_HWDETECT, "Bus Entry\n"));
555 Offset += 0x08;
556 break;
557
558 case 2:
559 DbgPrint((DPRINT_HWDETECT, "I/0 APIC Entry\n"));
560 Offset += 0x08;
561 break;
562
563 case 3:
564 DbgPrint((DPRINT_HWDETECT, "I/0 Interrupt Assignment Entry\n"));
565 Offset += 0x08;
566 break;
567
568 case 4:
569 DbgPrint((DPRINT_HWDETECT, "Local Interrupt Assignment Entry\n"));
570 Offset += 0x08;
571 break;
572
573 default:
574 DbgPrint((DPRINT_HWDETECT, "Unknown Entry %u\n",(ULONG)*Ptr));
575 return FALSE;
576 }
577 }
578 }
579 else
580 {
581 DbgPrint((DPRINT_HWDETECT,
582 "Unsupported MPS configuration: %x\n",
583 FpTable->FeatureByte[0]));
584
585 /* FIXME: Identify default configurations */
586
587 return FALSE;
588 }
589
590 return TRUE;
591 }
592
593
594
595 VOID
596 DetectCPUs(FRLDRHKEY SystemKey)
597 {
598 FRLDRHKEY CpuKey;
599 FRLDRHKEY FpuKey;
600 LONG Error;
601
602 /* Create the 'CentralProcessor' key */
603 Error = RegCreateKey(SystemKey,
604 "CentralProcessor",
605 &CpuKey);
606 if (Error != ERROR_SUCCESS)
607 {
608 DbgPrint((DPRINT_HWDETECT, "RegCreateKey() failed (Error %u)\n", (int)Error));
609 return;
610 }
611
612 /* Create the 'FloatingPointProcessor' key */
613 Error = RegCreateKey(SystemKey,
614 "FloatingPointProcessor",
615 &FpuKey);
616 if (Error != ERROR_SUCCESS)
617 {
618 DbgPrint((DPRINT_HWDETECT, "RegCreateKey() failed (Error %u)\n", (int)Error));
619 return;
620 }
621
622 /* Detect CPUs */
623 if (!DetectMps(CpuKey, FpuKey))
624 {
625 DetectCPU(CpuKey, FpuKey);
626 }
627 }
628
629 /* EOF */