mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1636 lines
42 KiB
1636 lines
42 KiB
//depot/Lab01_N/base/ntos/config/i386/init386.c#4 - edit change 6794 (text)
|
|
/*++
|
|
|
|
Copyright (c) 1990, 1991 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
init386.c
|
|
|
|
Abstract:
|
|
|
|
This module is responsible to build any x86 specific entries in
|
|
the hardware tree of registry.
|
|
|
|
Author:
|
|
|
|
Ken Reneris (kenr) 04-Aug-1992
|
|
|
|
|
|
Environment:
|
|
|
|
Kernel mode.
|
|
|
|
Revision History:
|
|
|
|
shielint - add BIOS date and version detection.
|
|
|
|
--*/
|
|
|
|
#include "cmp.h"
|
|
#include "stdio.h"
|
|
#include "acpitabl.h"
|
|
#include "ntacpi.h"
|
|
#include "rules.h"
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
#include "string.h"
|
|
#include "stdlib.h"
|
|
#include "ntverp.h"
|
|
#endif
|
|
|
|
|
|
typedef struct _ACPI_BIOS_INFORMATION {
|
|
ULONG BootArchitecture;
|
|
ULONG PreferredProfile;
|
|
ULONG Capabilities;
|
|
} ACPI_BIOS_INFORMATION, *PACPI_BIOS_INFORMATION;
|
|
//
|
|
// Title Index is set to 0.
|
|
// (from ..\cmconfig.c)
|
|
//
|
|
|
|
#define TITLE_INDEX_VALUE 0
|
|
|
|
extern const PCHAR SearchStrings[];
|
|
extern PCHAR BiosBegin;
|
|
extern PCHAR Start;
|
|
extern PCHAR End;
|
|
extern const UCHAR CmpID1[];
|
|
extern const UCHAR CmpID2[];
|
|
extern const WCHAR CmpVendorID[];
|
|
extern const WCHAR CmpProcessorNameString[];
|
|
extern const WCHAR CmpFeatureBits[];
|
|
extern const WCHAR CmpMHz[];
|
|
extern const WCHAR CmpUpdateSignature[];
|
|
extern const WCHAR CmPhysicalAddressExtension[];
|
|
|
|
#if !defined(_AMD64_)
|
|
extern const UCHAR CmpCyrixID[];
|
|
#endif
|
|
|
|
extern const UCHAR CmpIntelID[];
|
|
extern const UCHAR CmpAmdID[];
|
|
|
|
//
|
|
// Bios date and version definitions
|
|
//
|
|
|
|
#define BIOS_DATE_LENGTH 11
|
|
#define MAXIMUM_BIOS_VERSION_LENGTH 128
|
|
#define SYSTEM_BIOS_START 0xF0000
|
|
#define SYSTEM_BIOS_LENGTH 0x10000
|
|
#define INT10_VECTOR 0x10
|
|
#define VIDEO_BIOS_START 0xC0000
|
|
#define VIDEO_BIOS_LENGTH 0x8000
|
|
#define VERSION_DATA_LENGTH PAGE_SIZE
|
|
|
|
//
|
|
// Extended CPUID function definitions
|
|
//
|
|
|
|
#define CPUID_PROCESSOR_NAME_STRING_SZ 49
|
|
#define CPUID_EXTFN_BASE 0x80000000
|
|
#define CPUID_EXTFN_PROCESSOR_NAME 0x80000002
|
|
|
|
//
|
|
// CPU Stepping mismatch.
|
|
//
|
|
|
|
UCHAR CmProcessorMismatch;
|
|
|
|
#define CM_PROCESSOR_MISMATCH_VENDOR 0x01
|
|
#define CM_PROCESSOR_MISMATCH_STEPPING 0x02
|
|
#define CM_PROCESSOR_MISMATCH_L2 0x04
|
|
|
|
|
|
extern ULONG CmpConfigurationAreaSize;
|
|
extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
|
|
|
|
|
|
BOOLEAN
|
|
CmpGetBiosVersion (
|
|
PCHAR SearchArea,
|
|
ULONG SearchLength,
|
|
PCHAR VersionString
|
|
);
|
|
|
|
BOOLEAN
|
|
CmpGetAcpiBiosVersion(
|
|
PCHAR VersionString
|
|
);
|
|
|
|
BOOLEAN
|
|
CmpGetBiosDate (
|
|
PCHAR SearchArea,
|
|
ULONG SearchLength,
|
|
PCHAR DateString,
|
|
BOOLEAN SystemBiosDate
|
|
);
|
|
|
|
BOOLEAN
|
|
CmpGetAcpiBiosInformation(
|
|
PACPI_BIOS_INFORMATION AcpiBiosInformation
|
|
);
|
|
|
|
ULONG
|
|
Ke386CyrixId (
|
|
VOID
|
|
);
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
|
|
VOID
|
|
CmpPerformMachineIdentification(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
#endif
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,CmpGetBiosDate)
|
|
#pragma alloc_text(INIT,CmpGetBiosVersion)
|
|
#pragma alloc_text(INIT,CmpGetAcpiBiosVersion)
|
|
#pragma alloc_text(INIT,CmpGetAcpiBiosInformation)
|
|
#pragma alloc_text(INIT,CmpInitializeMachineDependentConfiguration)
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
#pragma alloc_text(INIT,CmpPerformMachineIdentification)
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if defined(_AMD64_)
|
|
|
|
#define KeI386NpxPresent TRUE
|
|
|
|
VOID
|
|
__inline
|
|
CPUID (
|
|
ULONG InEax,
|
|
PULONG OutEax,
|
|
PULONG OutEbx,
|
|
PULONG OutEcx,
|
|
PULONG OutEdx
|
|
)
|
|
{
|
|
CPU_INFO cpuInfo;
|
|
|
|
KiCpuId (InEax, &cpuInfo);
|
|
|
|
*OutEax = cpuInfo.Eax;
|
|
*OutEbx = cpuInfo.Ebx;
|
|
*OutEcx = cpuInfo.Ecx;
|
|
*OutEdx = cpuInfo.Edx;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
BOOLEAN
|
|
CmpGetBiosDate (
|
|
PCHAR SearchArea,
|
|
ULONG SearchLength,
|
|
PCHAR DateString,
|
|
BOOLEAN SystemBiosDate
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds the most recent date in the computer/video
|
|
card's ROM. When GetRomDate encounters a datae, it checks the
|
|
previously found date to see if the new date is more recent.
|
|
|
|
Arguments:
|
|
|
|
SearchArea - the area to search for a date.
|
|
|
|
SearchLength - Length of search.
|
|
|
|
DateString - Supplies a pointer to a fixed length memory to receive
|
|
the date string.
|
|
|
|
Return Value:
|
|
|
|
NT_SUCCESS if a date is found.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR prevDate[BIOS_DATE_LENGTH]; // Newest date found so far (CCYY/MM/DD)
|
|
CHAR currDate[BIOS_DATE_LENGTH]; // Date currently being examined (CCYY/MM/DD)
|
|
PCHAR start; // Start of the current search area.
|
|
PCHAR end; // End of the search area.
|
|
ULONG year; // YY
|
|
ULONG month; // MM
|
|
ULONG day; // DD
|
|
ULONG count;
|
|
|
|
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
|
|
|
//
|
|
// Initialize previous date
|
|
//
|
|
|
|
RtlZeroMemory(prevDate, BIOS_DATE_LENGTH);
|
|
|
|
//
|
|
// We need to look ahead 5 characters to determine the
|
|
// validity of the date pattern.
|
|
//
|
|
|
|
start = SearchArea + 2;
|
|
end = SearchArea + SearchLength - 5;
|
|
|
|
//
|
|
// Process the entire search area.
|
|
//
|
|
|
|
while (start < end) {
|
|
|
|
//
|
|
// We consider the following byte pattern as a potential date.
|
|
// We are assuming the following date pattern Month/Day/Year.
|
|
// "n/nn/nn" where n is any digit. We allow month to be single
|
|
// digit only.
|
|
//
|
|
|
|
if ( start[0] == '/' && start[3] == '/' &&
|
|
IS_DIGIT(*(start - 1)) &&
|
|
IS_DIGIT(start[1]) && IS_DIGIT(start[2]) &&
|
|
IS_DIGIT(start[4]) && IS_DIGIT(start[5])) {
|
|
|
|
//
|
|
// Copy MM/DD part into the currDate.
|
|
//
|
|
|
|
RtlMoveMemory(&currDate[5], start - 2, 5);
|
|
|
|
//
|
|
// Handle single digit month correctly.
|
|
//
|
|
|
|
if (!IS_DIGIT(currDate[5])) {
|
|
currDate[5] = '0';
|
|
}
|
|
|
|
//
|
|
// Copy the year YY into currDate
|
|
//
|
|
|
|
currDate[2] = start[4];
|
|
currDate[3] = start[5];
|
|
currDate[4] = currDate[7] = currDate[10] = '\0';
|
|
|
|
//
|
|
// Do basic validation for the date.
|
|
// Only one field (YY) can be 0.
|
|
// Only one field (YY) can be greater than 31.
|
|
// We assume the ROM date to be in the format MM/DD/YY.
|
|
//
|
|
|
|
year = strtoul(&currDate[2], NULL, 16);
|
|
month = strtoul(&currDate[5], NULL, 16);
|
|
day = strtoul(&currDate[8], NULL, 16);
|
|
|
|
//
|
|
// Count the number of fields that are 0.
|
|
//
|
|
|
|
count = ((day == 0)? 1 : 0) + ((month == 0)? 1 : 0) + ((year == 0)? 1 : 0);
|
|
if (count <= 1) {
|
|
|
|
//
|
|
// Count number of field that are greater than 31.
|
|
//
|
|
|
|
count = ((day > 0x31)? 1 : 0) + ((month > 0x31)? 1 : 0) + ((year > 0x31)? 1 : 0);
|
|
if (count <= 1) {
|
|
|
|
//
|
|
// See if the ROM already has a 4 digit date. We do this only for System ROM
|
|
// since they have a consistent date format.
|
|
//
|
|
|
|
if (SystemBiosDate && IS_DIGIT(start[6]) && IS_DIGIT(start[7]) &&
|
|
(memcmp(&start[4], "19", 2) == 0 || memcmp(&start[4], "20", 2) == 0)) {
|
|
|
|
currDate[0] = start[4];
|
|
currDate[1] = start[5];
|
|
currDate[2] = start[6];
|
|
currDate[3] = start[7];
|
|
|
|
} else {
|
|
|
|
//
|
|
// Internally, we treat year as a 4 digit quantity
|
|
// for comparison to determine the newest date.
|
|
// We treat year YY < 80 as 20YY, otherwise 19YY.
|
|
//
|
|
|
|
if (year < 0x80) {
|
|
currDate[0] = '2';
|
|
currDate[1] = '0';
|
|
} else {
|
|
currDate[0] = '1';
|
|
currDate[1] = '9';
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the '/' delimiters into the date.
|
|
//
|
|
|
|
currDate[4] = currDate[7] = '/';
|
|
|
|
//
|
|
// Compare the dates, and save the newer one.
|
|
//
|
|
|
|
if (memcmp (prevDate, currDate, BIOS_DATE_LENGTH - 1) < 0) {
|
|
RtlMoveMemory(prevDate, currDate, BIOS_DATE_LENGTH - 1);
|
|
}
|
|
|
|
//
|
|
// Next search should start at the second '/'.
|
|
//
|
|
|
|
start += 2;
|
|
}
|
|
}
|
|
}
|
|
start++;
|
|
}
|
|
|
|
if (prevDate[0] != '\0') {
|
|
|
|
//
|
|
// Convert from the internal CCYY/MM/DD format to
|
|
// return MM/DD//YY format.
|
|
//
|
|
|
|
RtlMoveMemory(DateString, &prevDate[5], 5);
|
|
DateString[5] = '/';
|
|
DateString[6] = prevDate[2];
|
|
DateString[7] = prevDate[3];
|
|
DateString[8] = '\0';
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
//
|
|
// If we did not find a date, return an empty string.
|
|
//
|
|
|
|
DateString[0] = '\0';
|
|
return (FALSE);
|
|
}
|
|
|
|
BOOLEAN
|
|
CmpGetBiosVersion (
|
|
PCHAR SearchArea,
|
|
ULONG SearchLength,
|
|
PCHAR VersionString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds the version number stored in ROM, if any.
|
|
|
|
Arguments:
|
|
|
|
SearchArea - the area to search for the version.
|
|
|
|
SearchLength - Length of search
|
|
|
|
VersionString - Supplies a pointer to a fixed length memory to receive
|
|
the version string.
|
|
|
|
Return Value:
|
|
|
|
TRUE if a version number is found. Else a value of FALSE is returned.
|
|
|
|
--*/
|
|
{
|
|
PCHAR String;
|
|
USHORT Length;
|
|
USHORT i;
|
|
CHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH];
|
|
PCHAR BufferPointer;
|
|
|
|
if (SearchArea != NULL) {
|
|
|
|
//
|
|
// If caller does not specify the search area, we will search
|
|
// the area left from previous search.
|
|
//
|
|
|
|
BiosBegin = SearchArea;
|
|
Start = SearchArea + 1;
|
|
End = SearchArea + SearchLength - 2;
|
|
}
|
|
|
|
while (1) {
|
|
|
|
//
|
|
// Search for a period with a digit on either side
|
|
//
|
|
|
|
String = NULL;
|
|
while (Start <= End) {
|
|
if (*Start == '.' && *(Start+1) >= '0' && *(Start+1) <= '9' &&
|
|
*(Start-1) >= '0' && *(Start-1) <= '9') {
|
|
String = Start;
|
|
break;
|
|
} else {
|
|
Start++;
|
|
}
|
|
}
|
|
|
|
if (Start > End) {
|
|
return(FALSE);
|
|
} else {
|
|
Start += 2;
|
|
}
|
|
|
|
Length = 0;
|
|
Buffer[MAXIMUM_BIOS_VERSION_LENGTH - 1] = '\0';
|
|
BufferPointer = &Buffer[MAXIMUM_BIOS_VERSION_LENGTH - 1];
|
|
|
|
//
|
|
// Search for the beginning of the string
|
|
//
|
|
|
|
String--;
|
|
while (Length < MAXIMUM_BIOS_VERSION_LENGTH - 8 &&
|
|
String >= BiosBegin &&
|
|
*String >= ' ' && *String <= 127 &&
|
|
*String != '$') {
|
|
--BufferPointer;
|
|
*BufferPointer = *String;
|
|
--String, ++Length;
|
|
}
|
|
++String;
|
|
|
|
//
|
|
// Can one of the search strings be found
|
|
//
|
|
|
|
for (i = 0; SearchStrings[i]; i++) {
|
|
if (strstr(BufferPointer, SearchStrings[i])) {
|
|
goto Found;
|
|
}
|
|
}
|
|
}
|
|
|
|
Found:
|
|
|
|
//
|
|
// Skip leading white space
|
|
//
|
|
|
|
for (; *String == ' '; ++String)
|
|
;
|
|
|
|
//
|
|
// Copy the string to user supplied buffer
|
|
//
|
|
|
|
for (i = 0; i < MAXIMUM_BIOS_VERSION_LENGTH - 1 &&
|
|
String <= (End + 1) &&
|
|
*String >= ' ' && *String <= 127 && *String != '$';
|
|
++i, ++String) {
|
|
VersionString[i] = *String;
|
|
}
|
|
VersionString[i] = '\0';
|
|
return (TRUE);
|
|
}
|
|
|
|
BOOLEAN
|
|
CmpGetAcpiBiosVersion(
|
|
PCHAR VersionString
|
|
)
|
|
{
|
|
ULONG length;
|
|
PDESCRIPTION_HEADER header;
|
|
ULONG i;
|
|
|
|
header = CmpFindACPITable(RSDT_SIGNATURE, &length);
|
|
if (header) {
|
|
|
|
for (i = 0; i < 6 && header->OEMID[i]; i++) {
|
|
|
|
*VersionString++ = header->OEMID[i];
|
|
}
|
|
sprintf(VersionString, " - %x", header->OEMRevision);
|
|
|
|
//
|
|
// Unmap the table
|
|
//
|
|
MmUnmapIoSpace(header, length );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
CmpGetAcpiBiosInformation(
|
|
PACPI_BIOS_INFORMATION AcpiBiosInformation
|
|
)
|
|
{
|
|
ULONG length;
|
|
PFADT fadt;
|
|
BOOLEAN result;
|
|
|
|
AcpiBiosInformation->BootArchitecture = 0;
|
|
AcpiBiosInformation->Capabilities = 0;
|
|
AcpiBiosInformation->PreferredProfile = 0;
|
|
fadt = (PFADT)CmpFindACPITable(FADT_SIGNATURE, &length);
|
|
if (fadt) {
|
|
|
|
//
|
|
// Information is valid only for ACPI version > 1.0
|
|
//
|
|
|
|
if (fadt->Header.Revision > 1) {
|
|
|
|
AcpiBiosInformation->BootArchitecture = fadt->boot_arch;
|
|
AcpiBiosInformation->Capabilities = fadt->flags;
|
|
AcpiBiosInformation->PreferredProfile = fadt->pm_profile;
|
|
}
|
|
|
|
result = (fadt->Header.Revision > 1)? TRUE : FALSE;
|
|
|
|
//
|
|
// Unmap the table
|
|
//
|
|
|
|
MmUnmapIoSpace(fadt, length);
|
|
|
|
return result;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
CmpInitializeMachineDependentConfiguration(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates x86 specific entries in the registry.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
|
|
OS Loader.
|
|
|
|
Returns:
|
|
|
|
NTSTATUS code for sucess or reason of failure.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG VideoBiosStart;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
UNICODE_STRING ValueData;
|
|
ANSI_STRING AnsiString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
ULONG Disposition;
|
|
HANDLE ParentHandle;
|
|
HANDLE BaseHandle, NpxHandle;
|
|
HANDLE CurrentControlSet;
|
|
CONFIGURATION_COMPONENT_DATA CurrentEntry;
|
|
UCHAR const* VendorID;
|
|
UCHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH];
|
|
PKPRCB Prcb;
|
|
ULONG i, Junk;
|
|
ULONG VersionsLength = 0, Length;
|
|
PCHAR VersionStrings, VersionPointer;
|
|
UNICODE_STRING SectionName;
|
|
SIZE_T ViewSize;
|
|
LARGE_INTEGER ViewBase;
|
|
PVOID BaseAddress;
|
|
HANDLE SectionHandle;
|
|
USHORT DeviceIndexTable[NUMBER_TYPES];
|
|
ULONG CpuIdFunction;
|
|
ULONG MaxExtFn;
|
|
PULONG NameString = NULL;
|
|
ULONG P0L2Size = 0;
|
|
ULONG ThisProcessorL2Size;
|
|
struct {
|
|
union {
|
|
UCHAR Bytes[CPUID_PROCESSOR_NAME_STRING_SZ];
|
|
ULONG DWords[1];
|
|
} u;
|
|
} ProcessorNameString;
|
|
ULONG VersionPass;
|
|
ACPI_BIOS_INFORMATION AcpiBiosInformation;
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
HANDLE BiosInfo;
|
|
#endif
|
|
|
|
|
|
for (i = 0; i < NUMBER_TYPES; i++) {
|
|
DeviceIndexTable[i] = 0;
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&CmRegistryMachineSystemCurrentControlSetControlSessionManagerMemoryManagement,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenKey( &BaseHandle,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
ULONG paeEnabled;
|
|
|
|
if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] == FALSE) {
|
|
paeEnabled = 0;
|
|
} else {
|
|
paeEnabled = 1;
|
|
}
|
|
|
|
RtlInitUnicodeString( &ValueName,
|
|
CmPhysicalAddressExtension );
|
|
|
|
|
|
NtSetValueKey( BaseHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_DWORD,
|
|
&paeEnabled,
|
|
sizeof(paeEnabled) );
|
|
|
|
NtClose( BaseHandle );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&CmRegistryMachineHardwareDescriptionSystemName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtCreateKey( &ParentHandle,
|
|
KEY_READ,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
// Something is really wrong...
|
|
return Status;
|
|
}
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&CmRegistryMachineSystemCurrentControlSetControlBiosInfo,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtCreateKey( &BiosInfo,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&Disposition
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
// Something is really wrong...
|
|
return Status;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// On an ARC machine the processor(s) are included in the hardware
|
|
// configuration passed in from bootup. Since there's no standard
|
|
// way to get all the ARC information for each processor in an MP
|
|
// machine via pc-ROMs the information will be added here (if it's
|
|
// not already present).
|
|
//
|
|
|
|
RtlInitUnicodeString( &KeyName,
|
|
L"CentralProcessor"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
0,
|
|
ParentHandle,
|
|
NULL
|
|
);
|
|
|
|
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
|
|
|
|
Status = NtCreateKey(
|
|
&BaseHandle,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&Disposition
|
|
);
|
|
|
|
NtClose (BaseHandle);
|
|
|
|
if (Disposition == REG_CREATED_NEW_KEY) {
|
|
|
|
//
|
|
// The ARC rom didn't add the processor(s) into the registry.
|
|
// Do it now.
|
|
//
|
|
|
|
CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
|
|
PagedPool,
|
|
CmpConfigurationAreaSize
|
|
);
|
|
|
|
//
|
|
// if (CmpConfigurationData == 0) {
|
|
// <do something useful>
|
|
// Note: we don't actually use it so it doesn't matter for now
|
|
// since it isn't used until the free. go figure.
|
|
// }
|
|
//
|
|
|
|
for (i=0; i < (ULONG)KeNumberProcessors; i++) {
|
|
Prcb = KiProcessorBlock[i];
|
|
|
|
RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry);
|
|
CurrentEntry.ComponentEntry.Class = ProcessorClass;
|
|
CurrentEntry.ComponentEntry.Type = CentralProcessor;
|
|
CurrentEntry.ComponentEntry.Key = i;
|
|
CurrentEntry.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
|
|
|
|
CurrentEntry.ComponentEntry.Identifier = Buffer;
|
|
if (Prcb->CpuID == 0) {
|
|
|
|
//
|
|
// Old style stepping format
|
|
//
|
|
|
|
sprintf (Buffer, CmpID1,
|
|
Prcb->CpuType,
|
|
(Prcb->CpuStep >> 8) + 'A',
|
|
Prcb->CpuStep & 0xff
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// New style stepping format
|
|
//
|
|
|
|
sprintf (Buffer, CmpID2,
|
|
Prcb->CpuType,
|
|
(Prcb->CpuStep >> 8),
|
|
Prcb->CpuStep & 0xff
|
|
);
|
|
}
|
|
|
|
CurrentEntry.ComponentEntry.IdentifierLength =
|
|
strlen (Buffer) + 1;
|
|
|
|
Status = CmpInitializeRegistryNode(
|
|
&CurrentEntry,
|
|
ParentHandle,
|
|
&BaseHandle,
|
|
-1,
|
|
(ULONG)-1,
|
|
DeviceIndexTable
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
|
|
if (KeI386NpxPresent) {
|
|
RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry);
|
|
CurrentEntry.ComponentEntry.Class = ProcessorClass;
|
|
CurrentEntry.ComponentEntry.Type = FloatingPointProcessor;
|
|
CurrentEntry.ComponentEntry.Key = i;
|
|
CurrentEntry.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
|
|
|
|
CurrentEntry.ComponentEntry.Identifier = Buffer;
|
|
|
|
if (Prcb->CpuType == 3) {
|
|
|
|
//
|
|
// 386 processors have 387's installed, else
|
|
// use processor identifier as the NPX identifier
|
|
//
|
|
|
|
strcpy (Buffer, "80387");
|
|
}
|
|
|
|
CurrentEntry.ComponentEntry.IdentifierLength =
|
|
strlen (Buffer) + 1;
|
|
|
|
Status = CmpInitializeRegistryNode(
|
|
&CurrentEntry,
|
|
ParentHandle,
|
|
&NpxHandle,
|
|
-1,
|
|
(ULONG)-1,
|
|
DeviceIndexTable
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(BaseHandle);
|
|
return(Status);
|
|
}
|
|
|
|
NtClose(NpxHandle);
|
|
}
|
|
|
|
//
|
|
// If processor supports Cpu Indentification then
|
|
// go obtain that information for the registry
|
|
//
|
|
|
|
VendorID = Prcb->CpuID ? Prcb->VendorString : NULL;
|
|
|
|
//
|
|
// Move to target processor and get other related
|
|
// processor information for the registery
|
|
//
|
|
|
|
KeSetSystemAffinityThread(Prcb->SetMember);
|
|
|
|
#if !defined(_AMD64_)
|
|
if (!Prcb->CpuID) {
|
|
|
|
//
|
|
// Test for Cyrix processor
|
|
//
|
|
|
|
if (Ke386CyrixId ()) {
|
|
VendorID = CmpCyrixID;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
|
|
//
|
|
// If this processor has extended CPUID functions, get
|
|
// the ProcessorNameString. Although the Intel books
|
|
// say that for CpuID functions > than the valued
|
|
// returned for function 0 will return undefined results,
|
|
// we have a guarantee from Intel that that result will
|
|
// never have the highest order bit set. This enables
|
|
// us to determine if the extended functions are supported
|
|
// by issuing CpuID function 0x80000000.
|
|
//
|
|
// Note: It is not known that this is true for all x86
|
|
// clones. If/when we find exceptions we will support
|
|
// them. In the mean time we are asking the clone makers
|
|
// to guarantee this behavior.
|
|
//
|
|
|
|
CPUID(CPUID_EXTFN_BASE, &MaxExtFn, &Junk, &Junk, &Junk);
|
|
|
|
if (MaxExtFn >= (CPUID_EXTFN_PROCESSOR_NAME + 2)) {
|
|
|
|
//
|
|
// This processor supports extended CPUID functions
|
|
// up to and (at least) including processor name string.
|
|
//
|
|
// Each CPUID call for the processor name string will
|
|
// return 16 bytes, 48 bytes in all, zero terminated.
|
|
//
|
|
|
|
NameString = &ProcessorNameString.u.DWords[0];
|
|
|
|
for (CpuIdFunction = CPUID_EXTFN_PROCESSOR_NAME;
|
|
CpuIdFunction <= (CPUID_EXTFN_PROCESSOR_NAME+2);
|
|
CpuIdFunction++) {
|
|
|
|
CPUID(CpuIdFunction,
|
|
NameString,
|
|
NameString + 1,
|
|
NameString + 2,
|
|
NameString + 3);
|
|
NameString += 4;
|
|
}
|
|
|
|
//
|
|
// Enforce 0 byte terminator.
|
|
//
|
|
|
|
ProcessorNameString.u.Bytes[CPUID_PROCESSOR_NAME_STRING_SZ-1] = 0;
|
|
}
|
|
}
|
|
|
|
ThisProcessorL2Size = KeGetPcr()->SecondLevelCacheSize;
|
|
|
|
//
|
|
// Restore thread's affinity to all processors
|
|
//
|
|
|
|
KeRevertToUserAffinityThread();
|
|
|
|
if (NameString) {
|
|
|
|
//
|
|
// Add Processor Name String to the registery
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
CmpProcessorNameString
|
|
);
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
ProcessorNameString.u.Bytes
|
|
);
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&ValueData,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
BaseHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
ValueData.Buffer,
|
|
ValueData.Length + sizeof( UNICODE_NULL )
|
|
);
|
|
|
|
RtlFreeUnicodeString(&ValueData);
|
|
}
|
|
|
|
if (VendorID) {
|
|
|
|
//
|
|
// Add Vendor Indentifier to the registery
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
CmpVendorID
|
|
);
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
VendorID
|
|
);
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&ValueData,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
BaseHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
ValueData.Buffer,
|
|
ValueData.Length + sizeof( UNICODE_NULL )
|
|
);
|
|
|
|
RtlFreeUnicodeString(&ValueData);
|
|
}
|
|
|
|
if (Prcb->FeatureBits) {
|
|
//
|
|
// Add processor feature bits to the registery
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
CmpFeatureBits
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
BaseHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_DWORD,
|
|
&Prcb->FeatureBits,
|
|
sizeof (Prcb->FeatureBits)
|
|
);
|
|
}
|
|
|
|
if (Prcb->MHz) {
|
|
//
|
|
// Add processor MHz to the registery
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
CmpMHz
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
BaseHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_DWORD,
|
|
&Prcb->MHz,
|
|
sizeof (Prcb->MHz)
|
|
);
|
|
}
|
|
|
|
if (Prcb->UpdateSignature.QuadPart) {
|
|
//
|
|
// Add processor MHz to the registery
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
CmpUpdateSignature
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
BaseHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_BINARY,
|
|
&Prcb->UpdateSignature,
|
|
sizeof (Prcb->UpdateSignature)
|
|
);
|
|
}
|
|
|
|
NtClose(BaseHandle);
|
|
|
|
//
|
|
// Check processor steppings.
|
|
//
|
|
|
|
if (i == 0) {
|
|
|
|
P0L2Size = ThisProcessorL2Size;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Check all processors against processor 0. Compare
|
|
// CPUID supported,
|
|
// Vendor ID String
|
|
// Family and Stepping
|
|
// L2 cache size.
|
|
//
|
|
|
|
if (Prcb->CpuID) {
|
|
if (strcmp(Prcb->VendorString,
|
|
KiProcessorBlock[0]->VendorString)) {
|
|
CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_VENDOR;
|
|
}
|
|
if (ThisProcessorL2Size != P0L2Size) {
|
|
CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_L2;
|
|
}
|
|
if ((Prcb->CpuType != KiProcessorBlock[0]->CpuType) ||
|
|
(Prcb->CpuStep != KiProcessorBlock[0]->CpuStep)) {
|
|
CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_STEPPING;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// If this processor doesn't support CPUID, P0
|
|
// shouldn't support it either.
|
|
//
|
|
|
|
if (KiProcessorBlock[0]->CpuID) {
|
|
CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_STEPPING;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 != CmpConfigurationData) {
|
|
ExFreePool((PVOID)CmpConfigurationData);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Next we try to collect System BIOS date and version strings.
|
|
//
|
|
|
|
//
|
|
// Open a physical memory section to map in physical memory.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&SectionName,
|
|
L"\\Device\\PhysicalMemory"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&SectionName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL
|
|
);
|
|
|
|
Status = ZwOpenSection(
|
|
&SectionHandle,
|
|
SECTION_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// If fail, forget the bios data and version
|
|
//
|
|
|
|
goto AllDone;
|
|
}
|
|
|
|
//
|
|
// Examine the first page of physical memory for int 10 segment
|
|
// address.
|
|
//
|
|
|
|
BaseAddress = 0;
|
|
ViewSize = 0x1000;
|
|
ViewBase.LowPart = 0;
|
|
ViewBase.HighPart = 0;
|
|
|
|
Status =ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
VideoBiosStart = VIDEO_BIOS_START;
|
|
} else {
|
|
VideoBiosStart = (*((PULONG)BaseAddress + INT10_VECTOR) & 0xFFFF0000) >> 12;
|
|
VideoBiosStart += (*((PULONG)BaseAddress + INT10_VECTOR) & 0x0000FFFF);
|
|
VideoBiosStart &= 0xffff8000;
|
|
if (VideoBiosStart < VIDEO_BIOS_START) {
|
|
VideoBiosStart = VIDEO_BIOS_START;
|
|
}
|
|
Status = ZwUnmapViewOfSection(
|
|
NtCurrentProcess(),
|
|
BaseAddress
|
|
);
|
|
}
|
|
|
|
VersionStrings = ExAllocatePool(PagedPool, VERSION_DATA_LENGTH);
|
|
BaseAddress = 0;
|
|
ViewSize = SYSTEM_BIOS_LENGTH;
|
|
ViewBase.LowPart = SYSTEM_BIOS_START;
|
|
ViewBase.HighPart = 0;
|
|
|
|
Status =ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (CmpGetBiosDate(BaseAddress, SYSTEM_BIOS_LENGTH, Buffer, TRUE)) {
|
|
|
|
//
|
|
// Convert ascii date string to unicode string and
|
|
// store it in registry.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"SystemBiosDate"
|
|
);
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
Buffer
|
|
);
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&ValueData,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
ParentHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
ValueData.Buffer,
|
|
ValueData.Length + sizeof( UNICODE_NULL )
|
|
);
|
|
|
|
RtlFreeUnicodeString(&ValueData);
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
|
|
memcpy(Buffer, (PCHAR)BaseAddress + 0xFFF5, 8);
|
|
Buffer[8] = '\0';
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
Buffer
|
|
);
|
|
|
|
Status = RtlAnsiStringToUnicodeString(
|
|
&ValueData,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
Status = NtSetValueKey(
|
|
BiosInfo,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
ValueData.Buffer,
|
|
ValueData.Length + sizeof( UNICODE_NULL )
|
|
);
|
|
|
|
RtlFreeUnicodeString(&ValueData);
|
|
}
|
|
|
|
NtClose (BiosInfo);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if ((VersionPointer = VersionStrings) != NULL) {
|
|
|
|
//
|
|
// Try to detect ALL the possible BIOS version strings.
|
|
//
|
|
|
|
for (VersionPass = 0; ; VersionPass++) {
|
|
|
|
if (VersionPass == 0) {
|
|
|
|
//
|
|
// First try to get the version from ACPI tables.
|
|
//
|
|
|
|
if (!CmpGetAcpiBiosVersion(Buffer)) {
|
|
|
|
//
|
|
// This is a non-ACPI system.
|
|
//
|
|
continue;
|
|
}
|
|
} else {
|
|
|
|
if (!CmpGetBiosVersion((VersionPass == 1)? BaseAddress : NULL, (VersionPass == 1)? SYSTEM_BIOS_LENGTH : 0, Buffer)) {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert to unicode strings and copy them to our
|
|
// VersionStrings buffer.
|
|
//
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
Buffer
|
|
);
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&ValueData,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
Length = ValueData.Length + sizeof(UNICODE_NULL);
|
|
RtlCopyMemory(VersionPointer,
|
|
ValueData.Buffer,
|
|
Length
|
|
);
|
|
VersionsLength += Length;
|
|
RtlFreeUnicodeString(&ValueData);
|
|
if (VersionsLength + (MAXIMUM_BIOS_VERSION_LENGTH +
|
|
sizeof(UNICODE_NULL)) * 2 > PAGE_SIZE) {
|
|
break;
|
|
}
|
|
VersionPointer += Length;
|
|
}
|
|
|
|
//
|
|
// If we found any version string, write it to the registry.
|
|
//
|
|
|
|
if (VersionsLength != 0) {
|
|
|
|
//
|
|
// Append a UNICODE_NULL to the end of VersionStrings
|
|
//
|
|
|
|
*(PWSTR)VersionPointer = UNICODE_NULL;
|
|
VersionsLength += sizeof(UNICODE_NULL);
|
|
|
|
//
|
|
// If any version string is found, we set up a ValueName and
|
|
// initialize its value to the string(s) we found.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"SystemBiosVersion"
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
ParentHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_MULTI_SZ,
|
|
VersionStrings,
|
|
VersionsLength
|
|
);
|
|
}
|
|
}
|
|
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
|
}
|
|
|
|
//
|
|
// Get system information like SealedCaseSystem, LegacyFreeSystem etc from
|
|
// the BIOS.
|
|
//
|
|
if (CmpGetAcpiBiosInformation(&AcpiBiosInformation)) {
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"BootArchitecture"
|
|
);
|
|
|
|
NtSetValueKey(
|
|
ParentHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_DWORD,
|
|
&AcpiBiosInformation.BootArchitecture,
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"PreferredProfile"
|
|
);
|
|
|
|
NtSetValueKey(
|
|
ParentHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_DWORD,
|
|
&AcpiBiosInformation.PreferredProfile,
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"Capabilities"
|
|
);
|
|
|
|
NtSetValueKey(
|
|
ParentHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_DWORD,
|
|
&AcpiBiosInformation.Capabilities,
|
|
sizeof(ULONG)
|
|
);
|
|
}
|
|
|
|
//
|
|
// Next we try to collect Video BIOS date and version strings.
|
|
//
|
|
|
|
BaseAddress = 0;
|
|
ViewSize = VIDEO_BIOS_LENGTH;
|
|
ViewBase.LowPart = VideoBiosStart;
|
|
ViewBase.HighPart = 0;
|
|
|
|
Status =ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (CmpGetBiosDate(BaseAddress, VIDEO_BIOS_LENGTH, Buffer, FALSE)) {
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"VideoBiosDate"
|
|
);
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
Buffer
|
|
);
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&ValueData,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
ParentHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
ValueData.Buffer,
|
|
ValueData.Length + sizeof( UNICODE_NULL )
|
|
);
|
|
|
|
RtlFreeUnicodeString(&ValueData);
|
|
}
|
|
|
|
if (VersionStrings && CmpGetBiosVersion(BaseAddress, VIDEO_BIOS_LENGTH, Buffer)) {
|
|
VersionPointer = VersionStrings;
|
|
do {
|
|
|
|
//
|
|
// Try to detect ALL the possible BIOS version strings.
|
|
// Convert them to unicode strings and copy them to our
|
|
// VersionStrings buffer.
|
|
//
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
Buffer
|
|
);
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&ValueData,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
Length = ValueData.Length + sizeof(UNICODE_NULL);
|
|
RtlCopyMemory(VersionPointer,
|
|
ValueData.Buffer,
|
|
Length
|
|
);
|
|
VersionsLength += Length;
|
|
RtlFreeUnicodeString(&ValueData);
|
|
if (VersionsLength + (MAXIMUM_BIOS_VERSION_LENGTH +
|
|
sizeof(UNICODE_NULL)) * 2 > PAGE_SIZE) {
|
|
break;
|
|
}
|
|
VersionPointer += Length;
|
|
} while (CmpGetBiosVersion(NULL, 0, Buffer));
|
|
|
|
if (VersionsLength != 0) {
|
|
|
|
//
|
|
// Append a UNICODE_NULL to the end of VersionStrings
|
|
//
|
|
|
|
*(PWSTR)VersionPointer = UNICODE_NULL;
|
|
VersionsLength += sizeof(UNICODE_NULL);
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"VideoBiosVersion"
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
ParentHandle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_MULTI_SZ,
|
|
VersionStrings,
|
|
VersionsLength
|
|
);
|
|
}
|
|
}
|
|
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
|
}
|
|
ZwClose(SectionHandle);
|
|
if (VersionStrings) {
|
|
ExFreePool((PVOID)VersionStrings);
|
|
}
|
|
|
|
AllDone:
|
|
|
|
NtClose (ParentHandle);
|
|
|
|
//
|
|
// Add any other x86 specific code here...
|
|
//
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
|
|
//
|
|
// Do machine identification.
|
|
//
|
|
|
|
CmpPerformMachineIdentification(LoaderBlock);
|
|
|
|
#endif
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
|
|
VOID
|
|
CmpPerformMachineIdentification(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
{
|
|
ULONG majorVersion;
|
|
ULONG minorVersion;
|
|
CHAR versionBuffer[64];
|
|
PCHAR major;
|
|
PCHAR minor;
|
|
ULONG minSize;
|
|
|
|
major = strcpy(versionBuffer, VER_PRODUCTVERSION_STR);
|
|
minor = strchr(major, '.');
|
|
majorVersion = atoi(major);
|
|
if( minor != NULL ) {
|
|
*minor++ = '\0';
|
|
minorVersion = atoi(minor);
|
|
} else {
|
|
minorVersion = 0;
|
|
}
|
|
if ( LoaderBlock->Extension->MajorVersion > majorVersion ||
|
|
(LoaderBlock->Extension->MajorVersion == majorVersion &&
|
|
LoaderBlock->Extension->MinorVersion >= minorVersion)) {
|
|
|
|
minSize = FIELD_OFFSET(LOADER_PARAMETER_EXTENSION, InfFileSize) + sizeof(ULONG);
|
|
if (LoaderBlock->Extension && LoaderBlock->Extension->Size >= minSize) {
|
|
|
|
if (LoaderBlock->Extension->InfFileImage && LoaderBlock->Extension->InfFileSize) {
|
|
|
|
CmpMatchInfList(
|
|
LoaderBlock->Extension->InfFileImage,
|
|
LoaderBlock->Extension->InfFileSize,
|
|
"MachineDescription"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|