From: Sir Richard Date: Fri, 2 Apr 2010 17:57:33 +0000 (+0000) Subject: [NTOS]: Rewrite boot driver loading code (not the driver code itself) to use the... X-Git-Tag: backups/header-work@57446~30^2~138 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=6075ae9a8f23bf75a23b9f380839fc680dd1b19e [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 --- diff --git a/reactos/ntoskrnl/include/internal/io.h b/reactos/ntoskrnl/include/internal/io.h index 2519a8134d2..dc80ff249a5 100644 --- a/reactos/ntoskrnl/include/internal/io.h +++ b/reactos/ntoskrnl/include/internal/io.h @@ -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 // diff --git a/reactos/ntoskrnl/io/iomgr/driver.c b/reactos/ntoskrnl/io/iomgr/driver.c index ef1b78969fb..f00a87d0e09 100644 --- a/reactos/ntoskrnl/io/iomgr/driver.c +++ b/reactos/ntoskrnl/io/iomgr/driver.c @@ -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; @@ -940,19 +959,83 @@ IopInitializeBootDrivers(VOID) LdrEntry = CONTAINING_RECORD(NextEntry, 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) + { + /* 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) + { + /* 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) { - /* Make sure we didn't load this driver already */ - if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED)) + /* 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))) { - DPRINT("Initializing bootdriver %wZ\n", &LdrEntry->BaseDllName); - /* Initialize it */ - IopInitializeBuiltinDriver(LdrEntry); + /* 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); } diff --git a/reactos/ntoskrnl/io/iomgr/iomgr.c b/reactos/ntoskrnl/io/iomgr/iomgr.c index cb32297d25c..c7999660a61 100644 --- a/reactos/ntoskrnl/io/iomgr/iomgr.c +++ b/reactos/ntoskrnl/io/iomgr/iomgr.c @@ -489,6 +489,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(); diff --git a/reactos/ntoskrnl/io/pnpmgr/pnpinit.c b/reactos/ntoskrnl/io/pnpmgr/pnpinit.c new file mode 100644 index 00000000000..8c5607289a6 --- /dev/null +++ b/reactos/ntoskrnl/io/pnpmgr/pnpinit.c @@ -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 +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/io/pnpmgr/pnputil.c b/reactos/ntoskrnl/io/pnpmgr/pnputil.c new file mode 100644 index 00000000000..f274f3db679 --- /dev/null +++ b/reactos/ntoskrnl/io/pnpmgr/pnputil.c @@ -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 +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index a605ee1b147..b6ed1824217 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -267,10 +267,12 @@ plugplay.c pnpdma.c + pnpinit.c pnpmgr.c pnpnotify.c pnpreport.c pnproot.c + pnputil.c