mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
897 lines
32 KiB
C
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;
|
|
}
|