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)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 PCHAR CmpID1
= "80%u86-%c%x";
18 PCHAR CmpID2
= "x86 Family %u Model %u Stepping %u";
19 PCHAR CmpBiosStrings
[] =
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",
29 PCHAR CmpBiosBegin
, CmpBiosSearchStart
, CmpBiosSearchEnd
;
31 /* FUNCTIONS *****************************************************************/
35 CmpGetBiosDate(IN PCHAR BiosStart
,
40 CHAR LastDate
[11] = {0}, CurrentDate
[11];
43 /* Skip the signature and the magic, and loop the BIOS ROM */
45 pp
= BiosStart
+ BiosLength
- 5;
48 /* Check for xx/yy/zz which we assume to be a date */
57 /* Copy the string proper */
58 RtlMoveMemory(&CurrentDate
[5], p
- 2, 5);
60 /* Add a 0 if the month only has one digit */
61 if (!isdigit(CurrentDate
[5])) CurrentDate
[5] = '0';
63 /* Now copy the year */
64 CurrentDate
[2] = p
[4];
65 CurrentDate
[3] = p
[5];
66 CurrentDate
[4] = CurrentDate
[7] = CurrentDate
[10] = ANSI_NULL
;
68 /* If the date comes from the BIOS, check if it's a 4-digit year */
72 ((RtlEqualMemory(&p
[4], "19", 2)) ||
73 (RtlEqualMemory(&p
[4], "20", 2))))
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];
83 /* Otherwise, we'll just assume anything under 80 is 2000 */
84 if (strtoul(&CurrentDate
[2], NULL
, 10) < 80)
86 /* Hopefully your BIOS wasn't made in 1979 */
92 /* Anything over 80, was probably made in the 1900s... */
98 /* Add slashes where we previously had NULLs */
99 CurrentDate
[4] = CurrentDate
[7] = '/';
101 /* Check which date is newer */
102 if (memcmp(LastDate
, CurrentDate
, 10) < 0)
104 /* Found a newer date, select it */
105 RtlMoveMemory(LastDate
, CurrentDate
, 10);
113 /* Make sure we found a date */
116 /* Copy the year at the pp, and keep only the last two digits */
117 RtlMoveMemory(BiosDate
, &LastDate
[5], 5);
119 BiosDate
[6] = LastDate
[2];
120 BiosDate
[7] = LastDate
[3];
121 BiosDate
[8] = ANSI_NULL
;
125 /* No date found, return empty string */
126 BiosDate
[0] = ANSI_NULL
;
132 CmpGetBiosVersion(IN PCHAR BiosStart
,
134 IN PCHAR BiosVersion
)
140 /* Check if we were given intitial data for the search */
143 /* Save it for later use */
144 CmpBiosBegin
= BiosStart
;
145 CmpBiosSearchStart
= BiosStart
+ 1;
146 CmpBiosSearchEnd
= BiosStart
+ BiosLength
- 2;
149 /* Now loop the BIOS area */
152 /* Start an initial search looking for numbers and periods */
154 while (CmpBiosSearchStart
<= CmpBiosSearchEnd
)
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'))
163 /* Start looking in this area for the actual BIOS Version */
164 pp
= CmpBiosSearchStart
;
170 CmpBiosSearchStart
++;
174 /* Break out if we're went past the BIOS area */
175 if (CmpBiosSearchStart
> CmpBiosSearchEnd
) return FALSE
;
177 /* Move to the next 2 bytes */
178 CmpBiosSearchStart
+= 2;
180 /* Null-terminate our scratch buffer and start the string here */
181 Buffer
[127] = ANSI_NULL
;
184 /* Go back one character since we're doing this backwards */
187 /* Loop the identifier we found as long as it's valid */
189 while ((i
++ < 127) &&
190 (pp
>= CmpBiosBegin
) &&
194 /* Copy the character */
198 /* Go past the last character since we went backwards */
201 /* Loop the strings we recognize */
202 for (i
= 0; CmpBiosStrings
[i
]; i
++)
204 /* Check if a match was found */
205 if (strstr(p
, CmpBiosStrings
[i
])) goto Match
;
210 /* Skip until we find a space */
211 for (; *pp
== ' '; pp
++);
213 /* Loop the final string */
217 /* Copy the character into the final string */
218 BiosVersion
[i
] = *pp
++;
219 } while ((++i
< 127) &&
220 (pp
<= (CmpBiosSearchEnd
+ 1)) &&
224 /* Null-terminate the version string */
225 BiosVersion
[i
] = ANSI_NULL
;
231 CmpGetIntelBrandString(OUT PCHAR CpuString
)
234 ULONG BrandId
, Signature
;
236 /* Get the Brand Id */
237 KiCpuId(&CpuInfo
, 0x00000001);
238 Signature
= CpuInfo
.Eax
;
239 BrandId
= CpuInfo
.Ebx
& 0xFF;
244 strcpy(CpuString
, "Intel(R) Celeron(R) processor");
248 strcpy(CpuString
, "Intel(R) Pentium(R) III processor");
251 if(Signature
== 0x000006B1)
252 strcpy(CpuString
, "Intel(R) Celeron(R) processor");
254 strcpy(CpuString
, "Intel(R) Pentium(R) III Xeon(R) processor");
257 strcpy(CpuString
, "Mobile Intel(R) Pentium(R) III Processor-M");
260 if(Signature
>= 0x00000F13)
261 strcpy(CpuString
, "Intel(R) Genuine Processor");
263 strcpy(CpuString
, "Intel(R) Pentium(R) 4 processor");
266 strcpy(CpuString
, "Intel(R) Pentium(R) 4 processor");
269 if(Signature
>= 0x00000F13)
270 strcpy(CpuString
, "Intel(R) Xeon(R) processor");
272 strcpy(CpuString
, "Intel(R) Xeon(R) processor MP");
275 strcpy(CpuString
, "Intel(R) Xeon(R) processor MP");
278 if(Signature
>= 0x00000F13)
279 strcpy(CpuString
, "Mobile Intel(R) Pentium(R) 4 processor-M");
281 strcpy(CpuString
, "Intel(R) Xeon(R) processor");
284 strcpy(CpuString
, "Intel(R) Celeron(R) M processor");
290 strcpy(CpuString
, "Mobile Intel(R) Celeron(R) processor");
294 strcpy(CpuString
, "Intel(R) Celeron(R) Processor");
297 strcpy(CpuString
, "Mobile Genuine Intel(R) Processor");
300 strcpy(CpuString
, "Intel(R) Pentium(R) M processor");
303 strcpy(CpuString
, "Unknown Intel processor");
309 CmpGetVendorString(IN PKPRCB Prcb
, OUT PCHAR CpuString
)
311 /* Check if we have a Vendor String */
312 if (Prcb
->VendorString
[0])
314 strcpy(CpuString
, Prcb
->VendorString
);
318 strcpy(CpuString
, "Unknown x86 processor");
324 CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
326 UNICODE_STRING KeyName
, ValueName
, Data
, SectionName
;
327 OBJECT_ATTRIBUTES ObjectAttributes
;
328 ULONG HavePae
, Length
, TotalLength
= 0, i
, Disposition
;
331 HANDLE KeyHandle
, BiosHandle
, SystemHandle
, FpuHandle
, SectionHandle
;
332 CONFIGURATION_COMPONENT_DATA ConfigData
;
335 ULONG VendorId
, ExtendedId
;
337 USHORT IndexTable
[MaximumType
+ 1] = {0};
338 ANSI_STRING TempString
;
339 PCHAR PartialString
= NULL
, BiosVersion
;
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
;
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
,
354 OBJ_CASE_INSENSITIVE
,
357 Status
= NtOpenKey(&KeyHandle
, KEY_READ
| KEY_WRITE
, &ObjectAttributes
);
358 if (NT_SUCCESS(Status
))
360 /* Detect if PAE is enabled */
361 HavePae
= SharedUserData
->ProcessorFeatures
[PF_PAE_ENABLED
];
364 RtlInitUnicodeString(&ValueName
, L
"PhysicalAddressExtension");
365 NtSetValueKey(KeyHandle
,
376 /* Open the hardware description key */
377 RtlInitUnicodeString(&KeyName
,
378 L
"\\Registry\\Machine\\Hardware\\Description\\System");
379 InitializeObjectAttributes(&ObjectAttributes
,
381 OBJ_CASE_INSENSITIVE
,
384 Status
= NtOpenKey(&SystemHandle
, KEY_READ
| KEY_WRITE
, &ObjectAttributes
);
385 if (!NT_SUCCESS(Status
)) return Status
;
387 /* Create the BIOS Information key */
388 RtlInitUnicodeString(&KeyName
,
389 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\"
390 L
"Control\\BIOSINFO");
391 InitializeObjectAttributes(&ObjectAttributes
,
393 OBJ_CASE_INSENSITIVE
,
396 Status
= NtCreateKey(&BiosHandle
,
401 REG_OPTION_NON_VOLATILE
,
403 if (ExpInTextModeSetup
)
405 if (!NT_SUCCESS(Status
))
408 else if (!NT_SUCCESS(Status
))
411 /* Create the CPU Key, and check if it already existed */
412 RtlInitUnicodeString(&KeyName
, L
"CentralProcessor");
413 InitializeObjectAttributes(&ObjectAttributes
,
415 OBJ_CASE_INSENSITIVE
,
418 Status
= NtCreateKey(&KeyHandle
,
419 KEY_READ
| KEY_WRITE
,
427 /* The key shouldn't already exist */
428 if (Disposition
== REG_CREATED_NEW_KEY
)
430 /* Allocate the configuration data for cmconfig.c */
431 CmpConfigurationData
= ExAllocatePoolWithTag(PagedPool
,
432 CmpConfigurationAreaSize
,
434 if (!CmpConfigurationData
) return STATUS_INSUFFICIENT_RESOURCES
;
437 for (i
= 0; i
< KeNumberProcessors
; i
++)
440 Prcb
= KiProcessorBlock
[i
];
442 /* Setup the Configuration Entry for the Processor */
443 RtlZeroMemory(&ConfigData
, sizeof (ConfigData
));
444 ConfigData
.ComponentEntry
.Class
= ProcessorClass
;
445 ConfigData
.ComponentEntry
.Type
= CentralProcessor
;
446 ConfigData
.ComponentEntry
.Key
= i
;
447 ConfigData
.ComponentEntry
.AffinityMask
= AFFINITY_MASK(i
);
448 ConfigData
.ComponentEntry
.Identifier
= Buffer
;
450 /* Check if the CPU doesn't support CPUID */
453 /* Build ID1-style string for older CPUs */
457 (Prcb
->CpuStep
>> 8) + 'A',
458 Prcb
->CpuStep
& 0xff);
462 /* Build ID2-style string for newer CPUs */
466 (Prcb
->CpuStep
>> 8),
467 Prcb
->CpuStep
& 0xff);
470 /* Save the ID string length now that we've created it */
471 ConfigData
.ComponentEntry
.IdentifierLength
= (ULONG
)strlen(Buffer
) + 1;
473 /* Initialize the registry configuration node for it */
474 Status
= CmpInitializeRegistryNode(&ConfigData
,
477 InterfaceTypeUndefined
,
480 if (!NT_SUCCESS(Status
)) return(Status
);
482 /* Check if we have an FPU */
483 if (KeI386NpxPresent
)
485 /* Setup the Configuration Entry for the FPU */
486 RtlZeroMemory(&ConfigData
, sizeof(ConfigData
));
487 ConfigData
.ComponentEntry
.Class
= ProcessorClass
;
488 ConfigData
.ComponentEntry
.Type
= FloatingPointProcessor
;
489 ConfigData
.ComponentEntry
.Key
= i
;
490 ConfigData
.ComponentEntry
.AffinityMask
= AFFINITY_MASK(i
);
491 ConfigData
.ComponentEntry
.Identifier
= Buffer
;
493 /* For 386 cpus, the CPU pp is the identifier */
494 if (Prcb
->CpuType
== 3) strcpy(Buffer
, "80387");
496 /* Save the ID string length now that we've created it */
497 ConfigData
.ComponentEntry
.IdentifierLength
= (ULONG
)strlen(Buffer
) + 1;
499 /* Initialize the registry configuration node for it */
500 Status
= CmpInitializeRegistryNode(&ConfigData
,
503 InterfaceTypeUndefined
,
506 if (!NT_SUCCESS(Status
))
508 /* Failed, close the CPU handle and return */
513 /* Close this new handle */
516 /* Stay on this CPU only */
517 KeSetSystemAffinityThread(Prcb
->SetMember
);
520 /* Uh oh, no CPUID! */
521 PartialString
= CpuString
;
522 CmpGetVendorString(Prcb
, PartialString
);
526 /* Check if we have extended CPUID that supports name ID */
527 KiCpuId(&CpuInfo
, 0x80000000);
528 ExtendedId
= CpuInfo
.Eax
;
529 if (ExtendedId
>= 0x80000004)
531 /* Do all the CPUIDs required to get the full name */
532 PartialString
= CpuString
;
533 for (ExtendedId
= 2; ExtendedId
<= 4; ExtendedId
++)
535 /* Do the CPUID and save the name string */
536 KiCpuId(&CpuInfo
, 0x80000000 | ExtendedId
);
537 ((PULONG
)PartialString
)[0] = CpuInfo
.Eax
;
538 ((PULONG
)PartialString
)[1] = CpuInfo
.Ebx
;
539 ((PULONG
)PartialString
)[2] = CpuInfo
.Ecx
;
540 ((PULONG
)PartialString
)[3] = CpuInfo
.Edx
;
542 /* Go to the next name string */
546 /* Null-terminate it */
547 CpuString
[47] = ANSI_NULL
;
551 KiCpuId(&CpuInfo
, 0x00000000);
552 VendorId
= CpuInfo
.Ebx
;
553 PartialString
= CpuString
;
556 case 'uneG': /* Intel */
557 CmpGetIntelBrandString(PartialString
);
559 case 'htuA': /* AMD */
561 CmpGetVendorString(Prcb
, PartialString
);
564 CmpGetVendorString(Prcb
, PartialString
);
569 /* Go back to user affinity */
570 KeRevertToUserAffinityThread();
572 /* Check if we have a CPU Name */
575 /* Convert it to Unicode */
576 RtlInitAnsiString(&TempString
, CpuString
);
577 RtlAnsiStringToUnicodeString(&Data
, &TempString
, TRUE
);
579 /* Add it to the registry */
580 RtlInitUnicodeString(&ValueName
, L
"ProcessorNameString");
581 Status
= NtSetValueKey(KeyHandle
,
586 Data
.Length
+ sizeof(UNICODE_NULL
));
588 /* ROS: Save a copy for bugzilla reporting */
589 RtlCreateUnicodeString(&KeRosProcessorName
, Data
.Buffer
);
591 /* Free the temporary buffer */
592 RtlFreeUnicodeString(&Data
);
595 /* Check if we had a Vendor ID */
596 if (Prcb
->VendorString
[0])
598 /* Convert it to Unicode */
599 RtlInitAnsiString(&TempString
, Prcb
->VendorString
);
600 RtlAnsiStringToUnicodeString(&Data
, &TempString
, TRUE
);
602 /* Add it to the registry */
603 RtlInitUnicodeString(&ValueName
, L
"VendorIdentifier");
604 Status
= NtSetValueKey(KeyHandle
,
609 Data
.Length
+ sizeof(UNICODE_NULL
));
611 /* Free the temporary buffer */
612 RtlFreeUnicodeString(&Data
);
615 /* Check if we have features bits */
616 if (Prcb
->FeatureBits
)
618 /* Add them to the registry */
619 RtlInitUnicodeString(&ValueName
, L
"FeatureSet");
620 Status
= NtSetValueKey(KeyHandle
,
625 sizeof(Prcb
->FeatureBits
));
628 /* Check if we detected the CPU Speed */
631 /* Add it to the registry */
632 RtlInitUnicodeString(&ValueName
, L
"~MHz");
633 Status
= NtSetValueKey(KeyHandle
,
641 /* Check if we have an update signature */
642 if (Prcb
->UpdateSignature
.QuadPart
)
644 /* Add it to the registry */
645 RtlInitUnicodeString(&ValueName
, L
"Update Signature");
646 Status
= NtSetValueKey(KeyHandle
,
650 &Prcb
->UpdateSignature
,
651 sizeof(Prcb
->UpdateSignature
));
654 /* Close the processor handle */
657 /* FIXME: Detect CPU mismatches */
661 /* Free the configuration data */
662 ExFreePoolWithTag(CmpConfigurationData
, TAG_CM
);
665 /* Open physical memory */
666 RtlInitUnicodeString(&SectionName
, L
"\\Device\\PhysicalMemory");
667 InitializeObjectAttributes(&ObjectAttributes
,
669 OBJ_CASE_INSENSITIVE
,
672 Status
= ZwOpenSection(&SectionHandle
,
675 if (!NT_SUCCESS(Status
)) goto Quickie
;
677 /* Map the first 1KB of memory to get the IVT */
678 ViewSize
= PAGE_SIZE
;
679 Status
= ZwMapViewOfSection(SectionHandle
,
689 if (!NT_SUCCESS(Status
))
692 VideoRomBase
= 0xC0000;
696 /* Calculate the base address from the vector */
697 VideoRomBase
= (*((PULONG
)BaseAddress
+ 0x10) >> 12) & 0xFFFF0;
698 VideoRomBase
+= *((PULONG
)BaseAddress
+ 0x10) & 0xFFF0;
700 /* Now get to the actual ROM Start and make sure it's not invalid*/
701 VideoRomBase
&= 0xFFFF8000;
702 if (VideoRomBase
< 0xC0000) VideoRomBase
= 0xC0000;
704 /* And unmap the section */
705 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
708 /* Allocate BIOS Version pp Buffer */
709 BiosVersion
= ExAllocatePoolWithTag(PagedPool
, PAGE_SIZE
, TAG_CM
);
711 /* Setup settings to map the 64K BIOS ROM */
713 ViewSize
= 16 * PAGE_SIZE
;
714 ViewBase
.LowPart
= 0xF0000;
715 ViewBase
.HighPart
= 0;
718 Status
= ZwMapViewOfSection(SectionHandle
,
728 if (NT_SUCCESS(Status
))
730 /* Scan the ROM to get the BIOS Date */
731 if (CmpGetBiosDate(BaseAddress
, 16 * PAGE_SIZE
, Buffer
, TRUE
))
733 /* Convert it to Unicode */
734 RtlInitAnsiString(&TempString
, Buffer
);
735 RtlAnsiStringToUnicodeString(&Data
, &TempString
, TRUE
);
737 /* Write the date into the registry */
738 RtlInitUnicodeString(&ValueName
, L
"SystemBiosDate");
739 Status
= NtSetValueKey(SystemHandle
,
744 Data
.Length
+ sizeof(UNICODE_NULL
));
746 /* Free the string */
747 RtlFreeUnicodeString(&Data
);
751 /* Get the BIOS Date Identifier */
752 RtlCopyMemory(Buffer
, (PCHAR
)BaseAddress
+ (16 * PAGE_SIZE
- 11), 8);
753 Buffer
[8] = ANSI_NULL
;
755 /* Convert it to unicode */
756 RtlInitAnsiString(&TempString
, Buffer
);
757 Status
= RtlAnsiStringToUnicodeString(&Data
, &TempString
, TRUE
);
758 if (NT_SUCCESS(Status
))
760 /* Save it to the registry */
761 Status
= NtSetValueKey(BiosHandle
,
766 Data
.Length
+ sizeof(UNICODE_NULL
));
768 /* ROS: Save a copy for bugzilla reporting */
769 RtlCreateUnicodeString(&KeRosBiosDate
, Data
.Buffer
);
771 /* Free the string */
772 RtlFreeUnicodeString(&Data
);
775 /* Close the bios information handle */
780 /* Get the BIOS Version */
781 if (CmpGetBiosVersion(BaseAddress
, 16 * PAGE_SIZE
, Buffer
))
783 /* Start at the beginning of our buffer */
784 CurrentVersion
= BiosVersion
;
787 /* Convert to Unicode */
788 RtlInitAnsiString(&TempString
, Buffer
);
789 RtlAnsiStringToUnicodeString(&Data
, &TempString
, TRUE
);
791 /* Calculate the length of this string and copy it in */
792 Length
= Data
.Length
+ sizeof(UNICODE_NULL
);
793 RtlMoveMemory(CurrentVersion
, Data
.Buffer
, Length
);
795 /* Free the unicode string */
796 RtlFreeUnicodeString(&Data
);
798 /* Update the total length and see if we're out of space */
799 TotalLength
+= Length
;
800 if (TotalLength
+ 256 + sizeof(UNICODE_NULL
) > PAGE_SIZE
)
802 /* One more string would push us out, so stop here */
806 /* Go to the next string inside the multi-string buffer */
807 CurrentVersion
+= Length
;
809 /* Query the next BIOS Version */
810 } while (CmpGetBiosVersion(NULL
, 0, Buffer
));
812 /* Check if we found any strings at all */
815 /* Add the final null-terminator */
816 *(PWSTR
)CurrentVersion
= UNICODE_NULL
;
817 TotalLength
+= sizeof(UNICODE_NULL
);
819 /* Write the BIOS Version to the registry */
820 RtlInitUnicodeString(&ValueName
, L
"SystemBiosVersion");
821 Status
= NtSetValueKey(SystemHandle
,
828 /* ROS: Save a copy for bugzilla reporting */
829 RtlCreateUnicodeString(&KeRosBiosVersion
, (PWCH
)BiosVersion
);
833 /* Unmap the section */
834 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
837 /* Now prepare for Video BIOS Mapping of 32KB */
839 ViewSize
= 8 * PAGE_SIZE
;
840 ViewBase
.QuadPart
= VideoRomBase
;
843 Status
= ZwMapViewOfSection(SectionHandle
,
853 if (NT_SUCCESS(Status
))
855 /* Scan the ROM to get the BIOS Date */
856 if (CmpGetBiosDate(BaseAddress
, 8 * PAGE_SIZE
, Buffer
, FALSE
))
858 /* Convert it to Unicode */
859 RtlInitAnsiString(&TempString
, Buffer
);
860 RtlAnsiStringToUnicodeString(&Data
, &TempString
, TRUE
);
862 /* Write the date into the registry */
863 RtlInitUnicodeString(&ValueName
, L
"VideoBiosDate");
864 Status
= NtSetValueKey(SystemHandle
,
869 Data
.Length
+ sizeof(UNICODE_NULL
));
871 /* ROS: Save a copy for bugzilla reporting */
872 RtlCreateUnicodeString(&KeRosVideoBiosDate
, Data
.Buffer
);
874 /* Free the string */
875 RtlFreeUnicodeString(&Data
);
878 /* Get the Video BIOS Version */
879 if (CmpGetBiosVersion(BaseAddress
, 8 * PAGE_SIZE
, Buffer
))
881 /* Start at the beginning of our buffer */
882 CurrentVersion
= BiosVersion
;
885 /* Convert to Unicode */
886 RtlInitAnsiString(&TempString
, Buffer
);
887 RtlAnsiStringToUnicodeString(&Data
, &TempString
, TRUE
);
889 /* Calculate the length of this string and copy it in */
890 Length
= Data
.Length
+ sizeof(UNICODE_NULL
);
891 RtlMoveMemory(CurrentVersion
, Data
.Buffer
, Length
);
893 /* Free the unicode string */
894 RtlFreeUnicodeString(&Data
);
896 /* Update the total length and see if we're out of space */
897 TotalLength
+= Length
;
898 if (TotalLength
+ 256 + sizeof(UNICODE_NULL
) > PAGE_SIZE
)
900 /* One more string would push us out, so stop here */
904 /* Go to the next string inside the multi-string buffer */
905 CurrentVersion
+= Length
;
907 /* Query the next BIOS Version */
908 } while (CmpGetBiosVersion(NULL
, 0, Buffer
));
910 /* Check if we found any strings at all */
913 /* Add the final null-terminator */
914 *(PWSTR
)CurrentVersion
= UNICODE_NULL
;
915 TotalLength
+= sizeof(UNICODE_NULL
);
917 /* Write the BIOS Version to the registry */
918 RtlInitUnicodeString(&ValueName
, L
"VideoBiosVersion");
919 Status
= NtSetValueKey(SystemHandle
,
926 /* ROS: Save a copy for bugzilla reporting */
927 RtlCreateUnicodeString(&KeRosVideoBiosVersion
, (PWCH
)BiosVersion
);
931 /* Unmap the section */
932 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
935 /* Close the section */
936 ZwClose(SectionHandle
);
938 /* Free the BIOS version string buffer */
939 if (BiosVersion
) ExFreePoolWithTag(BiosVersion
, TAG_CM
);
942 /* Close the procesor handle */
944 return STATUS_SUCCESS
;