a19e58c2598b0343a68e3338081e200f15cf92d2
[reactos.git] / ntoskrnl / config / i386 / cmhardwr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/i386/cmhardwr.c
5 * PURPOSE: Configuration Manager - Hardware-Specific Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 /* GLOBALS *******************************************************************/
16
17 PCHAR CmpID1 = "80%u86-%c%x";
18 PCHAR CmpID2 = "x86 Family %u Model %u Stepping %u";
19 PCHAR CmpBiosStrings[] =
20 {
21 "Ver",
22 "Rev",
23 "Rel",
24 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
25 "v 0", "v 1", "v 2", "v 3", "v 4", "v 5", "v 6", "v 7", "v 8", "v 9",
26 NULL
27 };
28
29 PCHAR CmpBiosBegin, CmpBiosSearchStart, CmpBiosSearchEnd;
30
31 /* FUNCTIONS *****************************************************************/
32
33 BOOLEAN
34 NTAPI
35 CmpGetBiosDate(IN PCHAR BiosStart,
36 IN ULONG BiosLength,
37 IN PCHAR BiosDate,
38 IN BOOLEAN FromBios)
39 {
40 CHAR LastDate[11] = {0}, CurrentDate[11];
41 PCHAR p, pp;
42
43 /* Skip the signature and the magic, and loop the BIOS ROM */
44 p = BiosStart + 2;
45 pp = BiosStart + BiosLength - 5;
46 while (p < pp)
47 {
48 /* Check for xx/yy/zz which we assume to be a date */
49 if ((p[0] == '/') &&
50 (p[3] == '/') &&
51 (isdigit(p[-1])) &&
52 (isdigit(p[1])) &&
53 (isdigit(p[2])) &&
54 (isdigit(p[4])) &&
55 (isdigit(p[5])))
56 {
57 /* Copy the string proper */
58 RtlMoveMemory(&CurrentDate[5], p - 2, 5);
59
60 /* Add a 0 if the month only has one digit */
61 if (!isdigit(CurrentDate[5])) CurrentDate[5] = '0';
62
63 /* Now copy the year */
64 CurrentDate[2] = p[4];
65 CurrentDate[3] = p[5];
66 CurrentDate[4] = CurrentDate[7] = CurrentDate[10] = ANSI_NULL;
67
68 /* If the date comes from the BIOS, check if it's a 4-digit year */
69 if ((FromBios) &&
70 (isdigit(p[6])) &&
71 (isdigit(p[7])) &&
72 ((RtlEqualMemory(&p[4], "19", 2)) ||
73 (RtlEqualMemory(&p[4], "20", 2))))
74 {
75 /* Copy the year proper */
76 CurrentDate[0] = p[4];
77 CurrentDate[1] = p[5];
78 CurrentDate[2] = p[6];
79 CurrentDate[3] = p[7];
80 }
81 else
82 {
83 /* Otherwise, we'll just assume anything under 80 is 2000 */
84 if (strtoul(&CurrentDate[2], NULL, 10) < 80)
85 {
86 /* Hopefully your BIOS wasn't made in 1979 */
87 CurrentDate[0] = '2';
88 CurrentDate[1] = '0';
89 }
90 else
91 {
92 /* Anything over 80, was probably made in the 1900s... */
93 CurrentDate[0] = '1';
94 CurrentDate[1] = '9';
95 }
96 }
97
98 /* Add slashes where we previously had NULLs */
99 CurrentDate[4] = CurrentDate[7] = '/';
100
101 /* Check which date is newer */
102 if (memcmp(LastDate, CurrentDate, 10) < 0)
103 {
104 /* Found a newer date, select it */
105 RtlMoveMemory(LastDate, CurrentDate, 10);
106 }
107
108 p += 2;
109 }
110 p++;
111 }
112
113 /* Make sure we found a date */
114 if (LastDate[0])
115 {
116 /* Copy the year at the pp, and keep only the last two digits */
117 RtlMoveMemory(BiosDate, &LastDate[5], 5);
118 BiosDate[5] = '/';
119 BiosDate[6] = LastDate[2];
120 BiosDate[7] = LastDate[3];
121 BiosDate[8] = ANSI_NULL;
122 return TRUE;
123 }
124
125 /* No date found, return empty string */
126 BiosDate[0] = ANSI_NULL;
127 return FALSE;
128 }
129
130 BOOLEAN
131 NTAPI
132 CmpGetBiosVersion(IN PCHAR BiosStart,
133 IN ULONG BiosLength,
134 IN PCHAR BiosVersion)
135 {
136 CHAR Buffer[128];
137 PCHAR p, pp;
138 USHORT i;
139
140 /* Check if we were given intitial data for the search */
141 if (BiosStart)
142 {
143 /* Save it for later use */
144 CmpBiosBegin = BiosStart;
145 CmpBiosSearchStart = BiosStart + 1;
146 CmpBiosSearchEnd = BiosStart + BiosLength - 2;
147 }
148
149 /* Now loop the BIOS area */
150 for (;;)
151 {
152 /* Start an initial search looking for numbers and periods */
153 pp = NULL;
154 while (CmpBiosSearchStart <= CmpBiosSearchEnd)
155 {
156 /* Check if we have an "x.y" version string */
157 if ((*CmpBiosSearchStart == '.') &&
158 (*(CmpBiosSearchStart + 1) >= '0') &&
159 (*(CmpBiosSearchStart + 1) <= '9') &&
160 (*(CmpBiosSearchStart - 1) >= '0') &&
161 (*(CmpBiosSearchStart - 1) <= '9'))
162 {
163 /* Start looking in this area for the actual BIOS Version */
164 pp = CmpBiosSearchStart;
165 break;
166 }
167 else
168 {
169 /* Keep searching */
170 CmpBiosSearchStart++;
171 }
172 }
173
174 /* Break out if we're went past the BIOS area */
175 if (CmpBiosSearchStart > CmpBiosSearchEnd) return FALSE;
176
177 /* Move to the next 2 bytes */
178 CmpBiosSearchStart += 2;
179
180 /* Null-terminate our scratch buffer and start the string here */
181 Buffer[127] = ANSI_NULL;
182 p = &Buffer[127];
183
184 /* Go back one character since we're doing this backwards */
185 pp--;
186
187 /* Loop the identifier we found as long as it's valid */
188 i = 0;
189 while ((i++ < 127) &&
190 (pp >= CmpBiosBegin) &&
191 (*pp >= ' ') &&
192 (*pp != '$'))
193 {
194 /* Copy the character */
195 *--p = *pp--;
196 }
197
198 /* Go past the last character since we went backwards */
199 pp++;
200
201 /* Loop the strings we recognize */
202 for (i = 0; CmpBiosStrings[i]; i++)
203 {
204 /* Check if a match was found */
205 if (strstr(p, CmpBiosStrings[i])) goto Match;
206 }
207 }
208
209 Match:
210 /* Skip until we find a space */
211 for (; *pp == ' '; pp++);
212
213 /* Loop the final string */
214 i = 0;
215 do
216 {
217 /* Copy the character into the final string */
218 BiosVersion[i] = *pp++;
219 } while ((++i < 127) &&
220 (pp <= (CmpBiosSearchEnd + 1)) &&
221 (*pp >= ' ') &&
222 (*pp != '$'));
223
224 /* Null-terminate the version string */
225 BiosVersion[i] = ANSI_NULL;
226 return TRUE;
227 }
228
229 VOID
230 NTAPI
231 CmpGetIntelBrandString(OUT PCHAR CpuString)
232 {
233 CPU_INFO CpuInfo;
234 ULONG BrandId, Signature;
235
236 /* Get the Brand Id */
237 KiCpuId(&CpuInfo, 0x00000001);
238 Signature = CpuInfo.Eax;
239 BrandId = CpuInfo.Ebx & 0xFF;
240
241 switch (BrandId)
242 {
243 case 0x01:
244 strcpy(CpuString, "Intel(R) Celeron(R) processor");
245 break;
246 case 0x02:
247 case 0x04:
248 strcpy(CpuString, "Intel(R) Pentium(R) III processor");
249 break;
250 case 0x03:
251 if(Signature == 0x000006B1)
252 strcpy(CpuString, "Intel(R) Celeron(R) processor");
253 else
254 strcpy(CpuString, "Intel(R) Pentium(R) III Xeon(R) processor");
255 break;
256 case 0x06:
257 strcpy(CpuString, "Mobile Intel(R) Pentium(R) III Processor-M");
258 break;
259 case 0x08:
260 if(Signature >= 0x00000F13)
261 strcpy(CpuString, "Intel(R) Genuine Processor");
262 else
263 strcpy(CpuString, "Intel(R) Pentium(R) 4 processor");
264 break;
265 case 0x09:
266 strcpy(CpuString, "Intel(R) Pentium(R) 4 processor");
267 break;
268 case 0x0B:
269 if(Signature >= 0x00000F13)
270 strcpy(CpuString, "Intel(R) Xeon(R) processor");
271 else
272 strcpy(CpuString, "Intel(R) Xeon(R) processor MP");
273 break;
274 case 0x0C:
275 strcpy(CpuString, "Intel(R) Xeon(R) processor MP");
276 break;
277 case 0x0E:
278 if(Signature >= 0x00000F13)
279 strcpy(CpuString, "Mobile Intel(R) Pentium(R) 4 processor-M");
280 else
281 strcpy(CpuString, "Intel(R) Xeon(R) processor");
282 break;
283 case 0x12:
284 strcpy(CpuString, "Intel(R) Celeron(R) M processor");
285 break;
286 case 0x07:
287 case 0x0F:
288 case 0x13:
289 case 0x17:
290 strcpy(CpuString, "Mobile Intel(R) Celeron(R) processor");
291 break;
292 case 0x0A:
293 case 0x14:
294 strcpy(CpuString, "Intel(R) Celeron(R) Processor");
295 break;
296 case 0x15:
297 strcpy(CpuString, "Mobile Genuine Intel(R) Processor");
298 break;
299 case 0x16:
300 strcpy(CpuString, "Intel(R) Pentium(R) M processor");
301 break;
302 default:
303 strcpy(CpuString, "Unknown Intel processor");
304 }
305 }
306
307 VOID
308 NTAPI
309 CmpGetVendorString(IN PKPRCB Prcb, OUT PCHAR CpuString)
310 {
311 /* Check if we have a Vendor String */
312 if (Prcb->VendorString[0])
313 {
314 strcpy(CpuString, Prcb->VendorString);
315 }
316 else
317 {
318 strcpy(CpuString, "Unknown x86 processor");
319 }
320 }
321
322 NTSTATUS
323 NTAPI
324 CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
325 {
326 UNICODE_STRING KeyName, ValueName, Data, SectionName;
327 OBJECT_ATTRIBUTES ObjectAttributes;
328 ULONG HavePae, Length, TotalLength = 0, i, Disposition;
329 SIZE_T ViewSize;
330 NTSTATUS Status;
331 HANDLE KeyHandle, BiosHandle, SystemHandle, FpuHandle, SectionHandle;
332 CONFIGURATION_COMPONENT_DATA ConfigData;
333 CHAR Buffer[128];
334 CPU_INFO CpuInfo;
335 ULONG VendorId, ExtendedId;
336 PKPRCB Prcb;
337 USHORT IndexTable[MaximumType + 1] = {0};
338 ANSI_STRING TempString;
339 PCHAR PartialString = NULL, BiosVersion;
340 CHAR CpuString[48];
341 PVOID BaseAddress = NULL;
342 LARGE_INTEGER ViewBase = {{0, 0}};
343 ULONG_PTR VideoRomBase;
344 PCHAR CurrentVersion;
345 extern UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion;
346 extern UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
347
348 /* Open the SMSS Memory Management key */
349 RtlInitUnicodeString(&KeyName,
350 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\"
351 L"Control\\Session Manager\\Memory Management");
352 InitializeObjectAttributes(&ObjectAttributes,
353 &KeyName,
354 OBJ_CASE_INSENSITIVE,
355 NULL,
356 NULL);
357 Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &ObjectAttributes);
358 if (NT_SUCCESS(Status))
359 {
360 /* Detect if PAE is enabled */
361 HavePae = SharedUserData->ProcessorFeatures[PF_PAE_ENABLED];
362
363 /* Set the value */
364 RtlInitUnicodeString(&ValueName, L"PhysicalAddressExtension");
365 NtSetValueKey(KeyHandle,
366 &ValueName,
367 0,
368 REG_DWORD,
369 &HavePae,
370 sizeof(HavePae));
371
372 /* Close the key */
373 NtClose(KeyHandle);
374 }
375
376 /* Open the hardware description key */
377 RtlInitUnicodeString(&KeyName,
378 L"\\Registry\\Machine\\Hardware\\Description\\System");
379 InitializeObjectAttributes(&ObjectAttributes,
380 &KeyName,
381 OBJ_CASE_INSENSITIVE,
382 NULL,
383 NULL);
384 Status = NtOpenKey(&SystemHandle, KEY_READ | KEY_WRITE, &ObjectAttributes);
385 if (!NT_SUCCESS(Status))
386 return Status;
387
388 /* Create the BIOS Information key */
389 RtlInitUnicodeString(&KeyName,
390 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\"
391 L"Control\\BIOSINFO");
392 InitializeObjectAttributes(&ObjectAttributes,
393 &KeyName,
394 OBJ_CASE_INSENSITIVE,
395 NULL,
396 NULL);
397 Status = NtCreateKey(&BiosHandle,
398 KEY_ALL_ACCESS,
399 &ObjectAttributes,
400 0,
401 NULL,
402 REG_OPTION_NON_VOLATILE,
403 &Disposition);
404 if (ExpInTextModeSetup)
405 {
406 if (!NT_SUCCESS(Status))
407 BiosHandle = NULL;
408 }
409 else if (!NT_SUCCESS(Status))
410 {
411 NtClose(SystemHandle);
412 return Status;
413 }
414
415 /* Create the CPU Key, and check if it already existed */
416 RtlInitUnicodeString(&KeyName, L"CentralProcessor");
417 InitializeObjectAttributes(&ObjectAttributes,
418 &KeyName,
419 OBJ_CASE_INSENSITIVE,
420 SystemHandle,
421 NULL);
422 Status = NtCreateKey(&KeyHandle,
423 KEY_READ | KEY_WRITE,
424 &ObjectAttributes,
425 0,
426 NULL,
427 0,
428 &Disposition);
429 NtClose(KeyHandle);
430
431 /* The key shouldn't already exist */
432 if (Disposition == REG_CREATED_NEW_KEY)
433 {
434 /* Allocate the configuration data for cmconfig.c */
435 CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
436 CmpConfigurationAreaSize,
437 TAG_CM);
438 if (!CmpConfigurationData)
439 {
440 // FIXME: Cleanup stuff!!
441 return STATUS_INSUFFICIENT_RESOURCES;
442 }
443
444 /* Loop all CPUs */
445 for (i = 0; i < KeNumberProcessors; i++)
446 {
447 /* Get the PRCB */
448 Prcb = KiProcessorBlock[i];
449
450 /* Setup the Configuration Entry for the Processor */
451 RtlZeroMemory(&ConfigData, sizeof(ConfigData));
452 ConfigData.ComponentEntry.Class = ProcessorClass;
453 ConfigData.ComponentEntry.Type = CentralProcessor;
454 ConfigData.ComponentEntry.Key = i;
455 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
456 ConfigData.ComponentEntry.Identifier = Buffer;
457
458 /* Check if the CPU doesn't support CPUID */
459 if (!Prcb->CpuID)
460 {
461 /* Build ID1-style string for older CPUs */
462 sprintf(Buffer,
463 CmpID1,
464 Prcb->CpuType,
465 (Prcb->CpuStep >> 8) + 'A',
466 Prcb->CpuStep & 0xff);
467 }
468 else
469 {
470 /* Build ID2-style string for newer CPUs */
471 sprintf(Buffer,
472 CmpID2,
473 Prcb->CpuType,
474 (Prcb->CpuStep >> 8),
475 Prcb->CpuStep & 0xff);
476 }
477
478 /* Save the ID string length now that we've created it */
479 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1;
480
481 /* Initialize the registry configuration node for it */
482 Status = CmpInitializeRegistryNode(&ConfigData,
483 SystemHandle,
484 &KeyHandle,
485 InterfaceTypeUndefined,
486 0xFFFFFFFF,
487 IndexTable);
488 if (!NT_SUCCESS(Status))
489 {
490 NtClose(BiosHandle);
491 NtClose(SystemHandle);
492 return Status;
493 }
494
495 /* Check if we have an FPU */
496 if (KeI386NpxPresent)
497 {
498 /* Setup the Configuration Entry for the FPU */
499 RtlZeroMemory(&ConfigData, sizeof(ConfigData));
500 ConfigData.ComponentEntry.Class = ProcessorClass;
501 ConfigData.ComponentEntry.Type = FloatingPointProcessor;
502 ConfigData.ComponentEntry.Key = i;
503 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
504 ConfigData.ComponentEntry.Identifier = Buffer;
505
506 /* For 386 cpus, the CPU pp is the identifier */
507 if (Prcb->CpuType == 3) strcpy(Buffer, "80387");
508
509 /* Save the ID string length now that we've created it */
510 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1;
511
512 /* Initialize the registry configuration node for it */
513 Status = CmpInitializeRegistryNode(&ConfigData,
514 SystemHandle,
515 &FpuHandle,
516 InterfaceTypeUndefined,
517 0xFFFFFFFF,
518 IndexTable);
519 if (!NT_SUCCESS(Status))
520 {
521 /* We failed, close all the opened handles and return */
522 NtClose(KeyHandle);
523 NtClose(BiosHandle);
524 NtClose(SystemHandle);
525 return Status;
526 }
527
528 /* Close this new handle */
529 NtClose(FpuHandle);
530
531 /* Stay on this CPU only */
532 KeSetSystemAffinityThread(Prcb->SetMember);
533 if (!Prcb->CpuID)
534 {
535 /* Uh oh, no CPUID! */
536 PartialString = CpuString;
537 CmpGetVendorString(Prcb, PartialString);
538 }
539 else
540 {
541 /* Check if we have extended CPUID that supports name ID */
542 KiCpuId(&CpuInfo, 0x80000000);
543 ExtendedId = CpuInfo.Eax;
544 if (ExtendedId >= 0x80000004)
545 {
546 /* Do all the CPUIDs required to get the full name */
547 PartialString = CpuString;
548 for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++)
549 {
550 /* Do the CPUID and save the name string */
551 KiCpuId(&CpuInfo, 0x80000000 | ExtendedId);
552 ((PULONG)PartialString)[0] = CpuInfo.Eax;
553 ((PULONG)PartialString)[1] = CpuInfo.Ebx;
554 ((PULONG)PartialString)[2] = CpuInfo.Ecx;
555 ((PULONG)PartialString)[3] = CpuInfo.Edx;
556
557 /* Go to the next name string */
558 PartialString += 16;
559 }
560
561 /* Null-terminate it */
562 CpuString[47] = ANSI_NULL;
563 }
564 else
565 {
566 KiCpuId(&CpuInfo, 0x00000000);
567 VendorId = CpuInfo.Ebx;
568 PartialString = CpuString;
569 switch (VendorId)
570 {
571 case 'uneG': /* Intel */
572 CmpGetIntelBrandString(PartialString);
573 break;
574 case 'htuA': /* AMD */
575 /* FIXME */
576 CmpGetVendorString(Prcb, PartialString);
577 break;
578 default:
579 CmpGetVendorString(Prcb, PartialString);
580 }
581 }
582 }
583
584 /* Go back to user affinity */
585 KeRevertToUserAffinityThread();
586
587 /* Check if we have a CPU Name */
588 if (PartialString)
589 {
590 /* Convert it to Unicode */
591 RtlInitAnsiString(&TempString, CpuString);
592 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
593
594 /* Add it to the registry */
595 RtlInitUnicodeString(&ValueName, L"ProcessorNameString");
596 Status = NtSetValueKey(KeyHandle,
597 &ValueName,
598 0,
599 REG_SZ,
600 Data.Buffer,
601 Data.Length + sizeof(UNICODE_NULL));
602
603 /* ROS: Save a copy for bugzilla reporting */
604 RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer);
605
606 /* Free the temporary buffer */
607 RtlFreeUnicodeString(&Data);
608 }
609
610 /* Check if we had a Vendor ID */
611 if (Prcb->VendorString[0])
612 {
613 /* Convert it to Unicode */
614 RtlInitAnsiString(&TempString, Prcb->VendorString);
615 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
616
617 /* Add it to the registry */
618 RtlInitUnicodeString(&ValueName, L"VendorIdentifier");
619 Status = NtSetValueKey(KeyHandle,
620 &ValueName,
621 0,
622 REG_SZ,
623 Data.Buffer,
624 Data.Length + sizeof(UNICODE_NULL));
625
626 /* Free the temporary buffer */
627 RtlFreeUnicodeString(&Data);
628 }
629
630 /* Check if we have features bits */
631 if (Prcb->FeatureBits)
632 {
633 /* Add them to the registry */
634 RtlInitUnicodeString(&ValueName, L"FeatureSet");
635 Status = NtSetValueKey(KeyHandle,
636 &ValueName,
637 0,
638 REG_DWORD,
639 &Prcb->FeatureBits,
640 sizeof(Prcb->FeatureBits));
641 }
642
643 /* Check if we detected the CPU Speed */
644 if (Prcb->MHz)
645 {
646 /* Add it to the registry */
647 RtlInitUnicodeString(&ValueName, L"~MHz");
648 Status = NtSetValueKey(KeyHandle,
649 &ValueName,
650 0,
651 REG_DWORD,
652 &Prcb->MHz,
653 sizeof(Prcb->MHz));
654 }
655
656 /* Check if we have an update signature */
657 if (Prcb->UpdateSignature.QuadPart)
658 {
659 /* Add it to the registry */
660 RtlInitUnicodeString(&ValueName, L"Update Signature");
661 Status = NtSetValueKey(KeyHandle,
662 &ValueName,
663 0,
664 REG_BINARY,
665 &Prcb->UpdateSignature,
666 sizeof(Prcb->UpdateSignature));
667 }
668
669 /* Close the processor handle */
670 NtClose(KeyHandle);
671
672 /* FIXME: Detect CPU mismatches */
673 }
674 }
675
676 /* Free the configuration data */
677 ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
678 }
679
680 /* Open physical memory */
681 RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory");
682 InitializeObjectAttributes(&ObjectAttributes,
683 &SectionName,
684 OBJ_CASE_INSENSITIVE,
685 NULL,
686 NULL);
687 Status = ZwOpenSection(&SectionHandle,
688 SECTION_ALL_ACCESS,
689 &ObjectAttributes);
690 if (!NT_SUCCESS(Status))
691 {
692 /* We failed, close all the opened handles and return */
693 // NtClose(KeyHandle);
694 NtClose(BiosHandle);
695 NtClose(SystemHandle);
696 /* 'Quickie' closes KeyHandle */
697 goto Quickie;
698 }
699
700 /* Map the first 1KB of memory to get the IVT */
701 ViewSize = PAGE_SIZE;
702 Status = ZwMapViewOfSection(SectionHandle,
703 NtCurrentProcess(),
704 &BaseAddress,
705 0,
706 ViewSize,
707 &ViewBase,
708 &ViewSize,
709 ViewUnmap,
710 MEM_DOS_LIM,
711 PAGE_READWRITE);
712 if (!NT_SUCCESS(Status))
713 {
714 /* Assume default */
715 VideoRomBase = 0xC0000;
716 }
717 else
718 {
719 /* Calculate the base address from the vector */
720 VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0;
721 VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0;
722
723 /* Now get to the actual ROM Start and make sure it's not invalid*/
724 VideoRomBase &= 0xFFFF8000;
725 if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000;
726
727 /* And unmap the section */
728 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
729 }
730
731 /* Allocate BIOS Version pp Buffer */
732 BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM);
733
734 /* Setup settings to map the 64K BIOS ROM */
735 BaseAddress = 0;
736 ViewSize = 16 * PAGE_SIZE;
737 ViewBase.LowPart = 0xF0000;
738 ViewBase.HighPart = 0;
739
740 /* Map it */
741 Status = ZwMapViewOfSection(SectionHandle,
742 NtCurrentProcess(),
743 &BaseAddress,
744 0,
745 ViewSize,
746 &ViewBase,
747 &ViewSize,
748 ViewUnmap,
749 MEM_DOS_LIM,
750 PAGE_READWRITE);
751 if (NT_SUCCESS(Status))
752 {
753 /* Scan the ROM to get the BIOS Date */
754 if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE))
755 {
756 /* Convert it to Unicode */
757 RtlInitAnsiString(&TempString, Buffer);
758 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
759
760 /* Write the date into the registry */
761 RtlInitUnicodeString(&ValueName, L"SystemBiosDate");
762 Status = NtSetValueKey(SystemHandle,
763 &ValueName,
764 0,
765 REG_SZ,
766 Data.Buffer,
767 Data.Length + sizeof(UNICODE_NULL));
768
769 /* Free the string */
770 RtlFreeUnicodeString(&Data);
771
772 if (BiosHandle)
773 {
774 /* Get the BIOS Date Identifier */
775 RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16 * PAGE_SIZE - 11), 8);
776 Buffer[8] = ANSI_NULL;
777
778 /* Convert it to unicode */
779 RtlInitAnsiString(&TempString, Buffer);
780 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
781 if (NT_SUCCESS(Status))
782 {
783 /* Save it to the registry */
784 Status = NtSetValueKey(BiosHandle,
785 &ValueName,
786 0,
787 REG_SZ,
788 Data.Buffer,
789 Data.Length + sizeof(UNICODE_NULL));
790
791 /* ROS: Save a copy for bugzilla reporting */
792 RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer);
793
794 /* Free the string */
795 RtlFreeUnicodeString(&Data);
796 }
797
798 /* Close the bios information handle */
799 NtClose(BiosHandle);
800 }
801 }
802
803 /* Get the BIOS Version */
804 if (CmpGetBiosVersion(BaseAddress, 16 * PAGE_SIZE, Buffer))
805 {
806 /* Start at the beginning of our buffer */
807 CurrentVersion = BiosVersion;
808 do
809 {
810 /* Convert to Unicode */
811 RtlInitAnsiString(&TempString, Buffer);
812 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
813
814 /* Calculate the length of this string and copy it in */
815 Length = Data.Length + sizeof(UNICODE_NULL);
816 RtlMoveMemory(CurrentVersion, Data.Buffer, Length);
817
818 /* Free the unicode string */
819 RtlFreeUnicodeString(&Data);
820
821 /* Update the total length and see if we're out of space */
822 TotalLength += Length;
823 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE)
824 {
825 /* One more string would push us out, so stop here */
826 break;
827 }
828
829 /* Go to the next string inside the multi-string buffer */
830 CurrentVersion += Length;
831
832 /* Query the next BIOS Version */
833 } while (CmpGetBiosVersion(NULL, 0, Buffer));
834
835 /* Check if we found any strings at all */
836 if (TotalLength)
837 {
838 /* Add the final null-terminator */
839 *(PWSTR)CurrentVersion = UNICODE_NULL;
840 TotalLength += sizeof(UNICODE_NULL);
841
842 /* Write the BIOS Version to the registry */
843 RtlInitUnicodeString(&ValueName, L"SystemBiosVersion");
844 Status = NtSetValueKey(SystemHandle,
845 &ValueName,
846 0,
847 REG_MULTI_SZ,
848 BiosVersion,
849 TotalLength);
850
851 /* ROS: Save a copy for bugzilla reporting */
852 RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion);
853 }
854 }
855
856 /* Unmap the section */
857 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
858 }
859
860 /* Now prepare for Video BIOS Mapping of 32KB */
861 BaseAddress = 0;
862 ViewSize = 8 * PAGE_SIZE;
863 ViewBase.QuadPart = VideoRomBase;
864
865 /* Map it */
866 Status = ZwMapViewOfSection(SectionHandle,
867 NtCurrentProcess(),
868 &BaseAddress,
869 0,
870 ViewSize,
871 &ViewBase,
872 &ViewSize,
873 ViewUnmap,
874 MEM_DOS_LIM,
875 PAGE_READWRITE);
876 if (NT_SUCCESS(Status))
877 {
878 /* Scan the ROM to get the BIOS Date */
879 if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE))
880 {
881 /* Convert it to Unicode */
882 RtlInitAnsiString(&TempString, Buffer);
883 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
884
885 /* Write the date into the registry */
886 RtlInitUnicodeString(&ValueName, L"VideoBiosDate");
887 Status = NtSetValueKey(SystemHandle,
888 &ValueName,
889 0,
890 REG_SZ,
891 Data.Buffer,
892 Data.Length + sizeof(UNICODE_NULL));
893
894 /* ROS: Save a copy for bugzilla reporting */
895 RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer);
896
897 /* Free the string */
898 RtlFreeUnicodeString(&Data);
899 }
900
901 /* Get the Video BIOS Version */
902 if (CmpGetBiosVersion(BaseAddress, 8 * PAGE_SIZE, Buffer))
903 {
904 /* Start at the beginning of our buffer */
905 CurrentVersion = BiosVersion;
906 do
907 {
908 /* Convert to Unicode */
909 RtlInitAnsiString(&TempString, Buffer);
910 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
911
912 /* Calculate the length of this string and copy it in */
913 Length = Data.Length + sizeof(UNICODE_NULL);
914 RtlMoveMemory(CurrentVersion, Data.Buffer, Length);
915
916 /* Free the unicode string */
917 RtlFreeUnicodeString(&Data);
918
919 /* Update the total length and see if we're out of space */
920 TotalLength += Length;
921 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE)
922 {
923 /* One more string would push us out, so stop here */
924 break;
925 }
926
927 /* Go to the next string inside the multi-string buffer */
928 CurrentVersion += Length;
929
930 /* Query the next BIOS Version */
931 } while (CmpGetBiosVersion(NULL, 0, Buffer));
932
933 /* Check if we found any strings at all */
934 if (TotalLength)
935 {
936 /* Add the final null-terminator */
937 *(PWSTR)CurrentVersion = UNICODE_NULL;
938 TotalLength += sizeof(UNICODE_NULL);
939
940 /* Write the BIOS Version to the registry */
941 RtlInitUnicodeString(&ValueName, L"VideoBiosVersion");
942 Status = NtSetValueKey(SystemHandle,
943 &ValueName,
944 0,
945 REG_MULTI_SZ,
946 BiosVersion,
947 TotalLength);
948
949 /* ROS: Save a copy for bugzilla reporting */
950 RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion);
951 }
952 }
953
954 /* Unmap the section */
955 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
956 }
957
958 /* Close the section */
959 ZwClose(SectionHandle);
960
961 /* Free the BIOS version string buffer */
962 if (BiosVersion) ExFreePoolWithTag(BiosVersion, TAG_CM);
963
964 Quickie:
965 /* Close the processor handle */
966 NtClose(KeyHandle);
967 return STATUS_SUCCESS;
968 }