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