[NTOS] Remove some hacks that are not needed anymore, since a real registry hive...
[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 (!NT_SUCCESS(Status))
405 {
406 NtClose(SystemHandle);
407 return Status;
408 }
409
410 /* Create the CPU Key, and check if it already existed */
411 RtlInitUnicodeString(&KeyName, L"CentralProcessor");
412 InitializeObjectAttributes(&ObjectAttributes,
413 &KeyName,
414 OBJ_CASE_INSENSITIVE,
415 SystemHandle,
416 NULL);
417 Status = NtCreateKey(&KeyHandle,
418 KEY_READ | KEY_WRITE,
419 &ObjectAttributes,
420 0,
421 NULL,
422 0,
423 &Disposition);
424 NtClose(KeyHandle);
425
426 /* The key shouldn't already exist */
427 if (Disposition == REG_CREATED_NEW_KEY)
428 {
429 /* Allocate the configuration data for cmconfig.c */
430 CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
431 CmpConfigurationAreaSize,
432 TAG_CM);
433 if (!CmpConfigurationData)
434 {
435 // FIXME: Cleanup stuff!!
436 return STATUS_INSUFFICIENT_RESOURCES;
437 }
438
439 /* Loop all CPUs */
440 for (i = 0; i < KeNumberProcessors; i++)
441 {
442 /* Get the PRCB */
443 Prcb = KiProcessorBlock[i];
444
445 /* Setup the Configuration Entry for the Processor */
446 RtlZeroMemory(&ConfigData, sizeof(ConfigData));
447 ConfigData.ComponentEntry.Class = ProcessorClass;
448 ConfigData.ComponentEntry.Type = CentralProcessor;
449 ConfigData.ComponentEntry.Key = i;
450 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
451 ConfigData.ComponentEntry.Identifier = Buffer;
452
453 /* Check if the CPU doesn't support CPUID */
454 if (!Prcb->CpuID)
455 {
456 /* Build ID1-style string for older CPUs */
457 sprintf(Buffer,
458 CmpID1,
459 Prcb->CpuType,
460 (Prcb->CpuStep >> 8) + 'A',
461 Prcb->CpuStep & 0xff);
462 }
463 else
464 {
465 /* Build ID2-style string for newer CPUs */
466 sprintf(Buffer,
467 CmpID2,
468 Prcb->CpuType,
469 (Prcb->CpuStep >> 8),
470 Prcb->CpuStep & 0xff);
471 }
472
473 /* Save the ID string length now that we've created it */
474 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1;
475
476 /* Initialize the registry configuration node for it */
477 Status = CmpInitializeRegistryNode(&ConfigData,
478 SystemHandle,
479 &KeyHandle,
480 InterfaceTypeUndefined,
481 0xFFFFFFFF,
482 IndexTable);
483 if (!NT_SUCCESS(Status))
484 {
485 NtClose(BiosHandle);
486 NtClose(SystemHandle);
487 return Status;
488 }
489
490 /* Check if we have an FPU */
491 if (KeI386NpxPresent)
492 {
493 /* Setup the Configuration Entry for the FPU */
494 RtlZeroMemory(&ConfigData, sizeof(ConfigData));
495 ConfigData.ComponentEntry.Class = ProcessorClass;
496 ConfigData.ComponentEntry.Type = FloatingPointProcessor;
497 ConfigData.ComponentEntry.Key = i;
498 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
499 ConfigData.ComponentEntry.Identifier = Buffer;
500
501 /* For 386 cpus, the CPU pp is the identifier */
502 if (Prcb->CpuType == 3) strcpy(Buffer, "80387");
503
504 /* Save the ID string length now that we've created it */
505 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1;
506
507 /* Initialize the registry configuration node for it */
508 Status = CmpInitializeRegistryNode(&ConfigData,
509 SystemHandle,
510 &FpuHandle,
511 InterfaceTypeUndefined,
512 0xFFFFFFFF,
513 IndexTable);
514 if (!NT_SUCCESS(Status))
515 {
516 /* We failed, close all the opened handles and return */
517 NtClose(KeyHandle);
518 NtClose(BiosHandle);
519 NtClose(SystemHandle);
520 return Status;
521 }
522
523 /* Close this new handle */
524 NtClose(FpuHandle);
525
526 /* Stay on this CPU only */
527 KeSetSystemAffinityThread(Prcb->SetMember);
528 if (!Prcb->CpuID)
529 {
530 /* Uh oh, no CPUID! */
531 PartialString = CpuString;
532 CmpGetVendorString(Prcb, PartialString);
533 }
534 else
535 {
536 /* Check if we have extended CPUID that supports name ID */
537 KiCpuId(&CpuInfo, 0x80000000);
538 ExtendedId = CpuInfo.Eax;
539 if (ExtendedId >= 0x80000004)
540 {
541 /* Do all the CPUIDs required to get the full name */
542 PartialString = CpuString;
543 for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++)
544 {
545 /* Do the CPUID and save the name string */
546 KiCpuId(&CpuInfo, 0x80000000 | ExtendedId);
547 ((PULONG)PartialString)[0] = CpuInfo.Eax;
548 ((PULONG)PartialString)[1] = CpuInfo.Ebx;
549 ((PULONG)PartialString)[2] = CpuInfo.Ecx;
550 ((PULONG)PartialString)[3] = CpuInfo.Edx;
551
552 /* Go to the next name string */
553 PartialString += 16;
554 }
555
556 /* Null-terminate it */
557 CpuString[47] = ANSI_NULL;
558 }
559 else
560 {
561 KiCpuId(&CpuInfo, 0x00000000);
562 VendorId = CpuInfo.Ebx;
563 PartialString = CpuString;
564 switch (VendorId)
565 {
566 case 'uneG': /* Intel */
567 CmpGetIntelBrandString(PartialString);
568 break;
569 case 'htuA': /* AMD */
570 /* FIXME */
571 CmpGetVendorString(Prcb, PartialString);
572 break;
573 default:
574 CmpGetVendorString(Prcb, PartialString);
575 }
576 }
577 }
578
579 /* Go back to user affinity */
580 KeRevertToUserAffinityThread();
581
582 /* Check if we have a CPU Name */
583 if (PartialString)
584 {
585 /* Convert it to Unicode */
586 RtlInitAnsiString(&TempString, CpuString);
587 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
588
589 /* Add it to the registry */
590 RtlInitUnicodeString(&ValueName, L"ProcessorNameString");
591 Status = NtSetValueKey(KeyHandle,
592 &ValueName,
593 0,
594 REG_SZ,
595 Data.Buffer,
596 Data.Length + sizeof(UNICODE_NULL));
597
598 /* ROS: Save a copy for bugzilla reporting */
599 RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer);
600
601 /* Free the temporary buffer */
602 RtlFreeUnicodeString(&Data);
603 }
604
605 /* Check if we had a Vendor ID */
606 if (Prcb->VendorString[0])
607 {
608 /* Convert it to Unicode */
609 RtlInitAnsiString(&TempString, Prcb->VendorString);
610 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
611
612 /* Add it to the registry */
613 RtlInitUnicodeString(&ValueName, L"VendorIdentifier");
614 Status = NtSetValueKey(KeyHandle,
615 &ValueName,
616 0,
617 REG_SZ,
618 Data.Buffer,
619 Data.Length + sizeof(UNICODE_NULL));
620
621 /* Free the temporary buffer */
622 RtlFreeUnicodeString(&Data);
623 }
624
625 /* Check if we have features bits */
626 if (Prcb->FeatureBits)
627 {
628 /* Add them to the registry */
629 RtlInitUnicodeString(&ValueName, L"FeatureSet");
630 Status = NtSetValueKey(KeyHandle,
631 &ValueName,
632 0,
633 REG_DWORD,
634 &Prcb->FeatureBits,
635 sizeof(Prcb->FeatureBits));
636 }
637
638 /* Check if we detected the CPU Speed */
639 if (Prcb->MHz)
640 {
641 /* Add it to the registry */
642 RtlInitUnicodeString(&ValueName, L"~MHz");
643 Status = NtSetValueKey(KeyHandle,
644 &ValueName,
645 0,
646 REG_DWORD,
647 &Prcb->MHz,
648 sizeof(Prcb->MHz));
649 }
650
651 /* Check if we have an update signature */
652 if (Prcb->UpdateSignature.QuadPart)
653 {
654 /* Add it to the registry */
655 RtlInitUnicodeString(&ValueName, L"Update Signature");
656 Status = NtSetValueKey(KeyHandle,
657 &ValueName,
658 0,
659 REG_BINARY,
660 &Prcb->UpdateSignature,
661 sizeof(Prcb->UpdateSignature));
662 }
663
664 /* Close the processor handle */
665 NtClose(KeyHandle);
666
667 /* FIXME: Detect CPU mismatches */
668 }
669 }
670
671 /* Free the configuration data */
672 ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
673 }
674
675 /* Open physical memory */
676 RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory");
677 InitializeObjectAttributes(&ObjectAttributes,
678 &SectionName,
679 OBJ_CASE_INSENSITIVE,
680 NULL,
681 NULL);
682 Status = ZwOpenSection(&SectionHandle,
683 SECTION_ALL_ACCESS,
684 &ObjectAttributes);
685 if (!NT_SUCCESS(Status))
686 {
687 /* We failed, close all the opened handles and return */
688 // NtClose(KeyHandle);
689 NtClose(BiosHandle);
690 NtClose(SystemHandle);
691 /* 'Quickie' closes KeyHandle */
692 goto Quickie;
693 }
694
695 /* Map the first 1KB of memory to get the IVT */
696 ViewSize = PAGE_SIZE;
697 Status = ZwMapViewOfSection(SectionHandle,
698 NtCurrentProcess(),
699 &BaseAddress,
700 0,
701 ViewSize,
702 &ViewBase,
703 &ViewSize,
704 ViewUnmap,
705 MEM_DOS_LIM,
706 PAGE_READWRITE);
707 if (!NT_SUCCESS(Status))
708 {
709 /* Assume default */
710 VideoRomBase = 0xC0000;
711 }
712 else
713 {
714 /* Calculate the base address from the vector */
715 VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0;
716 VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0;
717
718 /* Now get to the actual ROM Start and make sure it's not invalid*/
719 VideoRomBase &= 0xFFFF8000;
720 if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000;
721
722 /* And unmap the section */
723 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
724 }
725
726 /* Allocate BIOS Version pp Buffer */
727 BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM);
728
729 /* Setup settings to map the 64K BIOS ROM */
730 BaseAddress = 0;
731 ViewSize = 16 * PAGE_SIZE;
732 ViewBase.LowPart = 0xF0000;
733 ViewBase.HighPart = 0;
734
735 /* Map it */
736 Status = ZwMapViewOfSection(SectionHandle,
737 NtCurrentProcess(),
738 &BaseAddress,
739 0,
740 ViewSize,
741 &ViewBase,
742 &ViewSize,
743 ViewUnmap,
744 MEM_DOS_LIM,
745 PAGE_READWRITE);
746 if (NT_SUCCESS(Status))
747 {
748 /* Scan the ROM to get the BIOS Date */
749 if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE))
750 {
751 /* Convert it to Unicode */
752 RtlInitAnsiString(&TempString, Buffer);
753 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
754
755 /* Write the date into the registry */
756 RtlInitUnicodeString(&ValueName, L"SystemBiosDate");
757 Status = NtSetValueKey(SystemHandle,
758 &ValueName,
759 0,
760 REG_SZ,
761 Data.Buffer,
762 Data.Length + sizeof(UNICODE_NULL));
763
764 /* Free the string */
765 RtlFreeUnicodeString(&Data);
766
767 if (BiosHandle)
768 {
769 /* Get the BIOS Date Identifier */
770 RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16 * PAGE_SIZE - 11), 8);
771 Buffer[8] = ANSI_NULL;
772
773 /* Convert it to unicode */
774 RtlInitAnsiString(&TempString, Buffer);
775 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
776 if (NT_SUCCESS(Status))
777 {
778 /* Save it to the registry */
779 Status = NtSetValueKey(BiosHandle,
780 &ValueName,
781 0,
782 REG_SZ,
783 Data.Buffer,
784 Data.Length + sizeof(UNICODE_NULL));
785
786 /* ROS: Save a copy for bugzilla reporting */
787 RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer);
788
789 /* Free the string */
790 RtlFreeUnicodeString(&Data);
791 }
792
793 /* Close the bios information handle */
794 NtClose(BiosHandle);
795 }
796 }
797
798 /* Get the BIOS Version */
799 if (CmpGetBiosVersion(BaseAddress, 16 * PAGE_SIZE, Buffer))
800 {
801 /* Start at the beginning of our buffer */
802 CurrentVersion = BiosVersion;
803 do
804 {
805 /* Convert to Unicode */
806 RtlInitAnsiString(&TempString, Buffer);
807 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
808
809 /* Calculate the length of this string and copy it in */
810 Length = Data.Length + sizeof(UNICODE_NULL);
811 RtlMoveMemory(CurrentVersion, Data.Buffer, Length);
812
813 /* Free the unicode string */
814 RtlFreeUnicodeString(&Data);
815
816 /* Update the total length and see if we're out of space */
817 TotalLength += Length;
818 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE)
819 {
820 /* One more string would push us out, so stop here */
821 break;
822 }
823
824 /* Go to the next string inside the multi-string buffer */
825 CurrentVersion += Length;
826
827 /* Query the next BIOS Version */
828 } while (CmpGetBiosVersion(NULL, 0, Buffer));
829
830 /* Check if we found any strings at all */
831 if (TotalLength)
832 {
833 /* Add the final null-terminator */
834 *(PWSTR)CurrentVersion = UNICODE_NULL;
835 TotalLength += sizeof(UNICODE_NULL);
836
837 /* Write the BIOS Version to the registry */
838 RtlInitUnicodeString(&ValueName, L"SystemBiosVersion");
839 Status = NtSetValueKey(SystemHandle,
840 &ValueName,
841 0,
842 REG_MULTI_SZ,
843 BiosVersion,
844 TotalLength);
845
846 /* ROS: Save a copy for bugzilla reporting */
847 RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion);
848 }
849 }
850
851 /* Unmap the section */
852 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
853 }
854
855 /* Now prepare for Video BIOS Mapping of 32KB */
856 BaseAddress = 0;
857 ViewSize = 8 * PAGE_SIZE;
858 ViewBase.QuadPart = VideoRomBase;
859
860 /* Map it */
861 Status = ZwMapViewOfSection(SectionHandle,
862 NtCurrentProcess(),
863 &BaseAddress,
864 0,
865 ViewSize,
866 &ViewBase,
867 &ViewSize,
868 ViewUnmap,
869 MEM_DOS_LIM,
870 PAGE_READWRITE);
871 if (NT_SUCCESS(Status))
872 {
873 /* Scan the ROM to get the BIOS Date */
874 if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE))
875 {
876 /* Convert it to Unicode */
877 RtlInitAnsiString(&TempString, Buffer);
878 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
879
880 /* Write the date into the registry */
881 RtlInitUnicodeString(&ValueName, L"VideoBiosDate");
882 Status = NtSetValueKey(SystemHandle,
883 &ValueName,
884 0,
885 REG_SZ,
886 Data.Buffer,
887 Data.Length + sizeof(UNICODE_NULL));
888
889 /* ROS: Save a copy for bugzilla reporting */
890 RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer);
891
892 /* Free the string */
893 RtlFreeUnicodeString(&Data);
894 }
895
896 /* Get the Video BIOS Version */
897 if (CmpGetBiosVersion(BaseAddress, 8 * PAGE_SIZE, Buffer))
898 {
899 /* Start at the beginning of our buffer */
900 CurrentVersion = BiosVersion;
901 do
902 {
903 /* Convert to Unicode */
904 RtlInitAnsiString(&TempString, Buffer);
905 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
906
907 /* Calculate the length of this string and copy it in */
908 Length = Data.Length + sizeof(UNICODE_NULL);
909 RtlMoveMemory(CurrentVersion, Data.Buffer, Length);
910
911 /* Free the unicode string */
912 RtlFreeUnicodeString(&Data);
913
914 /* Update the total length and see if we're out of space */
915 TotalLength += Length;
916 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE)
917 {
918 /* One more string would push us out, so stop here */
919 break;
920 }
921
922 /* Go to the next string inside the multi-string buffer */
923 CurrentVersion += Length;
924
925 /* Query the next BIOS Version */
926 } while (CmpGetBiosVersion(NULL, 0, Buffer));
927
928 /* Check if we found any strings at all */
929 if (TotalLength)
930 {
931 /* Add the final null-terminator */
932 *(PWSTR)CurrentVersion = UNICODE_NULL;
933 TotalLength += sizeof(UNICODE_NULL);
934
935 /* Write the BIOS Version to the registry */
936 RtlInitUnicodeString(&ValueName, L"VideoBiosVersion");
937 Status = NtSetValueKey(SystemHandle,
938 &ValueName,
939 0,
940 REG_MULTI_SZ,
941 BiosVersion,
942 TotalLength);
943
944 /* ROS: Save a copy for bugzilla reporting */
945 RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion);
946 }
947 }
948
949 /* Unmap the section */
950 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
951 }
952
953 /* Close the section */
954 ZwClose(SectionHandle);
955
956 /* Free the BIOS version string buffer */
957 if (BiosVersion) ExFreePoolWithTag(BiosVersion, TAG_CM);
958
959 Quickie:
960 /* Close the processor handle */
961 NtClose(KeyHandle);
962 return STATUS_SUCCESS;
963 }