reactos/ntoskrnl/config/i386/cmhardwr.c
2023-04-05 03:33:41 +02:00

897 lines
32 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 CmpFullCpuID = "%s 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++)
{
#ifdef _M_AMD64
PCHAR FamilyId;
#endif
/* 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;
#if defined(_M_IX86)
/* Check if the CPU doesn't support CPUID */
if (!Prcb->CpuID)
{
/* Build 80x86-style string for older CPUs */
sprintf(Buffer,
"80%u86-%c%x",
Prcb->CpuType,
(Prcb->CpuStep >> 8) + 'A',
Prcb->CpuStep & 0xff);
}
else
{
/* Build full ID string for newer CPUs */
sprintf(Buffer,
CmpFullCpuID,
"x86",
Prcb->CpuType,
(Prcb->CpuStep >> 8),
Prcb->CpuStep & 0xff);
}
#elif defined(_M_AMD64)
if (Prcb->CpuVendor == CPU_VIA)
{
/* This is VIA64 family */
FamilyId = "VIA64";
}
else if (Prcb->CpuVendor == CPU_AMD)
{
/* This is AMD64 family */
FamilyId = "AMD64";
}
else
{
/* This is generic EM64T family */
FamilyId = "EM64T";
}
/* ID string has the same style for all 64-bit CPUs */
sprintf(Buffer,
CmpFullCpuID,
FamilyId,
Prcb->CpuType,
(Prcb->CpuStep >> 8),
Prcb->CpuStep & 0xff);
#else
#error Unknown architecture
#endif
/* 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);
if (NT_SUCCESS(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 Jira reporting */
if (!RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer))
{
/* Do not fail for this */
KeRosProcessorName.Length = 0;
}
/* 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);
if (NT_SUCCESS(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);
if (NT_SUCCESS(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 Jira reporting */
if (!RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer))
KeRosBiosDate.Length = 0;
/* 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);
Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE);
if (!NT_SUCCESS(Status))
break;
/* 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 Jira reporting */
if (!RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion))
KeRosBiosVersion.Length = 0;
}
}
/* 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);
if (NT_SUCCESS(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 Jira reporting */
if (!RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer))
KeRosVideoBiosDate.Length = 0;
/* 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);
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE)))
break;
/* 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 Jira reporting */
if (!RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion))
KeRosVideoBiosVersion.Length = 0;
}
}
/* 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;
}