reactos/ntoskrnl/config/cmconfig.c
Timo Kreuzer 71fefa32db
[NDK][NTOS] Add global definition of INIT_FUNCTION/INIT_SECTION (#779)
* Add an NDK header to define INIT_FUNCTION/INIT_SECTION globally
* Use _declspec(allocate(x)) and _declspec(code_seg(x)) on MSVC versions that support it
* Use INIT_FUNCTION on functions only and INIT_SECTION on data only (required by MSVC)
* Place INIT_FUNCTION before the return type (required by MSVC)
* Make sure declarations and implementations share the same modifiers (required by MSVC)
* Add a global linker option to suppress warnings about defined but unused INIT section
* Merge INIT section into .text in freeldr
2018-12-30 12:19:11 +01:00

413 lines
14 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/config/cmconfig.c
* PURPOSE: Configuration Manager - System Configuration Routines
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "ntoskrnl.h"
#define NDEBUG
#include "debug.h"
/* FUNCTIONS *****************************************************************/
INIT_FUNCTION
NTSTATUS
NTAPI
CmpInitializeRegistryNode(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
IN HANDLE NodeHandle,
OUT PHANDLE NewHandle,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN PUSHORT DeviceIndexTable)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName, ValueName, ValueData;
HANDLE KeyHandle, ParentHandle;
ANSI_STRING TempString;
CHAR TempBuffer[12];
WCHAR Buffer[12];
PCONFIGURATION_COMPONENT Component;
ULONG Disposition, Length = 0;
/* Get the component */
Component = &CurrentEntry->ComponentEntry;
/* Set system class components to ARC system type */
if (Component->Class == SystemClass) Component->Type = ArcSystem;
/* Create a key for the component */
InitializeObjectAttributes(&ObjectAttributes,
&CmTypeName[Component->Type],
OBJ_CASE_INSENSITIVE,
NodeHandle,
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if (!NT_SUCCESS(Status)) return Status;
/* Check if this is anything but a system class component */
if (Component->Class != SystemClass)
{
/* Build the sub-component string */
RtlIntegerToChar(DeviceIndexTable[Component->Type]++,
10,
12,
TempBuffer);
RtlInitAnsiString(&TempString, TempBuffer);
/* Convert it to Unicode */
RtlInitEmptyUnicodeString(&KeyName, Buffer, sizeof(Buffer));
Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
if (!NT_SUCCESS(Status))
{
NtClose(KeyHandle);
return Status;
}
/* Create the key */
ParentHandle = KeyHandle;
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
ParentHandle,
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
NtClose(ParentHandle);
/* Fail if the key couldn't be created, and make sure it's a new key */
if (!NT_SUCCESS(Status)) return Status;
ASSERT(Disposition == REG_CREATED_NEW_KEY);
}
/* Setup the component information key */
RtlInitUnicodeString(&ValueName, L"Component Information");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_BINARY,
&Component->Flags,
FIELD_OFFSET(CONFIGURATION_COMPONENT,
ConfigurationDataLength) -
FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags));
if (!NT_SUCCESS(Status))
{
/* Fail */
NtClose(KeyHandle);
return Status;
}
/* Check if we have an identifier */
if (Component->IdentifierLength)
{
/* Build the string and convert it to Unicode */
RtlInitUnicodeString(&ValueName, L"Identifier");
RtlInitAnsiString(&TempString, Component->Identifier);
Status = RtlAnsiStringToUnicodeString(&ValueData,
&TempString,
TRUE);
if (NT_SUCCESS(Status))
{
/* Save the identifier in the registry */
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
ValueData.Buffer,
ValueData.Length + sizeof(UNICODE_NULL));
RtlFreeUnicodeString(&ValueData);
}
/* Check for failure during conversion or registry write */
if (!NT_SUCCESS(Status))
{
/* Fail */
NtClose(KeyHandle);
return Status;
}
}
/* Setup the configuration data string */
RtlInitUnicodeString(&ValueName, L"Configuration Data");
/* Check if we got configuration data */
if (CurrentEntry->ConfigurationData)
{
/* Calculate the total length and check if it fits into our buffer */
Length = Component->ConfigurationDataLength +
FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
if (Length > CmpConfigurationAreaSize)
{
ASSERTMSG("Component too large -- need reallocation!\n", FALSE);
}
else
{
/* Copy the data */
RtlCopyMemory(&CmpConfigurationData->PartialResourceList.Version,
CurrentEntry->ConfigurationData,
Component->ConfigurationDataLength);
}
}
else
{
/* No configuration data, setup defaults */
CmpConfigurationData->PartialResourceList.Version = 0;
CmpConfigurationData->PartialResourceList.Revision = 0;
CmpConfigurationData->PartialResourceList.Count = 0;
Length = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
}
/* Set the interface type and bus number */
CmpConfigurationData->InterfaceType = InterfaceType;
CmpConfigurationData->BusNumber = BusNumber;
/* Save the actual data */
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_FULL_RESOURCE_DESCRIPTOR,
CmpConfigurationData,
Length);
if (!NT_SUCCESS(Status))
{
/* Fail */
NtClose(KeyHandle);
}
else
{
/* Return the new handle */
*NewHandle = KeyHandle;
}
/* Return status */
return Status;
}
INIT_FUNCTION
NTSTATUS
NTAPI
CmpSetupConfigurationTree(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
IN HANDLE ParentHandle,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber)
{
PCONFIGURATION_COMPONENT Component;
USHORT DeviceIndexTable[MaximumType + 1] = {0};
ULONG Interface = InterfaceType, Bus = BusNumber, i;
NTSTATUS Status;
HANDLE NewHandle;
/* Loop each entry */
while (CurrentEntry)
{
/* Check if this is an adapter */
Component = &CurrentEntry->ComponentEntry;
if ((Component->Class == AdapterClass) &&
(CurrentEntry->Parent->ComponentEntry.Class == SystemClass))
{
/* Check what kind of adapter it is */
switch (Component->Type)
{
/* EISA */
case EisaAdapter:
{
/* Fixup information */
Interface = Eisa;
Bus = CmpTypeCount[EisaAdapter]++;
break;
}
/* Turbo-channel */
case TcAdapter:
{
/* Fixup information */
Interface = TurboChannel;
Bus = CmpTypeCount[TurboChannel]++;
break;
}
/* ISA, PCI, etc busses */
case MultiFunctionAdapter:
{
/* Check if we have an identifier */
if (Component->Identifier)
{
/* Loop each multi-function adapter type */
for (i = 0; CmpMultifunctionTypes[i].Identifier; i++)
{
/* Check for a name match */
if (!_stricmp(CmpMultifunctionTypes[i].Identifier,
Component->Identifier))
{
/* Match found */
break;
}
}
/* Fix up information */
Interface = CmpMultifunctionTypes[i].InterfaceType;
Bus = CmpMultifunctionTypes[i].Count++;
}
break;
}
/* SCSI Bus */
case ScsiAdapter:
{
/* Fix up */
Interface = Internal;
Bus = CmpTypeCount[ScsiAdapter]++;
break;
}
/* Unknown */
default:
{
Interface = -1;
Bus = CmpUnknownBusCount++;
break;
}
}
}
/* Dump information on the component */
/* Setup the hardware node */
Status = CmpInitializeRegistryNode(CurrentEntry,
ParentHandle,
&NewHandle,
Interface,
Bus,
DeviceIndexTable);
if (!NT_SUCCESS(Status)) return Status;
/* Check for children */
if (CurrentEntry->Child)
{
/* Recurse child */
Status = CmpSetupConfigurationTree(CurrentEntry->Child,
NewHandle,
Interface,
Bus);
if (!NT_SUCCESS(Status))
{
/* Fail */
NtClose(NewHandle);
return Status;
}
}
/* Get to the next entry */
NtClose(NewHandle);
CurrentEntry = CurrentEntry->Sibling;
}
/* We're done */
return STATUS_SUCCESS;
}
INIT_FUNCTION
NTSTATUS
NTAPI
CmpInitializeHardwareConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
ULONG Disposition;
UNICODE_STRING KeyName;
/* Setup the key name */
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\Hardware\\DeviceMap");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Create the device map key */
Status = NtCreateKey(&KeyHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if (!NT_SUCCESS(Status))
return Status;
NtClose(KeyHandle);
/* Nobody should've created this key yet! */
ASSERT(Disposition == REG_CREATED_NEW_KEY);
/* Setup the key name */
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\Hardware\\Description");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Create the description key */
Status = NtCreateKey(&KeyHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if (!NT_SUCCESS(Status))
return Status;
/* Nobody should've created this key yet! */
ASSERT(Disposition == REG_CREATED_NEW_KEY);
/* Allocate the configuration data buffer */
CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
CmpConfigurationAreaSize,
TAG_CM);
if (!CmpConfigurationData)
{
NtClose(KeyHandle);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Check if we got anything from NTLDR */
if (LoaderBlock->ConfigurationRoot)
{
/* Setup the configuration tree */
Status = CmpSetupConfigurationTree(LoaderBlock->ConfigurationRoot,
KeyHandle,
-1,
-1);
}
else
{
/* Nothing else to do */
Status = STATUS_SUCCESS;
}
/* Free the buffer, close our handle and return status */
ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
NtClose(KeyHandle);
return Status;
}