2020-09-30 17:12:29 +02:00

1013 lines
26 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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"
//
// Title Index is set to 0.
// (from ..\cmconfig.c)
//
#define TITLE_INDEX_VALUE 0
extern PCHAR SearchStrings[];
extern PCHAR BiosBegin;
extern PCHAR Start;
extern PCHAR End;
extern UCHAR CmpID1[];
extern UCHAR CmpID2[];
extern WCHAR CmpVendorID[];
extern WCHAR CmpFeatureBits[];
extern WCHAR CmpMHz[];
extern WCHAR CmpUpdateSignature[];
extern UCHAR CmpCyrixID[];
//
// Bios date and version definitions
//
#define BIOS_DATE_LENGTH 9
#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
extern ULONG CmpConfigurationAreaSize;
extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
BOOLEAN
CmpGetBiosVersion (
PCHAR SearchArea,
ULONG SearchLength,
PCHAR VersionString
);
BOOLEAN
CmpGetBiosDate (
PCHAR SearchArea,
ULONG SearchLength,
PCHAR DateString
);
ULONG
Ke386CyrixId (
VOID
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpGetBiosDate)
#pragma alloc_text(INIT,CmpGetBiosVersion)
#pragma alloc_text(INIT,CmpInitializeMachineDependentConfiguration)
#endif
BOOLEAN
CmpGetBiosDate (
PCHAR SearchArea,
ULONG SearchLength,
PCHAR DateString
)
/*++
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.
--*/
{
BOOLEAN FoundFlag = TRUE; // Set to TRUE if the item was found
CHAR PrevDate[BIOS_DATE_LENGTH]; // Date currently being examined
CHAR CurrDate[BIOS_DATE_LENGTH]; // Date currently being examined
PCHAR String;
USHORT i; // Looping variable
USHORT Length; // Number of characters to move
PCHAR Start = SearchArea + 2;
PCHAR End = SearchArea + SearchLength - 5;
//
// Clear out the previous date
//
RtlZeroMemory(PrevDate, BIOS_DATE_LENGTH);
while (FoundFlag) {
String = NULL;
//
// Search for '/' with a digit on either side and another
// '/' 3 character away.
//
while (Start < End) {
if (*Start == '/' && *(Start+3) == '/' &&
(*(Start+1) <= '9' && *(Start+1) >= '0') &&
(*(Start-1) <= '9' && *(Start-1) >= '0') &&
(*(Start+5) <= '9' && *(Start+5) >= '0') &&
(*(Start+4) <= '9' && *(Start+4) >= '0') &&
(*(Start+2) <= '9' && *(Start+2) >= '0')) {
String = Start;
break;
} else {
Start++;
}
}
if (String) {
Start = String + 3;
String -= 2; // Move String to the beginning of
// date.
//
// Copy the year into CurrDate
//
CurrDate[0] = String[6];
CurrDate[1] = String[7];
CurrDate[2] = '/'; // The 1st "/" for YY/MM/DD
//
// Copy the month & day into CurrDate
// (Process properly if this is a one digit month)
//
if (*String > '9' || *String < '0') {
CurrDate[3] = '0';
String++;
i = 4;
Length = 4;
} else {
i = 3;
Length = 5;
}
RtlMoveMemory(&CurrDate[i], String, Length);
//
// Compare the dates, to see which is more recent
//
if (memcmp (PrevDate, CurrDate, BIOS_DATE_LENGTH - 1) < 0) {
RtlMoveMemory(PrevDate, CurrDate, BIOS_DATE_LENGTH - 1);
}
} else {
FoundFlag = FALSE;
}
}
//
// If we did not find a date
//
if (PrevDate[0] == '\0') {
DateString[0] = '\0';
return (FALSE);
}
//
// Put the date from chPrevDate's YY/MM/DD format
// into pchDateString's MM/DD/YY format
DateString[5] = '/';
DateString[6] = PrevDate[0];
DateString[7] = PrevDate[1];
RtlMoveMemory(DateString, &PrevDate[3], 5);
DateString[8] = '\0';
return (TRUE);
}
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);
}
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;
PUCHAR VendorID;
UCHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH];
PKPRCB Prcb;
ULONG i, Junk;
ULONG VersionsLength = 0, Length;
PCHAR VersionStrings, VersionPointer;
UNICODE_STRING SectionName;
ULONG ViewSize;
LARGE_INTEGER ViewBase;
PVOID BaseAddress;
HANDLE SectionHandle;
UCHAR DeviceIndexTable[NUMBER_TYPES];
for (i = 0; i < NUMBER_TYPES; i++) {
DeviceIndexTable[i] = 0;
}
InitializeObjectAttributes( &ObjectAttributes,
&CmRegistryMachineHardwareDescriptionSystemName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenKey( &ParentHandle,
KEY_READ,
&ObjectAttributes
);
if (!NT_SUCCESS(Status)) {
// Something is really wrong...
return Status;
}
//
// 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,
TITLE_INDEX_VALUE,
&CmClassName[ProcessorClass],
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
);
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 = 1 << 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 = 1 << 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 (!Prcb->CpuID) {
//
// Test for Cyrix processor
//
if (Ke386CyrixId ()) {
VendorID = CmpCyrixID;
}
}
//
// Restore thread's affinity to all processors
//
KeRevertToUserAffinityThread();
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);
}
ExFreePool((PVOID)CmpConfigurationData);
}
//
// Next we try to collect System BIOS date and version strings.
// BUGBUG This code should be moved to ntdetect.com after product 1.
//
//
// 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)) {
//
// 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);
}
if (VersionStrings && CmpGetBiosVersion(BaseAddress, SYSTEM_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);
RtlMoveMemory(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);
//
// 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);
}
//
// 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)) {
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);
RtlMoveMemory(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...
//
return STATUS_SUCCESS;
}