[NTOS]: Rewrite boot driver loading code (not the driver code itself) to use the boot loader's BootDriverListHead, instead of parsing InOrderListHead and cherry-picking ".sys" files. This is the last incompatibility with Windows.

[NTOS]: Use group prioritiy, tag numbers, and tag priority to determine the correct loading order for boot drivers, instead of just parsing the linked list. Dependencies work now!
[NTOS]: Load any DLLs that are driver-dependent with MmCallDllInitialize. Previously, these .DLLS were ignored and drivers could lose dependencies.

svn path=/trunk/; revision=46690
This commit is contained in:
Sir Richard 2010-04-02 17:57:33 +00:00
parent 74e30b9093
commit 6075ae9a8f
6 changed files with 595 additions and 13 deletions

View file

@ -395,6 +395,33 @@ typedef struct _LOAD_UNLOAD_PARAMS
PDRIVER_OBJECT DriverObject;
} LOAD_UNLOAD_PARAMS, *PLOAD_UNLOAD_PARAMS;
//
// Boot Driver List Entry
//
typedef struct _DRIVER_INFORMATION
{
LIST_ENTRY Link;
PDRIVER_OBJECT DriverObject;
PBOOT_DRIVER_LIST_ENTRY DataTableEntry;
HANDLE ServiceHandle;
USHORT TagPosition;
ULONG Failed;
ULONG Processed;
NTSTATUS Status;
} DRIVER_INFORMATION, *PDRIVER_INFORMATION;
//
// Boot Driver Node
//
typedef struct _BOOT_DRIVER_NODE
{
BOOT_DRIVER_LIST_ENTRY ListEntry;
UNICODE_STRING Group;
UNICODE_STRING Name;
ULONG Tag;
ULONG ErrorControl;
} BOOT_DRIVER_NODE, *PBOOT_DRIVER_NODE;
//
// List of Bus Type GUIDs
//
@ -605,6 +632,43 @@ IopGetRegistryValue(IN HANDLE Handle,
OUT PKEY_VALUE_FULL_INFORMATION *Information);
//
// PnP Routines
//
NTSTATUS
NTAPI
PiInitCacheGroupInformation(
VOID
);
USHORT
NTAPI
PpInitGetGroupOrderIndex(
IN HANDLE ServiceHandle
);
USHORT
NTAPI
PipGetDriverTagPriority(
IN HANDLE ServiceHandle
);
NTSTATUS
NTAPI
PnpRegMultiSzToUnicodeStrings(
IN PKEY_VALUE_FULL_INFORMATION KeyValueInformation,
OUT PUNICODE_STRING *UnicodeStringList,
OUT PULONG UnicodeStringCount
);
BOOLEAN
NTAPI
PnpRegSzToString(
IN PWCHAR RegSzData,
IN ULONG RegSzLength,
OUT PUSHORT StringLength OPTIONAL
);
//
// Initialization Routines
//

View file

