reactos/ntoskrnl/config/i386/cmhardwr.c
Stanislav Motylkov f234cb6e59
[NTOS:CM] Do not create ProcessorNameString value if there is no Brand String
If the CPU does support CPUID instruction but does not have the Brand String,
the legacy name detection should be performed either in CIM_Processor (WMI),
in the Processor device driver, or in the application itself.

The deleted Intel CPU name detection code can go to the WMI at some point.
In fact Windows XP and 2003 kernels do not have any strings of that kind.

This effectively reverts the hack committed 6 years ago in 7a985425 (r63798)
that was intended to workaround CORE-7952.

CORE-17413
2020-12-30 19:38:41 +03:00

852 lines
30 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/config/i386/cmhardwr.c
* PURPOSE: Configuration Manager - Hardware-Specific Code
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "ntoskrnl.h"
#define NDEBUG
#include "debug.h"
/* GLOBALS *******************************************************************/
PCHAR CmpID1 = "80%u86-%c%x";
PCHAR CmpID2 = "x86 Family %u Model %u Stepping %u";
PCHAR CmpBiosStrings[] =
{
"Ver",
"Rev",
"Rel",
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
"v 0", "v 1", "v 2", "v 3", "v 4", "v 5", "v 6", "v 7", "v 8", "v 9",
NULL
};
PCHAR CmpBiosBegin, CmpBiosSearchStart, CmpBiosSearchEnd;
/* FUNCTIONS *****************************************************************/
BOOLEAN
NTAPI
CmpGetBiosDate(IN PCHAR BiosStart,
IN ULONG BiosLength,
IN PCHAR BiosDate,
IN BOOLEAN FromBios)
{
CHAR LastDate[11] = {0}, CurrentDate[11];
PCHAR p, pp;
/* Skip the signature and the magic, and loop the BIOS ROM */
p = BiosStart + 2;
pp = BiosStart + BiosLength - 5;
while (p < pp)
{
/* Check for xx/yy/zz which we assume to be a date */
if ((p[0] == '/') &&
(p[3] == '/') &&
(isdigit(p[-1])) &&
(isdigit(p[1])) &&
(isdigit(p[2])) &&
(isdigit(p[4])) &&
(isdigit(p[5])))
{
/* Copy the string proper */
RtlMoveMemory(&CurrentDate[5], p - 2, 5);
/* Add a 0 if the month only has one digit */
if (!isdigit(CurrentDate[5])) CurrentDate[5] = '0';
/* Now copy the year */
CurrentDate[2] = p[4];
CurrentDate[3] = p[5];
CurrentDate[4] = CurrentDate[7] = CurrentDate[10] = ANSI_NULL;
/* If the date comes from the BIOS, check if it's a 4-digit year */
if ((FromBios) &&
(isdigit(p[6])) &&
(isdigit(p[7])) &&
((RtlEqualMemory(&p[4], "19", 2)) ||
(RtlEqualMemory(&p[4], "20", 2))))
{
/* Copy the year proper */
CurrentDate[0] = p[4];
CurrentDate[1] = p[5];
CurrentDate[2] = p[6];
CurrentDate[3] = p[7];
}
else
{
/* Otherwise, we'll just assume anything under 80 is 2000 */
if (strtoul(&CurrentDate[2], NULL, 10) < 80)
{
/* Hopefully your BIOS wasn't made in 1979 */
CurrentDate[0] = '2';
CurrentDate[1] = '0';
}
else
{
/* Anything over 80, was probably made in the 1900s... */
CurrentDate[0] = '1';
CurrentDate[1] = '9';
}
}
/* Add slashes where we previously had NULLs */
CurrentDate[4] = CurrentDate[7] = '/';
/* Check which date is newer */
if (memcmp(LastDate, CurrentDate, 10) < 0)
{
/* Found a newer date, select it */
RtlMoveMemory(LastDate, CurrentDate, 10);
}
p += 2;
}
p++;
}
/* Make sure we found a date */
if (LastDate[0])
{
/* Copy the year at the pp, and keep only the last two digits */
RtlMoveMemory(BiosDate, &LastDate[5], 5);
BiosDate[5] = '/';
BiosDate[6] = LastDate[2];
BiosDate[7] = LastDate[3];
BiosDate[8] = ANSI_NULL;
return TRUE;
}
/* No date found, return empty string */
BiosDate[0] = ANSI_NULL;
return FALSE;
}
BOOLEAN
NTAPI
CmpGetBiosVersion(IN PCHAR BiosStart,
IN ULONG BiosLength,
IN PCHAR BiosVersion)
{
CHAR Buffer[128];
PCHAR p, pp;
USHORT i;
/* Check if we were given intitial data for the search */
if (BiosStart)
{
/* Save it for later use */
CmpBiosBegin = BiosStart;
CmpBiosSearchStart = BiosStart + 1;
CmpBiosSearchEnd = BiosStart + BiosLength - 2;
}
/* Now loop the BIOS area */
for (;;)
{
/* Start an initial search looking for numbers and periods */
pp = NULL;
while (CmpBiosSearchStart <= CmpBiosSearchEnd)
{
/* Check if we have an "x.y" version string */
if ((*CmpBiosSearchStart == '.') &&
(*(CmpBiosSearchStart + 1) >= '0') &&
(*(CmpBiosSearchStart + 1) <= '9') &&
(*(CmpBiosSearchStart - 1) >= '0') &&
(*(CmpBiosSearchStart - 1) <= '9'))
{
/* Start looking in this area for the actual BIOS Version */
pp = CmpBiosSearchStart;
break;
}
else
{
/* Keep searching */
CmpBiosSearchStart++;
}
}
/* Break out if we're went past the BIOS area */
if (CmpBiosSearchStart > CmpBiosSearchEnd) return FALSE;
/* Move to the next 2 bytes */
CmpBiosSearchStart += 2;
/* Null-terminate our scratch buffer and start the string here */
Buffer[127] = ANSI_NULL;
p = &Buffer[127];
/* Go back one character since we're doing this backwards */
pp--;
/* Loop the identifier we found as long as it's valid */
i = 0;
while ((i++ < 127) &&
(pp >= CmpBiosBegin) &&
(*pp >= ' ') &&
(*pp != '$'))
{
/* Copy the character */
*--p = *pp--;
}
/* Go past the last character since we went backwards */
pp++;
/* Loop the strings we recognize */
for (i = 0; CmpBiosStrings[i]; i++)
{
/* Check if a match was found */
if (strstr(p, CmpBiosStrings[i])) goto Match;
}
}
Match:
/* Skip until we find a space */
for (; *pp == ' '; pp++);
/* Loop the final string */
i = 0;
do
{
/* Copy the character into the final string */
BiosVersion[i] = *pp++;
} while ((++i < 127) &&
(pp <= (CmpBiosSearchEnd + 1)) &&
(*pp >= ' ') &&
(*pp != '$'));
/* Null-terminate the version string */
BiosVersion[i] = ANSI_NULL;
return TRUE;
}
NTSTATUS
NTAPI
CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
UNICODE_STRING KeyName, ValueName, Data, SectionName;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG HavePae, Length, TotalLength = 0, i, Disposition;
SIZE_T ViewSize;
NTSTATUS Status;
HANDLE KeyHandle, BiosHandle, SystemHandle, FpuHandle, SectionHandle;
CONFIGURATION_COMPONENT_DATA ConfigData;
CHAR Buffer[128];
CPU_INFO CpuInfo;
ULONG ExtendedId;
PKPRCB Prcb;
USHORT IndexTable[MaximumType + 1] = {0};
ANSI_STRING TempString;
PCHAR PartialString = NULL, BiosVersion;
CHAR CpuString[48];
PVOID BaseAddress = NULL;
LARGE_INTEGER ViewBase = {{0, 0}};
ULONG_PTR VideoRomBase;
PCHAR CurrentVersion;
extern UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion;
extern UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
/* Open the SMSS Memory Management key */
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\"
L"Control\\Session Manager\\Memory Management");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
/* Detect if PAE is enabled */
HavePae = SharedUserData->ProcessorFeatures[PF_PAE_ENABLED];
/* Set the value */
RtlInitUnicodeString(&ValueName, L"PhysicalAddressExtension");
NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_DWORD,
&HavePae,
sizeof(HavePae));
/* Close the key */
NtClose(KeyHandle);
}
/* Open the hardware description key */
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\Hardware\\Description\\System");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&SystemHandle, KEY_READ | KEY_WRITE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
return Status;
/* Create the BIOS Information key */
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\"
L"Control\\BIOSINFO");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateKey(&BiosHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
&Disposition);
if (!NT_SUCCESS(Status))
{
NtClose(SystemHandle);
return Status;
}
/* Create the CPU Key, and check if it already existed */
RtlInitUnicodeString(&KeyName, L"CentralProcessor");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
SystemHandle,
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
NtClose(KeyHandle);
/* The key shouldn't already exist */
if (Disposition == REG_CREATED_NEW_KEY)
{
/* Allocate the configuration data for cmconfig.c */
CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
CmpConfigurationAreaSize,
TAG_CM);
if (!CmpConfigurationData)
{
// FIXME: Cleanup stuff!!
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Loop all CPUs */
for (i = 0; i < KeNumberProcessors; i++)
{
/* Get the PRCB */
Prcb = KiProcessorBlock[i];
/* Setup the Configuration Entry for the Processor */
RtlZeroMemory(&ConfigData, sizeof(ConfigData));
ConfigData.ComponentEntry.Class = ProcessorClass;
ConfigData.ComponentEntry.Type = CentralProcessor;
ConfigData.ComponentEntry.Key = i;
ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
ConfigData.ComponentEntry.Identifier = Buffer;
/* Check if the CPU doesn't support CPUID */
if (!Prcb->CpuID)
{
/* Build ID1-style string for older CPUs */
sprintf(Buffer,
CmpID1,
Prcb->CpuType,
(Prcb->CpuStep >> 8) + 'A',
Prcb->CpuStep & 0xff);
}
else
{
/* Build ID2-style string for newer CPUs */
sprintf(Buffer,
CmpID2,
Prcb->CpuType,
(Prcb->CpuStep >> 8),
Prcb->CpuStep & 0xff);
}
/* Save the ID string length now that we've created it */
ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1;
/* Initialize the registry configuration node for it */
Status = CmpInitializeRegistryNode(&ConfigData,
SystemHandle,
&KeyHandle,
InterfaceTypeUndefined,
0xFFFFFFFF,
IndexTable);
if (!NT_SUCCESS(Status))
{
NtClose(BiosHandle);
NtClose(SystemHandle);
return Status;
}
/* Check if we have an FPU */
if (KeI386NpxPresent)
{
/* Setup the Configuration Entry for the FPU */
RtlZeroMemory(&ConfigData, sizeof(ConfigData));
ConfigData.ComponentEntry.Class = ProcessorClass;
ConfigData.ComponentEntry.Type = FloatingPointProcessor;
ConfigData.ComponentEntry.Key = i;
ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
ConfigData.ComponentEntry.Identifier = Buffer;
/* For 386 cpus, the CPU pp is the identifier */
if (Prcb->CpuType == 3) strcpy(Buffer, "80387");
/* Save the ID string length now that we've created it */
ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1;
/* Initialize the registry configuration node for it */
Status = CmpInitializeRegistryNode(&ConfigData,
SystemHandle,
&FpuHandle,
InterfaceTypeUndefined,
0xFFFFFFFF,
IndexTable);
if (!NT_SUCCESS(Status))
{
/* We failed, close all the opened handles and return */
NtClose(KeyHandle);
NtClose(BiosHandle);
NtClose(SystemHandle);
return Status;
}
/* Close this new handle */
NtClose(FpuHandle);
/* Stay on this CPU only */
KeSetSystemAffinityThread(Prcb->SetMember);
if (!Prcb->CpuID)
{
/* Uh oh, no CPUID! Should not happen as we don't support 80386 and older 80486 */
ASSERT(FALSE);
}
else
{
/* Check if we have extended CPUID that supports name ID */
KiCpuId(&CpuInfo, 0x80000000);
ExtendedId = CpuInfo.Eax;
if (ExtendedId >= 0x80000004)
{
/* Do all the CPUIDs required to get the full name */
PartialString = CpuString;
for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++)
{
/* Do the CPUID and save the name string */
KiCpuId(&CpuInfo, 0x80000000 | ExtendedId);
((PULONG)PartialString)[0] = CpuInfo.Eax;
((PULONG)PartialString)[1] = CpuInfo.Ebx;
((PULONG)PartialString)[2] = CpuInfo.Ecx;
((PULONG)PartialString)[3] = CpuInfo.Edx;
/* Go to the next name string */
PartialString += 16;
}
/* Null-terminate it */
CpuString[47] = ANSI_NULL;
}
}
/* Go back to user affinity */
KeRevertToUserAffinityThread();
/* Check if we have a CPU Name */
if (PartialString)
{
/* Convert it to Unicode */
RtlInitAnsiString(&TempString, CpuString);
RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
/* Add it to the registry */
RtlInitUnicodeString(&ValueName, L"ProcessorNameString");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
Data.Buffer,
Data.Length + sizeof(UNICODE_NULL));
/* ROS: Save a copy for bugzilla reporting */
RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer);
/* Free the temporary buffer */
RtlFreeUnicodeString(&Data);
}
/* Check if we had a Vendor ID */
if (Prcb->VendorString[0])
{
/* Convert it to Unicode */
RtlInitAnsiString(&TempString, Prcb->VendorString);
RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
/* Add it to the registry */
RtlInitUnicodeString(&ValueName, L"VendorIdentifier");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
Data.Buffer,
Data.Length + sizeof(UNICODE_NULL));
/* Free the temporary buffer */
RtlFreeUnicodeString(&Data);
}
/* Check if we have features bits */
if (Prcb->FeatureBits)
{
/* Add them to the registry */
RtlInitUnicodeString(&ValueName, L"FeatureSet");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_DWORD,
&Prcb->FeatureBits,
sizeof(Prcb->FeatureBits));
}
/* Check if we detected the CPU Speed */
if (Prcb->MHz)
{
/* Add it to the registry */
RtlInitUnicodeString(&ValueName, L"~MHz");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_DWORD,
&Prcb->MHz,
sizeof(Prcb->MHz));
}
/* Check if we have an update signature */
if (Prcb->UpdateSignature.QuadPart)
{
/* Add it to the registry */
RtlInitUnicodeString(&ValueName, L"Update Signature");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_BINARY,
&Prcb->UpdateSignature,
sizeof(Prcb->UpdateSignature));
}
/* Close the processor handle */
NtClose(KeyHandle);
/* FIXME: Detect CPU mismatches */
}
}
/* Free the configuration data */
ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
}
/* Open physical memory */
RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory");
InitializeObjectAttributes(&ObjectAttributes,
&SectionName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenSection(&SectionHandle,
SECTION_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
/* We failed, close all the opened handles and return */
// NtClose(KeyHandle);
NtClose(BiosHandle);
NtClose(SystemHandle);
/* 'Quickie' closes KeyHandle */
goto Quickie;
}
/* Map the first 1KB of memory to get the IVT */
ViewSize = PAGE_SIZE;
Status = ZwMapViewOfSection(SectionHandle,
NtCurrentProcess(),
&BaseAddress,
0,
ViewSize,
&ViewBase,
&ViewSize,
ViewUnmap,
MEM_DOS_LIM,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
/* Assume default */
VideoRomBase = 0xC0000;
}
else
{
/* Calculate the base address from the vector */
VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0;
VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0;
/* Now get to the actual ROM Start and make sure it's not invalid*/
VideoRomBase &= 0xFFFF8000;
if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000;
/* And unmap the section */
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
/* Allocate BIOS Version pp Buffer */
BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM);
/* Setup settings to map the 64K BIOS ROM */
BaseAddress = 0;
ViewSize = 16 * PAGE_SIZE;
ViewBase.LowPart = 0xF0000;
ViewBase.HighPart = 0;
/* Map it */
Status = ZwMapViewOfSection(SectionHandle,
NtCurrentProcess(),
&BaseAddress,
0,
ViewSize,
&ViewBase,
&ViewSize,
ViewUnmap,
MEM_DOS_LIM,
PAGE_READWRITE);
if (NT_SUCCESS(Status))
{
/* Scan the ROM to get the BIOS Date */
if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE))
{
/* Convert it to Unicode */
RtlInitAnsiString(&TempString, Buffer);
RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
/* Write the date into the registry */
RtlInitUnicodeString(&ValueName, L"SystemBiosDate");
Status = NtSetValueKey(SystemHandle,
&ValueName,
0,
REG_SZ,
Data.Buffer,
Data.Length + sizeof(UNICODE_NULL));
/* Free the string */
RtlFreeUnicodeString(&Data);
if (BiosHandle)
{
/* Get the BIOS Date Identifier */
RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16 * PAGE_SIZE - 11), 8);
Buffer[8] = ANSI_NULL;
/* Convert it to unicode */
RtlInitAnsiString(&TempString, Buffer);
Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
if (NT_SUCCESS(Status))
{
/* Save it to the registry */
Status = NtSetValueKey(BiosHandle,
&ValueName,
0,
REG_SZ,
Data.Buffer,
Data.Length + sizeof(UNICODE_NULL));
/* ROS: Save a copy for bugzilla reporting */
RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer);
/* Free the string */
RtlFreeUnicodeString(&Data);
}
/* Close the bios information handle */
NtClose(BiosHandle);
}
}
/* Get the BIOS Version */
if (CmpGetBiosVersion(BaseAddress, 16 * PAGE_SIZE, Buffer))
{
/* Start at the beginning of our buffer */
CurrentVersion = BiosVersion;
do
{
/* Convert to Unicode */
RtlInitAnsiString(&TempString, Buffer);
RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
/* Calculate the length of this string and copy it in */
Length = Data.Length + sizeof(UNICODE_NULL);
RtlMoveMemory(CurrentVersion, Data.Buffer, Length);
/* Free the unicode string */
RtlFreeUnicodeString(&Data);
/* Update the total length and see if we're out of space */
TotalLength += Length;
if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE)
{
/* One more string would push us out, so stop here */
break;
}
/* Go to the next string inside the multi-string buffer */
CurrentVersion += Length;
/* Query the next BIOS Version */
} while (CmpGetBiosVersion(NULL, 0, Buffer));
/* Check if we found any strings at all */
if (TotalLength)
{
/* Add the final null-terminator */
*(PWSTR)CurrentVersion = UNICODE_NULL;
TotalLength += sizeof(UNICODE_NULL);
/* Write the BIOS Version to the registry */
RtlInitUnicodeString(&ValueName, L"SystemBiosVersion");
Status = NtSetValueKey(SystemHandle,
&ValueName,
0,
REG_MULTI_SZ,
BiosVersion,
TotalLength);
/* ROS: Save a copy for bugzilla reporting */
RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion);
}
}
/* Unmap the section */
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
/* Now prepare for Video BIOS Mapping of 32KB */
BaseAddress = 0;
ViewSize = 8 * PAGE_SIZE;
ViewBase.QuadPart = VideoRomBase;
/* Map it */
Status = ZwMapViewOfSection(SectionHandle,
NtCurrentProcess(),
&BaseAddress,
0,
ViewSize,
&ViewBase,
&ViewSize,
ViewUnmap,
MEM_DOS_LIM,
PAGE_READWRITE);
if (NT_SUCCESS(Status))
{
/* Scan the ROM to get the BIOS Date */
if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE))
{
/* Convert it to Unicode */
RtlInitAnsiString(&TempString, Buffer);
RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
/* Write the date into the registry */
RtlInitUnicodeString(&ValueName, L"VideoBiosDate");
Status = NtSetValueKey(SystemHandle,
&ValueName,
0,
REG_SZ,
Data.Buffer,
Data.Length + sizeof(UNICODE_NULL));
/* ROS: Save a copy for bugzilla reporting */
RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer);
/* Free the string */
RtlFreeUnicodeString(&Data);
}
/* Get the Video BIOS Version */
if (CmpGetBiosVersion(BaseAddress, 8 * PAGE_SIZE, Buffer))
{
/* Start at the beginning of our buffer */
CurrentVersion = BiosVersion;
do
{
/* Convert to Unicode */
RtlInitAnsiString(&TempString, Buffer);
RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
/* Calculate the length of this string and copy it in */
Length = Data.Length + sizeof(UNICODE_NULL);
RtlMoveMemory(CurrentVersion, Data.Buffer, Length);
/* Free the unicode string */
RtlFreeUnicodeString(&Data);
/* Update the total length and see if we're out of space */
TotalLength += Length;
if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE)
{
/* One more string would push us out, so stop here */
break;
}
/* Go to the next string inside the multi-string buffer */
CurrentVersion += Length;
/* Query the next BIOS Version */
} while (CmpGetBiosVersion(NULL, 0, Buffer));
/* Check if we found any strings at all */
if (TotalLength)
{
/* Add the final null-terminator */
*(PWSTR)CurrentVersion = UNICODE_NULL;
TotalLength += sizeof(UNICODE_NULL);
/* Write the BIOS Version to the registry */
RtlInitUnicodeString(&ValueName, L"VideoBiosVersion");
Status = NtSetValueKey(SystemHandle,
&ValueName,
0,
REG_MULTI_SZ,
BiosVersion,
TotalLength);
/* ROS: Save a copy for bugzilla reporting */
RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion);
}
}
/* Unmap the section */
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
/* Close the section */
ZwClose(SectionHandle);
/* Free the BIOS version string buffer */
if (BiosVersion) ExFreePoolWithTag(BiosVersion, TAG_CM);
Quickie:
/* Close the processor handle */
NtClose(KeyHandle);
return STATUS_SUCCESS;
}