mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 21:13:52 +00:00
71fefa32db
* 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
823 lines
28 KiB
C
823 lines
28 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* FILE: ntoskrnl/config/cmboot.c
|
|
* PURPOSE: Configuration Manager - Boot Initialization
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
* Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "ntoskrnl.h"
|
|
#define NDEBUG
|
|
#include "debug.h"
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
extern ULONG InitSafeBootMode;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
INIT_FUNCTION
|
|
HCELL_INDEX
|
|
NTAPI
|
|
CmpFindControlSet(IN PHHIVE SystemHive,
|
|
IN HCELL_INDEX RootCell,
|
|
IN PUNICODE_STRING SelectKeyName,
|
|
OUT PBOOLEAN AutoSelect)
|
|
{
|
|
UNICODE_STRING KeyName;
|
|
PCM_KEY_NODE Node;
|
|
HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell;
|
|
HCELL_INDEX CurrentValueCell;
|
|
PCM_KEY_VALUE KeyValue;
|
|
ULONG Length;
|
|
PULONG ControlSetId;
|
|
ANSI_STRING ControlSetAnsiName;
|
|
CHAR Buffer[128];
|
|
WCHAR WideBuffer[128];
|
|
NTSTATUS Status;
|
|
PULONG CurrentData;
|
|
|
|
/* Sanity check */
|
|
ASSERT(SystemHive->ReleaseCellRoutine == NULL);
|
|
|
|
/* Get the Select subkey */
|
|
RtlInitUnicodeString(&KeyName, L"select");
|
|
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell);
|
|
if (!Node) return HCELL_NIL;
|
|
SelectCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName);
|
|
if (SelectCell == HCELL_NIL) return SelectCell;
|
|
|
|
/* Get AutoSelect value */
|
|
RtlInitUnicodeString(&KeyName, L"AutoSelect");
|
|
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
|
|
if (!Node) return HCELL_NIL;
|
|
AutoSelectCell = CmpFindValueByName(SystemHive, Node, &KeyName);
|
|
if (AutoSelectCell == HCELL_NIL)
|
|
{
|
|
/* Assume TRUE if the value is missing. */
|
|
*AutoSelect = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Read the value */
|
|
KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell);
|
|
if (KeyValue == NULL) return HCELL_NIL;
|
|
|
|
/* Convert it to a boolean */
|
|
*AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length);
|
|
}
|
|
|
|
/* Now find the control set being looked up */
|
|
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
|
|
if (!Node) return HCELL_NIL;
|
|
SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName);
|
|
if (SelectValueCell == HCELL_NIL) return SelectValueCell;
|
|
|
|
/* Read the value (corresponding to the CCS ID) */
|
|
KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell);
|
|
if (!KeyValue) return HCELL_NIL;
|
|
if (KeyValue->Type != REG_DWORD) return HCELL_NIL;
|
|
ControlSetId = (PULONG)CmpValueToData(SystemHive, KeyValue, &Length);
|
|
|
|
/* Now build an Ansi String for the CCS's Name */
|
|
sprintf(Buffer, "ControlSet%03lu", *ControlSetId);
|
|
ControlSetAnsiName.Length = (USHORT)strlen(Buffer);
|
|
ControlSetAnsiName.MaximumLength = (USHORT)strlen(Buffer);
|
|
ControlSetAnsiName.Buffer = Buffer;
|
|
|
|
/* And convert it to Unicode... */
|
|
KeyName.MaximumLength = 256;
|
|
KeyName.Buffer = WideBuffer;
|
|
Status = RtlAnsiStringToUnicodeString(&KeyName,
|
|
&ControlSetAnsiName,
|
|
FALSE);
|
|
if (!NT_SUCCESS(Status)) return HCELL_NIL;
|
|
|
|
/* Now open it */
|
|
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell);
|
|
if (!Node) return HCELL_NIL;
|
|
ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName);
|
|
if (ControlSetCell == HCELL_NIL) return ControlSetCell;
|
|
|
|
/* Get the value of the "Current" CCS */
|
|
RtlInitUnicodeString(&KeyName, L"Current");
|
|
Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
|
|
if (!Node) return HCELL_NIL;
|
|
CurrentValueCell = CmpFindValueByName(SystemHive, Node, &KeyName);
|
|
|
|
/* Make sure it exists */
|
|
if (CurrentValueCell != HCELL_NIL)
|
|
{
|
|
/* Get the current value and make sure its a ULONG */
|
|
KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell);
|
|
if (!KeyValue) return HCELL_NIL;
|
|
if (KeyValue->Type == REG_DWORD)
|
|
{
|
|
/* Get the data and update it */
|
|
CurrentData = (PULONG)CmpValueToData(SystemHive,
|
|
KeyValue,
|
|
&Length);
|
|
if (!CurrentData) return HCELL_NIL;
|
|
*CurrentData = *ControlSetId;
|
|
}
|
|
}
|
|
|
|
/* Return the CCS Cell */
|
|
return ControlSetCell;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
ULONG
|
|
NTAPI
|
|
CmpFindTagIndex(IN PHHIVE Hive,
|
|
IN HCELL_INDEX TagCell,
|
|
IN HCELL_INDEX GroupOrderCell,
|
|
IN PUNICODE_STRING GroupName)
|
|
{
|
|
PCM_KEY_VALUE TagValue, Value;
|
|
HCELL_INDEX OrderCell;
|
|
PULONG TagOrder, DriverTag;
|
|
ULONG CurrentTag, Length;
|
|
PCM_KEY_NODE Node;
|
|
BOOLEAN BufferAllocated;
|
|
ASSERT(Hive->ReleaseCellRoutine == NULL);
|
|
|
|
/* Get the tag */
|
|
Value = HvGetCell(Hive, TagCell);
|
|
ASSERT(Value);
|
|
DriverTag = (PULONG)CmpValueToData(Hive, Value, &Length);
|
|
ASSERT(DriverTag);
|
|
|
|
/* Get the order array */
|
|
Node = HvGetCell(Hive, GroupOrderCell);
|
|
ASSERT(Node);
|
|
OrderCell = CmpFindValueByName(Hive, Node, GroupName);
|
|
if (OrderCell == HCELL_NIL) return -2;
|
|
|
|
/* And read it */
|
|
TagValue = HvGetCell(Hive, OrderCell);
|
|
CmpGetValueData(Hive, TagValue, &Length, (PVOID*)&TagOrder, &BufferAllocated, &OrderCell);
|
|
ASSERT(TagOrder);
|
|
|
|
/* Parse each tag */
|
|
for (CurrentTag = 1; CurrentTag <= TagOrder[0]; CurrentTag++)
|
|
{
|
|
/* Find a match */
|
|
if (TagOrder[CurrentTag] == *DriverTag)
|
|
{
|
|
/* Found it -- return the tag */
|
|
if (BufferAllocated) ExFreePool(TagOrder);
|
|
return CurrentTag;
|
|
}
|
|
}
|
|
|
|
/* No matches, so assume next to last ordering */
|
|
if (BufferAllocated) ExFreePool(TagOrder);
|
|
return -2;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpAddDriverToList(IN PHHIVE Hive,
|
|
IN HCELL_INDEX DriverCell,
|
|
IN HCELL_INDEX GroupOrderCell,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PLIST_ENTRY BootDriverListHead)
|
|
{
|
|
PBOOT_DRIVER_NODE DriverNode;
|
|
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
|
|
PCM_KEY_NODE Node;
|
|
ULONG Length;
|
|
USHORT NameLength;
|
|
HCELL_INDEX ValueCell, TagCell; PCM_KEY_VALUE Value;
|
|
PUNICODE_STRING FileName, RegistryString;
|
|
UNICODE_STRING UnicodeString;
|
|
PULONG ErrorControl;
|
|
PWCHAR Buffer;
|
|
ASSERT(Hive->ReleaseCellRoutine == NULL);
|
|
|
|
/* Allocate a driver node and initialize it */
|
|
DriverNode = CmpAllocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM);
|
|
if (!DriverNode) return FALSE;
|
|
DriverEntry = &DriverNode->ListEntry;
|
|
DriverEntry->RegistryPath.Buffer = NULL;
|
|
DriverEntry->FilePath.Buffer = NULL;
|
|
|
|
/* Get the driver cell */
|
|
Node = HvGetCell(Hive, DriverCell);
|
|
ASSERT(Node);
|
|
|
|
/* Get the name from the cell */
|
|
DriverNode->Name.Length = Node->Flags & KEY_COMP_NAME ?
|
|
CmpCompressedNameSize(Node->Name, Node->NameLength) :
|
|
Node->NameLength;
|
|
DriverNode->Name.MaximumLength = DriverNode->Name.Length;
|
|
NameLength = DriverNode->Name.Length;
|
|
|
|
/* Now allocate the buffer for it and copy the name */
|
|
DriverNode->Name.Buffer = CmpAllocate(NameLength, FALSE, TAG_CM);
|
|
if (!DriverNode->Name.Buffer) return FALSE;
|
|
if (Node->Flags & KEY_COMP_NAME)
|
|
{
|
|
/* Compressed name */
|
|
CmpCopyCompressedName(DriverNode->Name.Buffer,
|
|
DriverNode->Name.Length,
|
|
Node->Name,
|
|
Node->NameLength);
|
|
}
|
|
else
|
|
{
|
|
/* Normal name */
|
|
RtlCopyMemory(DriverNode->Name.Buffer, Node->Name, Node->NameLength);
|
|
}
|
|
|
|
/* Now find the image path */
|
|
RtlInitUnicodeString(&UnicodeString, L"ImagePath");
|
|
ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
|
|
if (ValueCell == HCELL_NIL)
|
|
{
|
|
/* Couldn't find it, so assume the drivers path */
|
|
Length = sizeof(L"System32\\Drivers\\") + NameLength + sizeof(L".sys");
|
|
|
|
/* Allocate the path name */
|
|
FileName = &DriverEntry->FilePath;
|
|
FileName->Length = 0;
|
|
FileName->MaximumLength = (USHORT)Length;
|
|
FileName->Buffer = CmpAllocate(Length, FALSE,TAG_CM);
|
|
if (!FileName->Buffer) return FALSE;
|
|
|
|
/* Write the path name */
|
|
RtlAppendUnicodeToString(FileName, L"System32\\Drivers\\");
|
|
RtlAppendUnicodeStringToString(FileName, &DriverNode->Name);
|
|
RtlAppendUnicodeToString(FileName, L".sys");
|
|
}
|
|
else
|
|
{
|
|
/* Path name exists, so grab it */
|
|
Value = HvGetCell(Hive, ValueCell);
|
|
ASSERT(Value);
|
|
|
|
/* Allocate and setup the path name */
|
|
FileName = &DriverEntry->FilePath;
|
|
Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length);
|
|
FileName->MaximumLength = FileName->Length = (USHORT)Length;
|
|
FileName->Buffer = CmpAllocate(Length, FALSE, TAG_CM);
|
|
|
|
/* Transfer the data */
|
|
if (!(FileName->Buffer) || !(Buffer)) return FALSE;
|
|
RtlCopyMemory(FileName->Buffer, Buffer, Length);
|
|
}
|
|
|
|
/* Now build the registry path */
|
|
RegistryString = &DriverEntry->RegistryPath;
|
|
RegistryString->Length = 0;
|
|
RegistryString->MaximumLength = RegistryPath->Length + NameLength;
|
|
RegistryString->Buffer = CmpAllocate(RegistryString->MaximumLength, FALSE, TAG_CM);
|
|
if (!RegistryString->Buffer) return FALSE;
|
|
|
|
/* Add the driver name to it */
|
|
RtlAppendUnicodeStringToString(RegistryString, RegistryPath);
|
|
RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name);
|
|
|
|
/* The entry is done, add it */
|
|
InsertHeadList(BootDriverListHead, &DriverEntry->Link);
|
|
|
|
/* Now find error control settings */
|
|
RtlInitUnicodeString(&UnicodeString, L"ErrorControl");
|
|
ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
|
|
if (ValueCell == HCELL_NIL)
|
|
{
|
|
/* Couldn't find it, so assume default */
|
|
DriverNode->ErrorControl = NormalError;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, read whatever the data says */
|
|
Value = HvGetCell(Hive, ValueCell);
|
|
ASSERT(Value);
|
|
ErrorControl = (PULONG)CmpValueToData(Hive, Value, &Length);
|
|
ASSERT(ErrorControl);
|
|
DriverNode->ErrorControl = *ErrorControl;
|
|
}
|
|
|
|
/* Next, get the group cell */
|
|
RtlInitUnicodeString(&UnicodeString, L"group");
|
|
ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
|
|
if (ValueCell == HCELL_NIL)
|
|
{
|
|
/* Couldn't find, so set an empty string */
|
|
RtlInitEmptyUnicodeString(&DriverNode->Group, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
/* Found it, read the group value */
|
|
Value = HvGetCell(Hive, ValueCell);
|
|
ASSERT(Value);
|
|
|
|
/* Copy it into the node */
|
|
DriverNode->Group.Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length);
|
|
if (!DriverNode->Group.Buffer) return FALSE;
|
|
DriverNode->Group.Length = (USHORT)Length - sizeof(UNICODE_NULL);
|
|
DriverNode->Group.MaximumLength = DriverNode->Group.Length;
|
|
}
|
|
|
|
/* Finally, find the tag */
|
|
RtlInitUnicodeString(&UnicodeString, L"Tag");
|
|
TagCell = CmpFindValueByName(Hive, Node, &UnicodeString);
|
|
if (TagCell == HCELL_NIL)
|
|
{
|
|
/* No tag, so load last */
|
|
DriverNode->Tag = -1;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, decode it based on tag order */
|
|
DriverNode->Tag = CmpFindTagIndex(Hive,
|
|
TagCell,
|
|
GroupOrderCell,
|
|
&DriverNode->Group);
|
|
}
|
|
|
|
/* All done! */
|
|
return TRUE;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpIsLoadType(IN PHHIVE Hive,
|
|
IN HCELL_INDEX Cell,
|
|
IN SERVICE_LOAD_TYPE LoadType)
|
|
{
|
|
PCM_KEY_NODE Node;
|
|
HCELL_INDEX ValueCell;
|
|
UNICODE_STRING ValueString = RTL_CONSTANT_STRING(L"Start");
|
|
PCM_KEY_VALUE Value;
|
|
ULONG Length;
|
|
PLONG Data;
|
|
ASSERT(Hive->ReleaseCellRoutine == NULL);
|
|
|
|
/* Open the start cell */
|
|
Node = HvGetCell(Hive, Cell);
|
|
ASSERT(Node);
|
|
ValueCell = CmpFindValueByName(Hive, Node, &ValueString);
|
|
if (ValueCell == HCELL_NIL) return FALSE;
|
|
|
|
/* Read the start value */
|
|
Value = HvGetCell(Hive, ValueCell);
|
|
ASSERT(Value);
|
|
Data = (PLONG)CmpValueToData(Hive, Value, &Length);
|
|
ASSERT(Data);
|
|
|
|
/* Return if the type matches */
|
|
return (*Data == LoadType);
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpFindDrivers(IN PHHIVE Hive,
|
|
IN HCELL_INDEX ControlSet,
|
|
IN SERVICE_LOAD_TYPE LoadType,
|
|
IN PWCHAR BootFileSystem OPTIONAL,
|
|
IN PLIST_ENTRY DriverListHead)
|
|
{
|
|
HCELL_INDEX ServicesCell, ControlCell, GroupOrderCell, DriverCell;
|
|
HCELL_INDEX SafeBootCell = HCELL_NIL;
|
|
UNICODE_STRING Name;
|
|
ULONG i;
|
|
WCHAR Buffer[128];
|
|
UNICODE_STRING UnicodeString, KeyPath;
|
|
PBOOT_DRIVER_NODE FsNode;
|
|
PCM_KEY_NODE ControlNode, ServicesNode, Node;
|
|
ASSERT(Hive->ReleaseCellRoutine == NULL);
|
|
|
|
/* Open the control set key */
|
|
ControlNode = HvGetCell(Hive, ControlSet);
|
|
ASSERT(ControlNode);
|
|
|
|
/* Get services cell */
|
|
RtlInitUnicodeString(&Name, L"Services");
|
|
ServicesCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
|
|
if (ServicesCell == HCELL_NIL) return FALSE;
|
|
|
|
/* Open services key */
|
|
ServicesNode = HvGetCell(Hive, ServicesCell);
|
|
ASSERT(ServicesNode);
|
|
|
|
/* Get control cell */
|
|
RtlInitUnicodeString(&Name, L"Control");
|
|
ControlCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
|
|
if (ControlCell == HCELL_NIL) return FALSE;
|
|
|
|
/* Get the group order cell and read it */
|
|
RtlInitUnicodeString(&Name, L"GroupOrderList");
|
|
Node = HvGetCell(Hive, ControlCell);
|
|
ASSERT(Node);
|
|
GroupOrderCell = CmpFindSubKeyByName(Hive, Node, &Name);
|
|
if (GroupOrderCell == HCELL_NIL) return FALSE;
|
|
|
|
/* Get Safe Boot cell */
|
|
if(InitSafeBootMode)
|
|
{
|
|
/* Open the Safe Boot key */
|
|
RtlInitUnicodeString(&Name, L"SafeBoot");
|
|
Node = HvGetCell(Hive, ControlCell);
|
|
ASSERT(Node);
|
|
SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
|
|
if (SafeBootCell == HCELL_NIL) return FALSE;
|
|
|
|
/* Open the correct start key (depending on the mode) */
|
|
Node = HvGetCell(Hive, SafeBootCell);
|
|
ASSERT(Node);
|
|
switch(InitSafeBootMode)
|
|
{
|
|
/* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
|
|
case 1:
|
|
case 3: RtlInitUnicodeString(&Name, L"Minimal"); break;
|
|
case 2: RtlInitUnicodeString(&Name, L"Network"); break;
|
|
default: return FALSE;
|
|
}
|
|
SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
|
|
if(SafeBootCell == HCELL_NIL) return FALSE;
|
|
}
|
|
|
|
/* Build the root registry path */
|
|
RtlInitEmptyUnicodeString(&KeyPath, Buffer, sizeof(Buffer));
|
|
RtlAppendUnicodeToString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
|
|
|
/* Find the first subkey (ie: the first driver or service) */
|
|
i = 0;
|
|
DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, i);
|
|
while (DriverCell != HCELL_NIL)
|
|
{
|
|
/* Make sure it's a driver of this start type AND is "safe" to load */
|
|
if (CmpIsLoadType(Hive, DriverCell, LoadType) &&
|
|
CmpIsSafe(Hive, SafeBootCell, DriverCell))
|
|
{
|
|
/* Add it to the list */
|
|
CmpAddDriverToList(Hive,
|
|
DriverCell,
|
|
GroupOrderCell,
|
|
&KeyPath,
|
|
DriverListHead);
|
|
|
|
}
|
|
|
|
/* Try the next subkey */
|
|
DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, ++i);
|
|
}
|
|
|
|
/* Check if we have a boot file system */
|
|
if (BootFileSystem)
|
|
{
|
|
/* Find it */
|
|
RtlInitUnicodeString(&UnicodeString, BootFileSystem);
|
|
DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &UnicodeString);
|
|
if (DriverCell != HCELL_NIL)
|
|
{
|
|
/* Always add it to the list */
|
|
CmpAddDriverToList(Hive,
|
|
DriverCell,
|
|
GroupOrderCell,
|
|
&KeyPath,
|
|
DriverListHead);
|
|
|
|
/* Mark it as critical so it always loads */
|
|
FsNode = CONTAINING_RECORD(DriverListHead->Flink,
|
|
BOOT_DRIVER_NODE,
|
|
ListEntry.Link);
|
|
FsNode->ErrorControl = SERVICE_ERROR_CRITICAL;
|
|
}
|
|
}
|
|
|
|
/* We're done! */
|
|
return TRUE;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpDoSort(IN PLIST_ENTRY DriverListHead,
|
|
IN PUNICODE_STRING OrderList)
|
|
{
|
|
PWCHAR Current, End = NULL;
|
|
PLIST_ENTRY NextEntry;
|
|
UNICODE_STRING GroupName;
|
|
PBOOT_DRIVER_NODE CurrentNode;
|
|
|
|
/* We're going from end to start, so get to the last group and keep going */
|
|
Current = &OrderList->Buffer[OrderList->Length / sizeof(WCHAR)];
|
|
while (Current > OrderList->Buffer)
|
|
{
|
|
/* Scan the current string */
|
|
do
|
|
{
|
|
if (*Current == UNICODE_NULL) End = Current;
|
|
} while ((*(--Current - 1) != UNICODE_NULL) && (Current != OrderList->Buffer));
|
|
|
|
/* This is our cleaned up string for this specific group */
|
|
ASSERT(End != NULL);
|
|
GroupName.Length = (USHORT)(End - Current) * sizeof(WCHAR);
|
|
GroupName.MaximumLength = GroupName.Length;
|
|
GroupName.Buffer = Current;
|
|
|
|
/* Now loop the driver list */
|
|
NextEntry = DriverListHead->Flink;
|
|
while (NextEntry != DriverListHead)
|
|
{
|
|
/* Get this node */
|
|
CurrentNode = CONTAINING_RECORD(NextEntry,
|
|
BOOT_DRIVER_NODE,
|
|
ListEntry.Link);
|
|
|
|
/* Get the next entry now since we'll do a relink */
|
|
NextEntry = CurrentNode->ListEntry.Link.Flink;
|
|
|
|
/* Is there a group name and does it match the current group? */
|
|
if ((CurrentNode->Group.Buffer) &&
|
|
(RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE)))
|
|
{
|
|
/* Remove from this location and re-link in the new one */
|
|
RemoveEntryList(&CurrentNode->ListEntry.Link);
|
|
InsertHeadList(DriverListHead, &CurrentNode->ListEntry.Link);
|
|
}
|
|
}
|
|
|
|
/* Move on */
|
|
Current--;
|
|
}
|
|
|
|
/* All done */
|
|
return TRUE;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpSortDriverList(IN PHHIVE Hive,
|
|
IN HCELL_INDEX ControlSet,
|
|
IN PLIST_ENTRY DriverListHead)
|
|
{
|
|
HCELL_INDEX Controls, GroupOrder, ListCell;
|
|
UNICODE_STRING Name, DependList;
|
|
PCM_KEY_VALUE ListNode;
|
|
ULONG Length;
|
|
PCM_KEY_NODE Node;
|
|
ASSERT(Hive->ReleaseCellRoutine == NULL);
|
|
|
|
/* Open the control key */
|
|
Node = HvGetCell(Hive, ControlSet);
|
|
ASSERT(Node);
|
|
RtlInitUnicodeString(&Name, L"Control");
|
|
Controls = CmpFindSubKeyByName(Hive, Node, &Name);
|
|
if (Controls == HCELL_NIL) return FALSE;
|
|
|
|
/* Open the service group order */
|
|
Node = HvGetCell(Hive, Controls);
|
|
ASSERT(Node);
|
|
RtlInitUnicodeString(&Name, L"ServiceGroupOrder");
|
|
GroupOrder = CmpFindSubKeyByName(Hive, Node, &Name);
|
|
if (GroupOrder == HCELL_NIL) return FALSE;
|
|
|
|
/* Open the list key */
|
|
Node = HvGetCell(Hive, GroupOrder);
|
|
ASSERT(Node);
|
|
RtlInitUnicodeString(&Name, L"list");
|
|
ListCell = CmpFindValueByName(Hive, Node, &Name);
|
|
if (ListCell == HCELL_NIL) return FALSE;
|
|
|
|
/* Now read the actual list */
|
|
ListNode = HvGetCell(Hive, ListCell);
|
|
ASSERT(ListNode);
|
|
if (ListNode->Type != REG_MULTI_SZ) return FALSE;
|
|
|
|
/* Copy it into a buffer */
|
|
DependList.Buffer = (PWCHAR)CmpValueToData(Hive, ListNode, &Length);
|
|
if (!DependList.Buffer) return FALSE;
|
|
DependList.Length = DependList.MaximumLength = (USHORT)Length - sizeof(UNICODE_NULL);
|
|
|
|
/* And start the recurive sort algorithm */
|
|
return CmpDoSort(DriverListHead, &DependList);
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode,
|
|
IN PBOOT_DRIVER_NODE EndNode)
|
|
{
|
|
PBOOT_DRIVER_NODE CurrentNode, PreviousNode;
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
/* Base case, nothing to do */
|
|
if (StartNode == EndNode) return TRUE;
|
|
|
|
/* Loop the nodes */
|
|
CurrentNode = StartNode;
|
|
do
|
|
{
|
|
/* Save this as the previous node */
|
|
PreviousNode = CurrentNode;
|
|
|
|
/* And move to the next one */
|
|
ListEntry = CurrentNode->ListEntry.Link.Flink;
|
|
CurrentNode = CONTAINING_RECORD(ListEntry,
|
|
BOOT_DRIVER_NODE,
|
|
ListEntry.Link);
|
|
|
|
/* Check if the previous driver had a bigger tag */
|
|
if (PreviousNode->Tag > CurrentNode->Tag)
|
|
{
|
|
/* Check if we need to update the tail */
|
|
if (CurrentNode == EndNode)
|
|
{
|
|
/* Update the tail */
|
|
ListEntry = CurrentNode->ListEntry.Link.Blink;
|
|
EndNode = CONTAINING_RECORD(ListEntry,
|
|
BOOT_DRIVER_NODE,
|
|
ListEntry.Link);
|
|
}
|
|
|
|
/* Remove this driver since we need to move it */
|
|
RemoveEntryList(&CurrentNode->ListEntry.Link);
|
|
|
|
/* Keep looping until we find a driver with a lower tag than ours */
|
|
while ((PreviousNode->Tag > CurrentNode->Tag) && (PreviousNode != StartNode))
|
|
{
|
|
/* We'll be re-inserted at this spot */
|
|
ListEntry = PreviousNode->ListEntry.Link.Blink;
|
|
PreviousNode = CONTAINING_RECORD(ListEntry,
|
|
BOOT_DRIVER_NODE,
|
|
ListEntry.Link);
|
|
}
|
|
|
|
/* Do the insert in the new location */
|
|
InsertTailList(&PreviousNode->ListEntry.Link, &CurrentNode->ListEntry.Link);
|
|
|
|
/* Update the head, if needed */
|
|
if (PreviousNode == StartNode) StartNode = CurrentNode;
|
|
}
|
|
} while (CurrentNode != EndNode);
|
|
|
|
/* All done */
|
|
return TRUE;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PBOOT_DRIVER_NODE StartNode, EndNode, CurrentNode;
|
|
|
|
/* Loop the list */
|
|
NextEntry = DriverListHead->Flink;
|
|
while (NextEntry != DriverListHead)
|
|
{
|
|
/* Find the first entry */
|
|
StartNode = CONTAINING_RECORD(NextEntry,
|
|
BOOT_DRIVER_NODE,
|
|
ListEntry.Link);
|
|
do
|
|
{
|
|
/* Find the last entry */
|
|
EndNode = CONTAINING_RECORD(NextEntry,
|
|
BOOT_DRIVER_NODE,
|
|
ListEntry.Link);
|
|
|
|
/* Get the next entry */
|
|
NextEntry = NextEntry->Flink;
|
|
CurrentNode = CONTAINING_RECORD(NextEntry,
|
|
BOOT_DRIVER_NODE,
|
|
ListEntry.Link);
|
|
|
|
/* If the next entry is back to the top, break out */
|
|
if (NextEntry == DriverListHead) break;
|
|
|
|
/* Otherwise, check if this entry is equal */
|
|
if (!RtlEqualUnicodeString(&StartNode->Group,
|
|
&CurrentNode->Group,
|
|
TRUE))
|
|
{
|
|
/* It is, so we've detected a cycle, break out */
|
|
break;
|
|
}
|
|
} while (NextEntry != DriverListHead);
|
|
|
|
/* Now we have the correct start and end pointers, so do the sort */
|
|
CmpOrderGroup(StartNode, EndNode);
|
|
}
|
|
|
|
/* We're done */
|
|
return TRUE;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpIsSafe(IN PHHIVE Hive,
|
|
IN HCELL_INDEX SafeBootCell,
|
|
IN HCELL_INDEX DriverCell)
|
|
{
|
|
PCM_KEY_NODE SafeBootNode;
|
|
PCM_KEY_NODE DriverNode;
|
|
PCM_KEY_VALUE KeyValue;
|
|
HCELL_INDEX CellIndex;
|
|
ULONG Length = 0;
|
|
UNICODE_STRING Name;
|
|
PWCHAR OriginalName;
|
|
ASSERT(Hive->ReleaseCellRoutine == NULL);
|
|
|
|
/* Driver key node (mandatory) */
|
|
ASSERT(DriverCell != HCELL_NIL);
|
|
DriverNode = HvGetCell(Hive, DriverCell);
|
|
ASSERT(DriverNode);
|
|
|
|
/* Safe boot key node (optional but return TRUE if not present) */
|
|
if(SafeBootCell == HCELL_NIL) return TRUE;
|
|
SafeBootNode = HvGetCell(Hive, SafeBootCell);
|
|
if(!SafeBootNode) return FALSE;
|
|
|
|
/* Search by the name from the group */
|
|
RtlInitUnicodeString(&Name, L"Group");
|
|
CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
|
|
if(CellIndex != HCELL_NIL)
|
|
{
|
|
KeyValue = HvGetCell(Hive, CellIndex);
|
|
ASSERT(KeyValue);
|
|
if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ)
|
|
{
|
|
/* Compose the search 'key' */
|
|
Name.Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
|
|
if (!Name.Buffer) return FALSE;
|
|
Name.Length = (USHORT)Length - sizeof(UNICODE_NULL);
|
|
Name.MaximumLength = Name.Length;
|
|
/* Search for corresponding key in the Safe Boot key */
|
|
CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
|
|
if(CellIndex != HCELL_NIL) return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Group has not been found - find driver name */
|
|
Name.Length = DriverNode->Flags & KEY_COMP_NAME ?
|
|
CmpCompressedNameSize(DriverNode->Name,
|
|
DriverNode->NameLength) :
|
|
DriverNode->NameLength;
|
|
Name.MaximumLength = Name.Length;
|
|
/* Now allocate the buffer for it and copy the name */
|
|
Name.Buffer = CmpAllocate(Name.Length, FALSE, TAG_CM);
|
|
if (!Name.Buffer) return FALSE;
|
|
if (DriverNode->Flags & KEY_COMP_NAME)
|
|
{
|
|
/* Compressed name */
|
|
CmpCopyCompressedName(Name.Buffer,
|
|
Name.Length,
|
|
DriverNode->Name,
|
|
DriverNode->NameLength);
|
|
}
|
|
else
|
|
{
|
|
/* Normal name */
|
|
RtlCopyMemory(Name.Buffer, DriverNode->Name, DriverNode->NameLength);
|
|
}
|
|
CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
|
|
RtlFreeUnicodeString(&Name);
|
|
if(CellIndex != HCELL_NIL) return TRUE;
|
|
|
|
/* Not group or driver name - search by image name */
|
|
RtlInitUnicodeString(&Name, L"ImagePath");
|
|
CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
|
|
if(CellIndex != HCELL_NIL)
|
|
{
|
|
KeyValue = HvGetCell(Hive, CellIndex);
|
|
ASSERT(KeyValue);
|
|
if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ)
|
|
{
|
|
/* Compose the search 'key' */
|
|
OriginalName = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
|
|
if (!OriginalName) return FALSE;
|
|
/* Get the base image file name */
|
|
Name.Buffer = wcsrchr(OriginalName, L'\\');
|
|
if (!Name.Buffer) return FALSE;
|
|
++Name.Buffer;
|
|
/* Length of the base name must be >=1 */
|
|
Name.Length = (USHORT)Length - (USHORT)((PUCHAR)Name.Buffer - (PUCHAR)OriginalName)
|
|
- sizeof(UNICODE_NULL);
|
|
if(Name.Length < 1) return FALSE;
|
|
Name.MaximumLength = Name.Length;
|
|
/* Search for corresponding key in the Safe Boot key */
|
|
CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
|
|
if(CellIndex != HCELL_NIL) return TRUE;
|
|
}
|
|
}
|
|
/* Nothing found - nothing else to search */
|
|
return FALSE;
|
|
}
|
|
|
|
/* EOF */
|