@ -34,6 +34,9 @@ POBJECT_TYPE IoDriverObjectType = NULL;
extern BOOLEAN ExpInTextModeSetup;
extern BOOLEAN PnpSystemInit;
USHORT IopGroupIndex;
PLIST_ENTRY IopGroupTable;
/* PRIVATE FUNCTIONS **********************************************************/
NTSTATUS NTAPI
@ -880,14 +883,17 @@ VOID
FASTCALL
IopInitializeBootDrivers(VOID)
{
PLIST_ENTRY ListHead, NextEntry;
PLIST_ENTRY ListHead, NextEntry, NextEntry2;
PLDR_DATA_TABLE_ENTRY LdrEntry;
PDEVICE_NODE DeviceNode;
PDRIVER_OBJECT DriverObject;
LDR_DATA_TABLE_ENTRY ModuleObject;
NTSTATUS Status;
UNICODE_STRING DriverName;
ULONG i, Index;
PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
HANDLE KeyHandle;
PBOOT_DRIVER_LIST_ENTRY BootEntry;
DPRINT("IopInitializeBootDrivers()\n");
/* Use IopRootDeviceNode for now */
@ -931,6 +937,19 @@ IopInitializeBootDrivers(VOID)
return;
}
/* Get highest group order index */
IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
/* Allocate the group table */
IopGroupTable = ExAllocatePoolWithTag(PagedPool,
IopGroupIndex * sizeof(LIST_ENTRY),
TAG_IO);
if (IopGroupTable == NULL) ASSERT(FALSE);
/* Initialize the group table lists */
for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
/* Loop the boot modules */
ListHead = &KeLoaderBlock->LoadOrderListHead;
NextEntry = ListHead->Flink;
@ -941,18 +960,82 @@ IopInitializeBootDrivers(VOID)
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
/*
* HACK: Make sure we're loading a driver
* (we should be using BootDriverListHead!)
*/
if (wcsstr(_wcsupr(LdrEntry->BaseDllName.Buffer), L".SYS"))
/* Check if the DLL needs to be initialized */
if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
{
/* Make sure we didn't load this driver already */
if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED))
/* Call its entrypoint */
MmCallDllInitialize(LdrEntry, NULL);
}
/* Go to the next driver */
NextEntry = NextEntry->Flink;
}
/* Loop the boot drivers */
ListHead = &KeLoaderBlock->BootDriverListHead;
NextEntry = ListHead->Flink;
while (ListHead != NextEntry)
{
DPRINT("Initializing bootdriver %wZ\n", &LdrEntry->BaseDllName);
/* Initialize it */
IopInitializeBuiltinDriver(LdrEntry);
/* Get the entry */
BootEntry = CONTAINING_RECORD(NextEntry,
BOOT_DRIVER_LIST_ENTRY,
Link);
/* Get the driver loader entry */
LdrEntry = BootEntry->LdrEntry;
/* Allocate our internal accounting structure */
DriverInfo = ExAllocatePoolWithTag(PagedPool,
sizeof(DRIVER_INFORMATION),
TAG_IO);
if (DriverInfo)
{
/* Zero it and initialize it */
RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
InitializeListHead(&DriverInfo->Link);
DriverInfo->DataTableEntry = BootEntry;
/* Open the registry key */
Status = IopOpenRegistryKeyEx(&KeyHandle,
NULL,
&BootEntry->RegistryPath,
KEY_READ);
if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
((KeLoaderBlock->SetupLdrBlock) && (KeyHandle = (PVOID)1)))
{
/* Save the handle */
DriverInfo->ServiceHandle = KeyHandle;
/* Get the group oder index */
Index = PpInitGetGroupOrderIndex(KeyHandle);
/* Get the tag position */
DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
/* Insert it into the list, at the right place */
ASSERT(Index < IopGroupIndex);
NextEntry2 = IopGroupTable[Index].Flink;
while (NextEntry2 != &IopGroupTable[Index])
{
/* Get the driver info */
DriverInfoTag = CONTAINING_RECORD(NextEntry2,
DRIVER_INFORMATION,
Link);
/* Check if we found the right tag position */
if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
{
/* We're done */
break;
}
/* Next entry */
NextEntry2 = NextEntry2->Flink;
}
/* Insert us right before the next entry */
NextEntry2 = NextEntry2->Blink;
InsertHeadList(NextEntry2, &DriverInfo->Link);
}
}
@ -960,6 +1043,29 @@ IopInitializeBootDrivers(VOID)
NextEntry = NextEntry->Flink;
}
/* Loop each group index */
for (i = 0; i < IopGroupIndex; i++)
{
/* Loop each group table */
NextEntry = IopGroupTable[i].Flink;
while (NextEntry != &IopGroupTable[i])
{
/* Get the entry */
DriverInfo = CONTAINING_RECORD(NextEntry,
DRIVER_INFORMATION,
Link);
/* Get the driver loader entry */
LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
/* Initialize it */
IopInitializeBuiltinDriver(LdrEntry);
/* Next entry */
NextEntry = NextEntry->Flink;
}
}
/* In old ROS, the loader list became empty after this point. Simulate. */
InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
}

