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.
719 lines
20 KiB
719 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1990, 1991 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
cmconfig.c
|
|
|
|
Abstract:
|
|
|
|
This module is responsible to build the hardware tree of the
|
|
registry data base.
|
|
|
|
Author:
|
|
|
|
Shie-Lin Tzong (shielint) 23-Jan-1992
|
|
|
|
|
|
Environment:
|
|
|
|
Kernel mode.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "cmp.h"
|
|
|
|
//
|
|
// Title Index - Never used for Product 1, set to 0 for now.
|
|
//
|
|
|
|
#define TITLE_INDEX_VALUE 0
|
|
|
|
|
|
extern ULONG CmpTypeCount[];
|
|
|
|
|
|
#define EISA_ADAPTER_INDEX EisaAdapter
|
|
#define TURBOCHANNEL_ADAPTER_INDEX TcAdapter
|
|
|
|
//
|
|
// The following variables are used to cross-reference multifunction
|
|
// adapters to their corresponding NT interface type.
|
|
//
|
|
|
|
extern struct {
|
|
PUCHAR AscString;
|
|
USHORT InterfaceType;
|
|
USHORT Count;
|
|
} CmpMultifunctionTypes[];
|
|
|
|
extern USHORT CmpUnknownBusCount;
|
|
|
|
|
|
//
|
|
// CmpConfigurationData - A pointer to the area reserved for the purpose
|
|
// of reconstructing Configuration Data.
|
|
//
|
|
// CmpConfigurationAreaSize - Record the size of the Configuration Data
|
|
// area.
|
|
|
|
extern ULONG CmpConfigurationAreaSize;
|
|
extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
|
|
|
|
//
|
|
// Function prototypes for internal erferences
|
|
//
|
|
|
|
NTSTATUS
|
|
CmpSetupConfigurationTree(
|
|
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
|
|
IN HANDLE ParentHandle,
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,CmpInitializeHardwareConfiguration)
|
|
#pragma alloc_text(INIT,CmpSetupConfigurationTree)
|
|
#pragma alloc_text(INIT,CmpInitializeRegistryNode)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
CmpInitializeHardwareConfiguration(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates \\Registry\Machine\Hardware node in
|
|
the registry and calls SetupTree routine to put the hardware
|
|
information to 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;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE BaseHandle;
|
|
PCONFIGURATION_COMPONENT_DATA ConfigurationRoot;
|
|
ULONG Disposition;
|
|
|
|
ConfigurationRoot = (PCONFIGURATION_COMPONENT_DATA)LoaderBlock->ConfigurationRoot;
|
|
|
|
//
|
|
// Create \\Registry\Machine\Hardware\DeviceMap
|
|
//
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&CmRegistryMachineHardwareDeviceMapName,
|
|
0,
|
|
(HANDLE)NULL,
|
|
NULL
|
|
);
|
|
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
|
|
|
|
Status = NtCreateKey( // Paht may already exist
|
|
&BaseHandle,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObjectAttributes,
|
|
TITLE_INDEX_VALUE,
|
|
NULL,
|
|
0,
|
|
&Disposition
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
NtClose(BaseHandle);
|
|
|
|
ASSERT(Disposition == REG_CREATED_NEW_KEY);
|
|
|
|
//
|
|
// Create \\Registry\Machine\Hardware\Description and use the
|
|
// returned handle as the BaseHandle to build the hardware tree.
|
|
//
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&CmRegistryMachineHardwareDescriptionName,
|
|
0,
|
|
(HANDLE)NULL,
|
|
NULL
|
|
);
|
|
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
|
|
|
|
Status = NtCreateKey( // Path may already exist
|
|
&BaseHandle,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObjectAttributes,
|
|
TITLE_INDEX_VALUE,
|
|
NULL,
|
|
0,
|
|
&Disposition
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
ASSERT(Disposition == REG_CREATED_NEW_KEY);
|
|
|
|
//
|
|
// Allocate 16K bytes memory from paged pool for constructing
|
|
// configuration data for controller component.
|
|
// NOTE: The configuration Data for controller component
|
|
// usually takes less than 100 bytes. But on EISA machine, the
|
|
// EISA configuration information takes more than 10K and up to
|
|
// 64K. I believe 16K is the reasonable number to handler 99.9%
|
|
// of the machines. Therefore, 16K is the initial value.
|
|
//
|
|
|
|
CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
|
|
PagedPool,
|
|
CmpConfigurationAreaSize
|
|
);
|
|
|
|
if (CmpConfigurationData == NULL) {
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
//
|
|
// Call SetupConfigurationTree routine to go over each component
|
|
// of the tree and add component information to registry database.
|
|
//
|
|
|
|
if (ConfigurationRoot) {
|
|
Status = CmpSetupConfigurationTree(ConfigurationRoot,
|
|
BaseHandle,
|
|
-1,
|
|
(ULONG)-1);
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
ExFreePool((PVOID)CmpConfigurationData);
|
|
NtClose(BaseHandle);
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
CmpSetupConfigurationTree(
|
|
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
|
|
IN HANDLE ParentHandle,
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine traverses loader configuration tree and register
|
|
the hardware information to the registry data base.
|
|
|
|
Note to reduce the stack usage on machines with large number of PCI buses,
|
|
we do not recursively process the sibling nodes. We only recursively
|
|
process the child trees.
|
|
|
|
Arguments:
|
|
|
|
CurrentEntry - Supplies a pointer to a loader configuration
|
|
tree or subtree.
|
|
|
|
ParentHandle - Supplies the parent handle of CurrentEntry node.
|
|
|
|
InterfaceType - Specify the Interface type of the bus that the
|
|
CurrentEntry component resides.
|
|
|
|
BusNumber - Specify the Bus Number of the bus that the CurrentEntry
|
|
component resides. If Bus number is -1, it means InterfaceType
|
|
and BusNumber are meaningless for this component.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE NewHandle;
|
|
USHORT i;
|
|
CONFIGURATION_COMPONENT *Component;
|
|
INTERFACE_TYPE LocalInterfaceType = InterfaceType;
|
|
ULONG LocalBusNumber = BusNumber;
|
|
USHORT DeviceIndexTable[NUMBER_TYPES];
|
|
|
|
for (i = 0; i < NUMBER_TYPES; i++) {
|
|
DeviceIndexTable[i] = 0;
|
|
}
|
|
|
|
//
|
|
// Process current entry and its siblings
|
|
//
|
|
|
|
while (CurrentEntry) {
|
|
|
|
//
|
|
// Register current entry first before going down to its children
|
|
//
|
|
|
|
Component = &CurrentEntry->ComponentEntry;
|
|
|
|
//
|
|
// If the current component is a bus component, we will set up
|
|
// its bus number and Interface type and use them to initialize
|
|
// its subtree.
|
|
//
|
|
|
|
if (Component->Class == AdapterClass &&
|
|
CurrentEntry->Parent->ComponentEntry.Class == SystemClass) {
|
|
|
|
switch (Component->Type) {
|
|
|
|
case EisaAdapter:
|
|
LocalInterfaceType = Eisa;
|
|
LocalBusNumber = CmpTypeCount[EISA_ADAPTER_INDEX]++;
|
|
break;
|
|
case TcAdapter:
|
|
LocalInterfaceType = TurboChannel;
|
|
LocalBusNumber = CmpTypeCount[TURBOCHANNEL_ADAPTER_INDEX]++;
|
|
break;
|
|
case MultiFunctionAdapter:
|
|
|
|
//
|
|
// Here we try to distinguish if the Multifunction adapter is
|
|
// Isa, Mca, Internal bus and assign BusNumber based on
|
|
// its interface type (bus type.)
|
|
//
|
|
|
|
if (Component->Identifier) {
|
|
for (i=0; CmpMultifunctionTypes[i].AscString; i++) {
|
|
if (_stricmp((PCHAR)CmpMultifunctionTypes[i].AscString,
|
|
Component->Identifier) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
LocalInterfaceType = CmpMultifunctionTypes[i].InterfaceType;
|
|
LocalBusNumber = CmpMultifunctionTypes[i].Count++;
|
|
}
|
|
break;
|
|
|
|
case ScsiAdapter:
|
|
|
|
//
|
|
// Set the bus type to internal.
|
|
//
|
|
|
|
LocalInterfaceType = Internal;
|
|
LocalBusNumber = CmpTypeCount[ScsiAdapter]++;
|
|
break;
|
|
|
|
default:
|
|
LocalInterfaceType = -1;
|
|
LocalBusNumber = CmpUnknownBusCount++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize and copy current component to hardware registry
|
|
//
|
|
|
|
Status = CmpInitializeRegistryNode(
|
|
CurrentEntry,
|
|
ParentHandle,
|
|
&NewHandle,
|
|
LocalInterfaceType,
|
|
LocalBusNumber,
|
|
DeviceIndexTable
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Once we are going one level down, we need to clear the TypeCount
|
|
// table for everything under the current component class ...
|
|
//
|
|
|
|
if (CurrentEntry->Child) {
|
|
|
|
//
|
|
// Process the child entry of current entry
|
|
//
|
|
|
|
Status = CmpSetupConfigurationTree(CurrentEntry->Child,
|
|
NewHandle,
|
|
LocalInterfaceType,
|
|
LocalBusNumber
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(NewHandle);
|
|
return(Status);
|
|
}
|
|
}
|
|
NtClose(NewHandle);
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
}
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CmpInitializeRegistryNode(
|
|
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
|
|
IN HANDLE ParentHandle,
|
|
OUT PHANDLE NewHandle,
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN PUSHORT DeviceIndexTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a node for the current firmware component
|
|
and puts component data to the data part of the node.
|
|
|
|
Arguments:
|
|
|
|
CurrentEntry - Supplies a pointer to a configuration component.
|
|
|
|
Handle - Supplies the parent handle of CurrentEntry node.
|
|
|
|
NewHandle - Suppiles a pointer to a HANDLE to receive the handle of
|
|
the newly created node.
|
|
|
|
InterfaceType - Specify the Interface type of the bus that the
|
|
CurrentEntry component resides. (See BusNumber also)
|
|
|
|
BusNumber - Specify the Bus Number of the bus that the CurrentEntry
|
|
component resides on. If Bus number is -1, it means InterfaceType
|
|
and BusNumber are meaningless for this component.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
UNICODE_STRING ValueData;
|
|
HANDLE Handle;
|
|
HANDLE OldHandle;
|
|
ANSI_STRING AnsiString;
|
|
CHAR Buffer[12];
|
|
WCHAR UnicodeBuffer[12];
|
|
CONFIGURATION_COMPONENT *Component;
|
|
ULONG Disposition;
|
|
ULONG ConfigurationDataLength = 0;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR NewArea;
|
|
|
|
Component = &CurrentEntry->ComponentEntry;
|
|
|
|
//
|
|
// If the component class is SystemClass, we set its Type to be
|
|
// ArcSystem. The reason is because the detection code sets
|
|
// its type to MaximumType to indicate it is NOT ARC compatible.
|
|
// Here, we are only interested in building a System Node. So we
|
|
// change its Type to ArcSystem to ease the setup.
|
|
//
|
|
|
|
if (Component->Class == SystemClass) {
|
|
Component->Type = ArcSystem;
|
|
}
|
|
|
|
//
|
|
// Create a new key to describe the Component.
|
|
//
|
|
// The type of the component will be used as the keyname of the
|
|
// registry node. The class is the class of the component.
|
|
//
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&(CmTypeName[Component->Type]),
|
|
0,
|
|
ParentHandle,
|
|
NULL
|
|
);
|
|
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
|
|
|
|
Status = NtCreateKey( // Paht may already exist
|
|
&Handle,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&Disposition
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// If this component is NOT a SystemClass component, we will
|
|
// create a subkey to identify the component's ordering.
|
|
//
|
|
|
|
if (Component->Class != SystemClass) {
|
|
|
|
RtlIntegerToChar(
|
|
DeviceIndexTable[Component->Type]++,
|
|
10,
|
|
12,
|
|
Buffer
|
|
);
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
Buffer
|
|
);
|
|
|
|
KeyName.Buffer = (PWSTR)UnicodeBuffer;
|
|
KeyName.Length = 0;
|
|
KeyName.MaximumLength = sizeof(UnicodeBuffer);
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&KeyName,
|
|
&AnsiString,
|
|
FALSE
|
|
);
|
|
|
|
OldHandle = Handle;
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
0,
|
|
OldHandle,
|
|
NULL
|
|
);
|
|
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
|
|
|
|
Status = NtCreateKey(
|
|
&Handle,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&Disposition
|
|
);
|
|
|
|
NtClose(OldHandle);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
ASSERT(Disposition == REG_CREATED_NEW_KEY);
|
|
}
|
|
|
|
//
|
|
// Create a value which describes the following component information:
|
|
// Flags, Cersion, Key, AffinityMask.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"Component Information"
|
|
);
|
|
|
|
Status = NtSetValueKey(
|
|
Handle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_BINARY,
|
|
&Component->Flags,
|
|
FIELD_OFFSET(CONFIGURATION_COMPONENT, ConfigurationDataLength) -
|
|
FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags)
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(Handle);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Create a value which describes the component identifier, if any.
|
|
//
|
|
|
|
if (Component->IdentifierLength) {
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"Identifier"
|
|
);
|
|
|
|
RtlInitAnsiString(
|
|
&AnsiString,
|
|
Component->Identifier
|
|
);
|
|
|
|
Status = RtlAnsiStringToUnicodeString(
|
|
&ValueData,
|
|
&AnsiString,
|
|
TRUE
|
|
);
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
Status = NtSetValueKey(
|
|
Handle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
ValueData.Buffer,
|
|
ValueData.Length + sizeof( UNICODE_NULL )
|
|
);
|
|
|
|
RtlFreeUnicodeString(&ValueData);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(Handle);
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a value entry for component configuration data.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"Configuration Data"
|
|
);
|
|
|
|
//
|
|
// Create the configuration data based on CM_FULL_RESOURCE_DESCRIPTOR.
|
|
//
|
|
// Note the configuration data in firmware tree may be in the form of
|
|
// CM_PARTIAL_RESOURCE_LIST or nothing. In both cases, we need to
|
|
// set up the registry configuration data to be in the form of
|
|
// CM_FULL_RESOURCE_DESCRIPTOR.
|
|
//
|
|
|
|
if (CurrentEntry->ConfigurationData) {
|
|
|
|
//
|
|
// This component has configuration data, we copy the data
|
|
// to our work area, add some more data items and copy the new
|
|
// configuration data to the registry.
|
|
//
|
|
|
|
ConfigurationDataLength = Component->ConfigurationDataLength +
|
|
FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
|
|
PartialResourceList);
|
|
|
|
//
|
|
// Make sure our reserved area is big enough to hold the data.
|
|
//
|
|
|
|
if (ConfigurationDataLength > CmpConfigurationAreaSize) {
|
|
|
|
//
|
|
// If reserved area is not big enough, we resize our reserved
|
|
// area. If, unfortunately, the reallocation fails, we simply
|
|
// loss the configuration data of this particular component.
|
|
//
|
|
|
|
NewArea = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
|
|
PagedPool,
|
|
ConfigurationDataLength
|
|
);
|
|
|
|
if (NewArea) {
|
|
CmpConfigurationAreaSize = ConfigurationDataLength;
|
|
ExFreePool(CmpConfigurationData);
|
|
CmpConfigurationData = NewArea;
|
|
RtlCopyMemory(
|
|
(PUCHAR)&CmpConfigurationData->PartialResourceList.Version,
|
|
CurrentEntry->ConfigurationData,
|
|
Component->ConfigurationDataLength
|
|
);
|
|
} else {
|
|
Component->ConfigurationDataLength = 0;
|
|
CurrentEntry->ConfigurationData = NULL;
|
|
}
|
|
} else {
|
|
RtlCopyMemory(
|
|
(PUCHAR)&CmpConfigurationData->PartialResourceList.Version,
|
|
CurrentEntry->ConfigurationData,
|
|
Component->ConfigurationDataLength
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
if (CurrentEntry->ConfigurationData == NULL) {
|
|
|
|
//
|
|
// This component has NO configuration data (or we can't resize
|
|
// our reserved area to hold the data), we simple add whatever
|
|
// is required to set up a CM_FULL_RESOURCE_LIST.
|
|
//
|
|
|
|
CmpConfigurationData->PartialResourceList.Version = 0;
|
|
CmpConfigurationData->PartialResourceList.Revision = 0;
|
|
CmpConfigurationData->PartialResourceList.Count = 0;
|
|
ConfigurationDataLength = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
|
|
PartialResourceList) +
|
|
FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
|
|
PartialDescriptors);
|
|
}
|
|
|
|
//
|
|
// Set up InterfaceType and BusNumber for the component.
|
|
//
|
|
|
|
CmpConfigurationData->InterfaceType = InterfaceType;
|
|
CmpConfigurationData->BusNumber = BusNumber;
|
|
|
|
//
|
|
// Write the newly constructed configuration data to the hardware registry
|
|
//
|
|
|
|
Status = NtSetValueKey(
|
|
Handle,
|
|
&ValueName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_FULL_RESOURCE_DESCRIPTOR,
|
|
CmpConfigurationData,
|
|
ConfigurationDataLength
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(Handle);
|
|
return(Status);
|
|
}
|
|
|
|
*NewHandle = Handle;
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|