View file

@ -490,6 +490,9 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
/* Initialize PnP manager */
PnpInit();
/* Setup the group cache */
if (!NT_SUCCESS(PiInitCacheGroupInformation())) return FALSE;
/* Create the group driver list */
IoCreateDriverList();

View file

@ -0,0 +1,222 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/io/pnpmgr/pnpinit.c
* PURPOSE: PnP Initialization Code
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
PUNICODE_STRING PiInitGroupOrderTable;
ULONG PiInitGroupOrderTableCount;
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
PiInitCacheGroupInformation(VOID)
{
HANDLE KeyHandle;
NTSTATUS Status;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
PUNICODE_STRING GroupTable;
ULONG Count;
UNICODE_STRING GroupString =
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\ServiceGroupOrder");
/* ReactOS HACK for SETUPLDR */
if (KeLoaderBlock->SetupLdrBlock)
{
/* Bogus data */
PiInitGroupOrderTableCount = 0;
PiInitGroupOrderTable = (PVOID)0xBABEB00B;
return STATUS_SUCCESS;
}
/* Open the registry key */
Status = IopOpenRegistryKeyEx(&KeyHandle,
NULL,
&GroupString,
KEY_READ);
if (NT_SUCCESS(Status))
{
/* Get the list */
Status = IopGetRegistryValue(KeyHandle, L"List", &KeyValueInformation);
ZwClose(KeyHandle);
/* Make sure we got it */
if (NT_SUCCESS(Status))
{
/* Make sure it's valid */
if ((KeyValueInformation->Type == REG_MULTI_SZ) &&
(KeyValueInformation->DataLength))
{
/* Convert it to unicode strings */
Status = PnpRegMultiSzToUnicodeStrings(KeyValueInformation,
&GroupTable,
&Count);
/* Cache it for later */
PiInitGroupOrderTable = GroupTable;
PiInitGroupOrderTableCount = Count;
}
else
{
/* Fail */
Status = STATUS_UNSUCCESSFUL;
}
/* Free the information */
ExFreePool(KeyValueInformation);
}
}
/* Return status */
return Status;
}
USHORT
NTAPI
PpInitGetGroupOrderIndex(IN HANDLE ServiceHandle)
{
NTSTATUS Status;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
ULONG i;
PVOID Buffer;
UNICODE_STRING Group;
PAGED_CODE();
/* Make sure we have a cache */
if (!PiInitGroupOrderTable) return -1;
/* If we don't have a handle, the rest is easy -- return the count */
if (!ServiceHandle) return PiInitGroupOrderTableCount + 1;
/* Otherwise, get the group value */
Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
if (!NT_SUCCESS(Status)) return PiInitGroupOrderTableCount;
/* Make sure we have a valid string */
ASSERT(KeyValueInformation->Type == REG_SZ);
ASSERT(KeyValueInformation->DataLength);
/* Convert to unicode string */
Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
Group.MaximumLength = KeyValueInformation->DataLength;
Group.Buffer = Buffer;
/* Loop the groups */
for (i = 0; i < PiInitGroupOrderTableCount; i++)
{
/* Try to find a match */
if (RtlEqualUnicodeString(&Group, &PiInitGroupOrderTable[i], TRUE)) break;
}
/* We're done */
ExFreePool(KeyValueInformation);
return i;
}
USHORT
NTAPI
PipGetDriverTagPriority(IN HANDLE ServiceHandle)
{
NTSTATUS Status;
HANDLE KeyHandle = NULL;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
PKEY_VALUE_FULL_INFORMATION KeyValueInformationTag;
PKEY_VALUE_FULL_INFORMATION KeyValueInformationGroupOrderList;
PVOID Buffer;
UNICODE_STRING Group;
PULONG GroupOrder;
ULONG i = -1, Count, Tag = 0;
UNICODE_STRING GroupString =
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\ServiceGroupOrder");
/* Open the key */
Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &GroupString, KEY_READ);
if (!NT_SUCCESS(Status)) goto Quickie;
/* Read the group */
Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
if (!NT_SUCCESS(Status)) goto Quickie;
/* Make sure we have a group */
if ((KeyValueInformation->Type == REG_SZ) &&
(KeyValueInformation->DataLength))
{
/* Convert to unicode string */
Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
Group.MaximumLength = KeyValueInformation->DataLength;
Group.Buffer = Buffer;
}
/* Now read the tag */
Status = IopGetRegistryValue(ServiceHandle, L"Tag", &KeyValueInformationTag);
if (!NT_SUCCESS(Status)) goto Quickie;
/* Make sure we have a tag */
if ((KeyValueInformationTag->Type == REG_DWORD) &&
(KeyValueInformationTag->DataLength))
{
/* Read it */
Tag = *(PULONG)((ULONG_PTR)KeyValueInformationTag +
KeyValueInformationTag->DataOffset);
}
/* We can get rid of this now */
ExFreePool(KeyValueInformationTag);
/* Now let's read the group's tag order */
Status = IopGetRegistryValue(KeyHandle,
Group.Buffer,
&KeyValueInformationGroupOrderList);
/* We can get rid of this now */
Quickie:
if (KeyValueInformation) ExFreePool(KeyValueInformation);
if (KeyHandle) NtClose(KeyHandle);
if (!NT_SUCCESS(Status)) return -1;
/* We're on the success path -- validate the tag order*/
if ((KeyValueInformationGroupOrderList->Type == REG_BINARY) &&
(KeyValueInformationGroupOrderList->DataLength))
{
/* Get the order array */
GroupOrder = (PULONG)((ULONG_PTR)KeyValueInformationGroupOrderList +
KeyValueInformationGroupOrderList->DataOffset);
/* Get the count */
Count = *GroupOrder;
ASSERT(((Count + 1) * sizeof(ULONG)) <=
KeyValueInformationGroupOrderList->DataLength);
/* Now loop each tag */
GroupOrder++;
for (i = 1; i <= Count; i++)
{
/* If we found it, we're out */
if (Tag == *GroupOrder) break;
/* Try the next one */
GroupOrder++;
}
}
/* Last buffer to free */
ExFreePool(KeyValueInformationGroupOrderList);
return i;
}
/* EOF */

View file

@ -0,0 +1,185 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/io/pnpmgr/pnputil.c
* PURPOSE: PnP Utility Code
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
/* FUNCTIONS ******************************************************************/
VOID
NTAPI
PnpFreeUnicodeStringList(IN PUNICODE_STRING UnicodeStringList,
IN ULONG StringCount)
{
ULONG i;
/* Go through the list */
if (UnicodeStringList)
{
/* Go through each string */
for (i = 0; i < StringCount; i++)
{
/* Check if it exists */
if (UnicodeStringList[i].Buffer)
{
/* Free it */
ExFreePool(UnicodeStringList[i].Buffer);
}
}
/* Free the whole list */
ExFreePool(UnicodeStringList);
}
}
NTSTATUS
NTAPI
PnpRegMultiSzToUnicodeStrings(IN PKEY_VALUE_FULL_INFORMATION KeyValueInformation,
OUT PUNICODE_STRING *UnicodeStringList,
OUT PULONG UnicodeStringCount)
{
PWCHAR p, pp, ps;
ULONG i = 0, n;
ULONG Count = 0;
/* Validate the key information */
if (KeyValueInformation->Type != REG_MULTI_SZ) return STATUS_INVALID_PARAMETER;
/* Set the pointers */
p = (PWCHAR)((ULONG_PTR)KeyValueInformation +
KeyValueInformation->DataOffset);
pp = (PWCHAR)((ULONG_PTR)p + KeyValueInformation->DataLength);
/* Loop the data */
while (p != pp)
{
/* If we find a NULL, that means one string is done */
if (!*p)
{
/* Add to our string count */
Count++;
/* Check for a double-NULL, which means we're done */
if (((p + 1) == pp) || !(*(p + 1))) break;
}
/* Go to the next character */
p++;
}
/* If we looped the whole list over, we missed increment a string, do it */
if (p == pp) Count++;
/* Allocate the list now that we know how big it is */
*UnicodeStringList = ExAllocatePoolWithTag(PagedPool,
sizeof(UNICODE_STRING) * Count,
'sUpP');
if (!(*UnicodeStringList)) return STATUS_INSUFFICIENT_RESOURCES;
/* Set pointers for second loop */
ps = p = (PWCHAR)((ULONG_PTR)KeyValueInformation +
KeyValueInformation->DataOffset);
/* Loop again, to do the copy this time */
while (p != pp)
{
/* If we find a NULL, that means one string is done */
if (!*p)
{
/* Check how long this string is */
n = (ULONG_PTR)p - (ULONG_PTR)ps + sizeof(UNICODE_NULL);
/* Allocate the buffer */
(*UnicodeStringList)[i].Buffer = ExAllocatePoolWithTag(PagedPool,
n,
'sUpP');
if (!(*UnicodeStringList)[i].Buffer)
{
/* Back out of everything */
PnpFreeUnicodeStringList(*UnicodeStringList, i);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy the string into the buffer */
RtlCopyMemory((*UnicodeStringList)[i].Buffer, ps, n);
/* Set the lengths */
(*UnicodeStringList)[i].MaximumLength = n;
(*UnicodeStringList)[i].Length = n - sizeof(UNICODE_NULL);
/* One more entry done */
i++;
/* Check for a double-NULL, which means we're done */
if (((p + 1) == pp) || !(*(p + 1))) break;
/* New string */
ps = p + 1;
}
/* New string */
p++;
}
/* Check if we've reached the last string */
if (p == pp)
{
/* Calculate the string length */
n = (ULONG_PTR)p - (ULONG_PTR)ps;
/* Allocate the buffer for it */
(*UnicodeStringList)[i].Buffer = ExAllocatePoolWithTag(PagedPool,
n +
sizeof(UNICODE_NULL),
'sUpP');
if (!(*UnicodeStringList)[i].Buffer)
{
/* Back out of everything */
PnpFreeUnicodeStringList(*UnicodeStringList, i);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Make sure there's an actual string here */
if (n) RtlCopyMemory((*UnicodeStringList)[i].Buffer, ps, n);
/* Null-terminate the string ourselves */
(*UnicodeStringList)[i].Buffer[n / sizeof(WCHAR)] = UNICODE_NULL;
/* Set the lenghts */
(*UnicodeStringList)[i].Length = n;
(*UnicodeStringList)[i].MaximumLength = n + sizeof(UNICODE_NULL);
}
/* And we're done */
*UnicodeStringCount = Count;
return STATUS_SUCCESS;
}
BOOLEAN
NTAPI
PnpRegSzToString(IN PWCHAR RegSzData,
IN ULONG RegSzLength,
OUT PUSHORT StringLength OPTIONAL)
{
PWCHAR p, pp;
/* Find the end */
pp = RegSzData + RegSzLength;
for (p = RegSzData; p < pp; p++) if (!*p) break;
/* Return it */
if (StringLength) *StringLength = p - RegSzData;
return TRUE;
}
/* EOF */

View file

@ -267,10 +267,12 @@
<directory name="pnpmgr">
<file>plugplay.c</file>
<file>pnpdma.c</file>
<file>pnpinit.c</file>
<file>pnpmgr.c</file>
<file>pnpnotify.c</file>
<file>pnpreport.c</file>
<file>pnproot.c</file>
<file>pnputil.c</file>
</directory>
</directory>
<if property="_WINKD_" value="0">