https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c4c0585f96a2a8642d231…
commit c4c0585f96a2a8642d2319e17b4bb834f2b943b7
Author: Victor Perevertkin <victor.perevertkin(a)reactos.org>
AuthorDate: Thu Nov 26 04:39:38 2020 +0300
Commit: Victor Perevertkin <victor.perevertkin(a)reactos.org>
CommitDate: Mon Jan 4 16:50:33 2021 +0300
[NTOS:IO][NTOS:PNP] Implement PiCallDriverAddDevice
- Move the driver's name obtaining logic into the IopGetDriverNames
function
- Create a new PiCallDriverAddDevice instead of PipCallDriverAddDevice
and move it to pnpmgr/devaction.c file. Move around all its internal
helpers too
- Support a proper Windows-compatible driver loading order for a PDO
(lower filters, main service, upper filters, etc.)
- Set a correct Problem for the DeviceNode, in case of an error during
driver loading
- Check the Start Type for all drivers before loading
- Do not try to load drivers during the early boot stage when there is
no disk subsystem initialized
---
ntoskrnl/include/internal/io.h | 46 ++-
ntoskrnl/io/iomgr/driver.c | 603 ++++++++-------------------------------
ntoskrnl/io/pnpmgr/devaction.c | 630 ++++++++++++++++++++++++++++++++++-------
ntoskrnl/io/pnpmgr/devnode.c | 17 ++
ntoskrnl/io/pnpmgr/pnpinit.c | 139 ---------
ntoskrnl/io/pnpmgr/pnpmgr.c | 69 -----
6 files changed, 673 insertions(+), 831 deletions(-)
diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h
index ad51265ba3f..65005373bd2 100644
--- a/ntoskrnl/include/internal/io.h
+++ b/ntoskrnl/include/internal/io.h
@@ -568,12 +568,9 @@ IopDetectResourceConflict(
// PNP Routines
//
NTSTATUS
-NTAPI
-PipCallDriverAddDevice(
- IN PDEVICE_NODE DeviceNode,
- IN BOOLEAN LoadDriver,
- IN PDRIVER_OBJECT DriverObject
-);
+PiCallDriverAddDevice(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ BOOLEAN LoadDrivers);
NTSTATUS
NTAPI
@@ -612,6 +609,15 @@ PiInsertDevNode(
_In_ PDEVICE_NODE DeviceNode,
_In_ PDEVICE_NODE ParentNode);
+VOID
+PiSetDevNodeProblem(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ UINT32 Problem);
+
+VOID
+PiClearDevNodeProblem(
+ _In_ PDEVICE_NODE DeviceNode);
+
NTSTATUS
IopFreeDeviceNode(
IN PDEVICE_NODE DeviceNode
@@ -811,13 +817,6 @@ IopReadyDeviceObjects(
IN PDRIVER_OBJECT Driver
);
-NTSTATUS
-FASTCALL
-IopInitializeDevice(
- IN PDEVICE_NODE DeviceNode,
- IN PDRIVER_OBJECT DriverObject
-);
-
NTSTATUS
IopStartDevice(
IN PDEVICE_NODE DeviceNode
@@ -1110,26 +1109,17 @@ IopDeleteDriver(
IN PVOID ObjectBody
);
-NTSTATUS
-FASTCALL
-IopGetDriverObject(
- OUT PDRIVER_OBJECT *DriverObject,
- IN PUNICODE_STRING ServiceName,
- IN BOOLEAN FileSystem
-);
-
-NTSTATUS
-FASTCALL
-IopLoadServiceModule(
- IN PUNICODE_STRING ServiceName,
- OUT PLDR_DATA_TABLE_ENTRY *ModuleObject
-);
-
NTSTATUS
IopLoadDriver(
_In_ HANDLE ServiceHandle,
_Out_ PDRIVER_OBJECT *DriverObject);
+NTSTATUS
+IopGetDriverNames(
+ _In_ HANDLE ServiceHandle,
+ _Out_ PUNICODE_STRING DriverName,
+ _Out_opt_ PUNICODE_STRING ServiceName);
+
NTSTATUS
IopInitializeDriverModule(
_In_ PLDR_DATA_TABLE_ENTRY ModuleObject,
diff --git a/ntoskrnl/io/iomgr/driver.c b/ntoskrnl/io/iomgr/driver.c
index 994d7375af8..1e02c1cc213 100644
--- a/ntoskrnl/io/iomgr/driver.c
+++ b/ntoskrnl/io/iomgr/driver.c
@@ -122,64 +122,127 @@ IopDeleteDriver(IN PVOID ObjectBody)
}
NTSTATUS
-FASTCALL
-IopGetDriverObject(
- PDRIVER_OBJECT *DriverObject,
- PUNICODE_STRING ServiceName,
- BOOLEAN FileSystem)
+IopGetDriverNames(
+ _In_ HANDLE ServiceHandle,
+ _Out_ PUNICODE_STRING DriverName,
+ _Out_opt_ PUNICODE_STRING ServiceName)
{
- PDRIVER_OBJECT Object;
- UNICODE_STRING Prefix;
- UNICODE_STRING DriverName;
- NTSTATUS Status;
+ UNICODE_STRING driverName = {.Buffer = NULL}, serviceName;
+ PKEY_VALUE_FULL_INFORMATION kvInfo;
+ NTSTATUS status;
- DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
- DriverObject, ServiceName, FileSystem);
+ PAGED_CODE();
- *DriverObject = NULL;
+ // 1. Check the "ObjectName" field in the driver's registry key (it has
the priority)
+ status = IopGetRegistryValue(ServiceHandle, L"ObjectName", &kvInfo);
+ if (NT_SUCCESS(status))
+ {
+ // we're got the ObjectName. Use it to create the DRIVER_OBJECT
+ if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0)
+ {
+ ExFreePool(kvInfo);
+ return STATUS_ILL_FORMED_SERVICE_ENTRY;
+ }
- /* Create ModuleName string */
- if (ServiceName == NULL || ServiceName->Buffer == NULL)
- /* We don't know which DriverObject we have to open */
- return STATUS_INVALID_PARAMETER_2;
+ driverName.Length = kvInfo->DataLength - sizeof(WCHAR),
+ driverName.MaximumLength = kvInfo->DataLength,
+ driverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, driverName.MaximumLength,
TAG_IO);
+ if (!driverName.Buffer)
+ {
+ ExFreePool(kvInfo);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
- if (FileSystem != FALSE)
- RtlInitUnicodeString(&Prefix, FILESYSTEM_ROOT_NAME);
- else
- RtlInitUnicodeString(&Prefix, DRIVER_ROOT_NAME);
+ RtlMoveMemory(driverName.Buffer,
+ (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
+ driverName.Length);
+ ExFreePool(kvInfo);
+ }
- DriverName.Length = 0;
- DriverName.MaximumLength = Prefix.Length + ServiceName->Length +
sizeof(UNICODE_NULL);
- ASSERT(DriverName.MaximumLength > ServiceName->Length);
- DriverName.Buffer = ExAllocatePoolWithTag(PagedPool, DriverName.MaximumLength,
TAG_IO);
- if (DriverName.Buffer == NULL)
+ // check if we need to get ServiceName as well
+ PKEY_BASIC_INFORMATION basicInfo;
+ if (!NT_SUCCESS(status) || ServiceName != NULL)
{
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlAppendUnicodeStringToString(&DriverName, &Prefix);
- RtlAppendUnicodeStringToString(&DriverName, ServiceName);
+ ULONG infoLength;
+ status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0,
&infoLength);
+ if (status == STATUS_BUFFER_TOO_SMALL)
+ {
+ basicInfo = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO);
+ if (!basicInfo)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
- DPRINT("Driver name: '%wZ'\n", &DriverName);
+ status = ZwQueryKey(ServiceHandle, KeyBasicInformation, basicInfo,
infoLength, &infoLength);
+ if (!NT_SUCCESS(status))
+ {
+ ExFreePoolWithTag(basicInfo, TAG_IO);
+ return status;
+ }
- /* Open driver object */
- Status = ObReferenceObjectByName(&DriverName,
- OBJ_OPENIF | OBJ_KERNEL_HANDLE |
OBJ_CASE_INSENSITIVE, /* Attributes */
- NULL, /* PassedAccessState */
- 0, /* DesiredAccess */
- IoDriverObjectType,
- KernelMode,
- NULL, /* ParseContext */
- (PVOID*)&Object);
- ExFreePoolWithTag(DriverName.Buffer, TAG_IO);
- if (!NT_SUCCESS(Status))
+ serviceName.Length = basicInfo->NameLength;
+ serviceName.MaximumLength = basicInfo->NameLength;
+ serviceName.Buffer = basicInfo->Name;
+ }
+ else
+ {
+ return NT_SUCCESS(status) ? STATUS_UNSUCCESSFUL : status;
+ }
+ }
+
+ // 2. there is no "ObjectName" - construct it ourselves. Depending on a
driver type,
+ // it will be either "\Driver\<ServiceName>" or
"\FileSystem\<ServiceName>"
+ if (driverName.Buffer == NULL)
{
- DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
- return Status;
+ status = IopGetRegistryValue(ServiceHandle, L"Type", &kvInfo);
+ if (!NT_SUCCESS(status) || kvInfo->Type != REG_DWORD)
+ {
+ ExFreePool(kvInfo);
+ ExFreePoolWithTag(basicInfo, TAG_IO); // container for serviceName
+ return STATUS_ILL_FORMED_SERVICE_ENTRY;
+ }
+
+ UINT32 driverType;
+ RtlMoveMemory(&driverType, (PVOID)((ULONG_PTR)kvInfo +
kvInfo->DataOffset), sizeof(UINT32));
+ ExFreePool(kvInfo);
+
+ driverName.Length = 0;
+ if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType ==
SERVICE_FILE_SYSTEM_DRIVER)
+ driverName.MaximumLength = sizeof(FILESYSTEM_ROOT_NAME) +
serviceName.Length;
+ else
+ driverName.MaximumLength = sizeof(DRIVER_ROOT_NAME) + serviceName.Length;
+ driverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, driverName.MaximumLength,
TAG_IO);
+ if (!driverName.Buffer)
+ {
+ ExFreePoolWithTag(basicInfo, TAG_IO); // container for serviceName
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType ==
SERVICE_FILE_SYSTEM_DRIVER)
+ RtlAppendUnicodeToString(&driverName, FILESYSTEM_ROOT_NAME);
+ else
+ RtlAppendUnicodeToString(&driverName, DRIVER_ROOT_NAME);
+
+ RtlAppendUnicodeStringToString(&driverName, &serviceName);
}
- *DriverObject = Object;
+ if (ServiceName)
+ {
+ PWCHAR buf = ExAllocatePoolWithTag(PagedPool, serviceName.Length, TAG_IO);
+ if (!buf)
+ {
+ ExFreePoolWithTag(basicInfo, TAG_IO); // container for serviceName
+ ExFreePoolWithTag(driverName.Buffer, TAG_IO);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlMoveMemory(buf, serviceName.Buffer, serviceName.Length);
+ ServiceName->MaximumLength = serviceName.Length;
+ ServiceName->Length = serviceName.Length;
+ ServiceName->Buffer = buf;
+ }
+ ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
- DPRINT("Driver Object: %p\n", Object);
+ *DriverName = driverName;
return STATUS_SUCCESS;
}
@@ -317,162 +380,6 @@ IopNormalizeImagePath(
return STATUS_SUCCESS;
}
-NTSTATUS
-IopQueryServiceSettings(
- _In_ PUNICODE_STRING ServiceName,
- _Out_ PUNICODE_STRING ServiceImagePath,
- _Out_ PULONG ServiceStart)
-{
- NTSTATUS Status;
- RTL_QUERY_REGISTRY_TABLE QueryTable[3];
- UNICODE_STRING CCSName = RTL_CONSTANT_STRING(
- L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
- HANDLE CCSKey, ServiceKey;
-
- /* Open CurrentControlSet */
- Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status
0x%lx\n",
- &CCSName, Status);
- return Status;
- }
-
- /* Open service key */
- Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status
0x%lx\n",
- ServiceName, Status);
- ZwClose(CCSKey);
- return Status;
- }
-
- /*
- * Get information about the service.
- */
- RtlZeroMemory(QueryTable, sizeof(QueryTable));
-
- RtlInitUnicodeString(ServiceImagePath, NULL);
-
- QueryTable[0].Name = L"Start";
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- QueryTable[0].EntryContext = ServiceStart;
-
- QueryTable[1].Name = L"ImagePath";
- QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
- QueryTable[1].EntryContext = ServiceImagePath;
-
- Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
- (PWSTR)ServiceKey,
- QueryTable,
- NULL,
- NULL);
-
- ZwClose(ServiceKey);
- ZwClose(CCSKey);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("RtlQueryRegistryValues() failed for '%wZ' (Status
%lx)\n", ServiceName, Status);
- return Status;
- }
-
- return Status;
-}
-
-/*
- * IopLoadServiceModule
- *
- * Load a module specified by registry settings for service.
- *
- * Parameters
- * ServiceName
- * Name of the service to load.
- *
- * Return Value
- * Status
- */
-NTSTATUS
-FASTCALL
-IopLoadServiceModule(
- IN PUNICODE_STRING ServiceName,
- OUT PLDR_DATA_TABLE_ENTRY *ModuleObject)
-{
- ULONG ServiceStart;
- UNICODE_STRING ServiceImagePath;
- NTSTATUS Status;
- PVOID BaseAddress;
-
- ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDriverLoadResource));
- ASSERT(ServiceName->Length);
- DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
-
- if (ExpInTextModeSetup)
- {
- /* We have no registry, but luckily we know where all the drivers are */
- DPRINT1("IopLoadServiceModule(%wZ, 0x%p) called in ExpInTextModeSetup
mode...\n", ServiceName, ModuleObject);
-
- /* ServiceStart < 4 is all that matters */
- ServiceStart = 0;
-
- /* IopNormalizeImagePath will do all of the work for us if we give it an empty
string */
- RtlInitEmptyUnicodeString(&ServiceImagePath, NULL, 0);
- }
- else
- {
- Status = IopQueryServiceSettings(ServiceName, &ServiceImagePath,
&ServiceStart);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("IopQueryServiceSettings() failed for '%wZ' (Status
%lx)\n", ServiceName, Status);
- return Status;
- }
- }
-
- /*
- * Normalize the image path for all later processing.
- */
- Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
- return Status;
- }
-
- /*
- * Case for disabled drivers
- */
- if (ServiceStart >= 4)
- {
- /* We can't load this */
- Status = STATUS_DRIVER_UNABLE_TO_LOAD;
- }
- else
- {
- DPRINT("Loading module from %wZ\n", &ServiceImagePath);
- Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0,
(PVOID)ModuleObject, &BaseAddress);
- if (NT_SUCCESS(Status))
- {
- IopDisplayLoadingMessage(ServiceName);
- }
- }
-
- ExFreePool(ServiceImagePath.Buffer);
-
- /*
- * Now check if the module was loaded successfully.
- */
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Module loading failed (Status %x)\n", Status);
- }
-
- DPRINT("Module loading (Status %x)\n", Status);
-
- return Status;
-}
-
/**
* @brief Initialize a loaded driver
*
@@ -504,112 +411,18 @@ IopInitializeDriverModule(
PAGED_CODE();
- // get the ServiceName
- PKEY_BASIC_INFORMATION basicInfo;
- ULONG infoLength;
- Status = ZwQueryKey(ServiceHandle, KeyBasicInformation, NULL, 0, &infoLength);
- if (Status == STATUS_BUFFER_TOO_SMALL)
- {
- basicInfo = ExAllocatePoolWithTag(PagedPool, infoLength, TAG_IO);
- if (!basicInfo)
- {
- MmUnloadSystemImage(ModuleObject);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- Status = ZwQueryKey(ServiceHandle, KeyBasicInformation, basicInfo, infoLength,
&infoLength);
- if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(basicInfo, TAG_IO);
- MmUnloadSystemImage(ModuleObject);
- return Status;
- }
-
- ServiceName.Length = basicInfo->NameLength;
- ServiceName.MaximumLength = basicInfo->NameLength;
- ServiceName.Buffer = basicInfo->Name;
- }
- else
+ Status = IopGetDriverNames(ServiceHandle, &DriverName, &ServiceName);
+ if (!NT_SUCCESS(Status))
{
MmUnloadSystemImage(ModuleObject);
- return NT_SUCCESS(Status) ? STATUS_UNSUCCESSFUL : Status;
- }
-
- // Make the DriverName field of a DRIVER_OBJECT
- PKEY_VALUE_FULL_INFORMATION kvInfo;
-
- // 1. Check the "ObjectName" field in the driver's registry key (it has
the priority)
- Status = IopGetRegistryValue(ServiceHandle, L"ObjectName", &kvInfo);
- if (NT_SUCCESS(Status))
- {
- // we're got the ObjectName. Use it to create the DRIVER_OBJECT
- if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0)
- {
- ExFreePool(kvInfo);
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
- MmUnloadSystemImage(ModuleObject);
- return STATUS_ILL_FORMED_SERVICE_ENTRY;
- }
-
- DriverName.Length = kvInfo->DataLength - sizeof(WCHAR),
- DriverName.MaximumLength = kvInfo->DataLength,
- DriverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, DriverName.MaximumLength,
TAG_IO);
- if (!DriverName.Buffer)
- {
- ExFreePool(kvInfo);
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
- MmUnloadSystemImage(ModuleObject);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- RtlMoveMemory(DriverName.Buffer,
- (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
- DriverName.Length);
- ExFreePool(kvInfo);
- }
- else
- {
- // 2. there is no "ObjectName" - construct it ourselves. Depending on a
driver type,
- // it will be either "\Driver\<ServiceName>" or
"\FileSystem\<ServiceName>"
-
- Status = IopGetRegistryValue(ServiceHandle, L"Type", &kvInfo);
- if (!NT_SUCCESS(Status) || kvInfo->Type != REG_DWORD)
- {
- ExFreePool(kvInfo);
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
- MmUnloadSystemImage(ModuleObject);
- return STATUS_ILL_FORMED_SERVICE_ENTRY;
- }
-
- UINT32 driverType;
- RtlMoveMemory(&driverType, (PVOID)((ULONG_PTR)kvInfo +
kvInfo->DataOffset), sizeof(UINT32));
- ExFreePool(kvInfo);
-
- DriverName.Length = 0;
- if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType ==
SERVICE_FILE_SYSTEM_DRIVER)
- DriverName.MaximumLength = sizeof(FILESYSTEM_ROOT_NAME) +
ServiceName.Length;
- else
- DriverName.MaximumLength = sizeof(DRIVER_ROOT_NAME) + ServiceName.Length;
- DriverName.Buffer = ExAllocatePoolWithTag(NonPagedPool, DriverName.MaximumLength,
TAG_IO);
- if (!DriverName.Buffer)
- {
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
- MmUnloadSystemImage(ModuleObject);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- if (driverType == SERVICE_RECOGNIZER_DRIVER || driverType ==
SERVICE_FILE_SYSTEM_DRIVER)
- RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
- else
- RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
-
- RtlAppendUnicodeStringToString(&DriverName, &ServiceName);
+ return Status;
}
DPRINT("Driver name: '%wZ'\n", &DriverName);
// obtain the registry path for the DriverInit routine
PKEY_NAME_INFORMATION nameInfo;
+ ULONG infoLength;
Status = ZwQueryKey(ServiceHandle, KeyNameInformation, NULL, 0, &infoLength);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
@@ -644,7 +457,7 @@ IopInitializeDriverModule(
if (!NT_SUCCESS(Status))
{
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
+ RtlFreeUnicodeString(&ServiceName);
RtlFreeUnicodeString(&DriverName);
MmUnloadSystemImage(ModuleObject);
return Status;
@@ -672,7 +485,7 @@ IopInitializeDriverModule(
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
+ RtlFreeUnicodeString(&ServiceName);
RtlFreeUnicodeString(&DriverName);
MmUnloadSystemImage(ModuleObject);
DPRINT1("Error while creating driver object \"%wZ\" status
%x\n", &DriverName, Status);
@@ -706,7 +519,7 @@ IopInitializeDriverModule(
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(nameInfo, TAG_IO);
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
+ RtlFreeUnicodeString(&ServiceName);
RtlFreeUnicodeString(&DriverName);
return Status;
}
@@ -725,7 +538,7 @@ IopInitializeDriverModule(
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
+ RtlFreeUnicodeString(&ServiceName);
RtlFreeUnicodeString(&DriverName);
return Status;
}
@@ -743,14 +556,14 @@ IopInitializeDriverModule(
ObMakeTemporaryObject(driverObject);
ObDereferenceObject(driverObject);
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
+ RtlFreeUnicodeString(&ServiceName);
RtlFreeUnicodeString(&DriverName);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy the name and set it in the driver extension */
RtlCopyUnicodeString(&serviceKeyName, &ServiceName);
- ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
+ RtlFreeUnicodeString(&ServiceName);
driverObject->DriverExtension->ServiceKeyName = serviceKeyName;
/* Make a copy of the driver name to store in the driver object */
@@ -836,186 +649,6 @@ IopInitializeDriverModule(
return STATUS_SUCCESS;
}
-/*
- * IopAttachFilterDriversCallback
- *
- * Internal routine used by IopAttachFilterDrivers.
- */
-NTSTATUS
-NTAPI
-IopAttachFilterDriversCallback(
- PWSTR ValueName,
- ULONG ValueType,
- PVOID ValueData,
- ULONG ValueLength,
- PVOID Context,
- PVOID EntryContext)
-{
- PDEVICE_NODE DeviceNode = Context;
- UNICODE_STRING ServiceName;
- PWCHAR Filters;
- PLDR_DATA_TABLE_ENTRY ModuleObject;
- PDRIVER_OBJECT DriverObject;
- NTSTATUS Status;
-
- /* No filter value present */
- if (ValueType == REG_NONE)
- return STATUS_SUCCESS;
-
- for (Filters = ValueData;
- ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
- *Filters != 0;
- Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
- {
- DPRINT("Filter Driver: %S (%wZ)\n", Filters,
&DeviceNode->InstancePath);
-
- ServiceName.Buffer = Filters;
- ServiceName.MaximumLength =
- ServiceName.Length = (USHORT)wcslen(Filters) * sizeof(WCHAR);
-
- UNICODE_STRING RegistryPath;
-
- // Make the registry path for the driver
- RegistryPath.Length = 0;
- RegistryPath.MaximumLength = sizeof(ServicesKeyName) + ServiceName.Length;
- RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
RegistryPath.MaximumLength, TAG_IO);
- if (RegistryPath.Buffer == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlAppendUnicodeToString(&RegistryPath, ServicesKeyName);
- RtlAppendUnicodeStringToString(&RegistryPath, &ServiceName);
-
- HANDLE serviceHandle;
- Status = IopOpenRegistryKeyEx(&serviceHandle, NULL, &RegistryPath,
KEY_READ);
- RtlFreeUnicodeString(&RegistryPath);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- Status = IopGetDriverObject(&DriverObject,
- &ServiceName,
- FALSE);
- if (!NT_SUCCESS(Status))
- {
- KeEnterCriticalRegion();
- ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
-
- /* Load and initialize the filter driver */
- Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
- if (!NT_SUCCESS(Status))
- {
- ExReleaseResourceLite(&IopDriverLoadResource);
- KeLeaveCriticalRegion();
- ZwClose(serviceHandle);
- return Status;
- }
-
- NTSTATUS driverEntryStatus;
- Status = IopInitializeDriverModule(ModuleObject,
- serviceHandle,
- &DriverObject,
- &driverEntryStatus);
-
- ExReleaseResourceLite(&IopDriverLoadResource);
- KeLeaveCriticalRegion();
-
- if (!NT_SUCCESS(Status))
- {
- ZwClose(serviceHandle);
- return Status;
- }
- }
-
- ZwClose(serviceHandle);
-
- Status = IopInitializeDevice(DeviceNode, DriverObject);
-
- /* Remove extra reference */
- ObDereferenceObject(DriverObject);
-
- if (!NT_SUCCESS(Status))
- return Status;
- }
-
- return STATUS_SUCCESS;
-}
-
-/*
- * IopAttachFilterDrivers
- *
- * Load filter drivers for specified device node.
- *
- * Parameters
- * Lower
- * Set to TRUE for loading lower level filters or FALSE for upper
- * level filters.
- */
-NTSTATUS
-FASTCALL
-IopAttachFilterDrivers(
- PDEVICE_NODE DeviceNode,
- HANDLE EnumSubKey,
- HANDLE ClassKey,
- BOOLEAN Lower)
-{
- RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
- NTSTATUS Status;
-
- /*
- * First load the device filters
- */
- QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
- if (Lower)
- QueryTable[0].Name = L"LowerFilters";
- else
- QueryTable[0].Name = L"UpperFilters";
- QueryTable[0].Flags = 0;
- QueryTable[0].DefaultType = REG_NONE;
-
- Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
- (PWSTR)EnumSubKey,
- QueryTable,
- DeviceNode,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Failed to load device %s filters: %08X\n",
- Lower ? "lower" : "upper", Status);
- return Status;
- }
-
- QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
- if (Lower)
- QueryTable[0].Name = L"LowerFilters";
- else
- QueryTable[0].Name = L"UpperFilters";
- QueryTable[0].EntryContext = NULL;
- QueryTable[0].Flags = 0;
- QueryTable[0].DefaultType = REG_NONE;
-
- if (ClassKey == NULL)
- {
- return STATUS_SUCCESS;
- }
-
- Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
- (PWSTR)ClassKey,
- QueryTable,
- DeviceNode,
- NULL);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Failed to load class %s filters: %08X\n",
- Lower ? "lower" : "upper", Status);
- return Status;
- }
-
- return STATUS_SUCCESS;
-}
-
NTSTATUS
NTAPI
MiResolveImageReferences(IN PVOID ImageBase,
diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c
index 17347573216..12f3e443c30 100644
--- a/ntoskrnl/io/pnpmgr/devaction.c
+++ b/ntoskrnl/io/pnpmgr/devaction.c
@@ -49,6 +49,8 @@ KSPIN_LOCK IopDeviceActionLock;
KEVENT PiEnumerationFinished;
static const WCHAR ServicesKeyName[] =
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
+#define TAG_PNP_DEVACTION 'aDpP'
+
/* TYPES *********************************************************************/
typedef struct _DEVICE_ACTION_REQUEST
@@ -60,6 +62,29 @@ typedef struct _DEVICE_ACTION_REQUEST
DEVICE_ACTION Action;
} DEVICE_ACTION_REQUEST, *PDEVICE_ACTION_REQUEST;
+typedef enum _ADD_DEV_DRIVER_TYPE
+{
+ LowerFilter,
+ LowerClassFilter,
+ DeviceDriver,
+ UpperFilter,
+ UpperClassFilter
+} ADD_DEV_DRIVER_TYPE;
+
+typedef struct _ADD_DEV_DRIVERS_LIST
+{
+ LIST_ENTRY ListEntry;
+ PDRIVER_OBJECT DriverObject;
+ ADD_DEV_DRIVER_TYPE DriverType;
+} ADD_DEV_DRIVERS_LIST, *PADD_DEV_DRIVERS_LIST;
+
+typedef struct _ATTACH_FILTER_DRIVERS_CONTEXT
+{
+ ADD_DEV_DRIVER_TYPE DriverType;
+ PDEVICE_NODE DeviceNode;
+ PLIST_ENTRY DriversListHead;
+} ATTACH_FILTER_DRIVERS_CONTEXT, *PATTACH_FILTER_DRIVERS_CONTEXT;
+
/* FUNCTIONS *****************************************************************/
PDEVICE_OBJECT
@@ -325,6 +350,500 @@ IopCreateDeviceInstancePath(
return STATUS_SUCCESS;
}
+/**
+ * @brief Loads and/or returns the driver associated with the registry entry if the
driver
+ * is enabled. In case of an error, sets up a corresponding Problem to the
DeviceNode
+ */
+static
+NTSTATUS
+NTAPI
+PiAttachFilterDriversCallback(
+ PWSTR ValueName,
+ ULONG ValueType,
+ PVOID ValueData,
+ ULONG ValueLength,
+ PVOID Ctx,
+ PVOID EntryContext)
+{
+ PATTACH_FILTER_DRIVERS_CONTEXT context = Ctx;
+ PDRIVER_OBJECT DriverObject;
+ NTSTATUS Status;
+ BOOLEAN loadDrivers = (BOOLEAN)(ULONG_PTR)EntryContext;
+
+ PAGED_CODE();
+
+ // No filter value present
+ if (ValueType != REG_SZ)
+ return STATUS_SUCCESS;
+
+ if (ValueLength <= sizeof(WCHAR))
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ // open the service registry key
+ UNICODE_STRING serviceName = { .Length = 0 }, servicesKeyName;
+ RtlInitUnicodeString(&serviceName, ValueData);
+ RtlInitUnicodeString(&servicesKeyName, ServicesKeyName);
+
+ HANDLE ccsServicesHandle, serviceHandle = NULL;
+
+ Status = IopOpenRegistryKeyEx(&ccsServicesHandle, NULL, &servicesKeyName,
KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to open a registry key for \"%wZ\" (status
%x)\n", &serviceName, Status);
+ return Status;
+ }
+
+ Status = IopOpenRegistryKeyEx(&serviceHandle, ccsServicesHandle,
&serviceName, KEY_READ);
+ ZwClose(ccsServicesHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to open a registry key for \"%wZ\" (status
%x)\n", &serviceName, Status);
+ return Status;
+ }
+
+ PADD_DEV_DRIVERS_LIST driverEntry = ExAllocatePoolWithTag(PagedPool,
+ sizeof(*driverEntry),
+ TAG_PNP_DEVACTION);
+
+ if (!driverEntry)
+ {
+ DPRINT1("Failed to allocate driverEntry for \"%wZ\"\n",
&serviceName);
+ ZwClose(serviceHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // check if the driver is disabled
+ PKEY_VALUE_FULL_INFORMATION kvInfo;
+ SERVICE_LOAD_TYPE startType = DisableLoad;
+
+ Status = IopGetRegistryValue(serviceHandle, L"Start", &kvInfo);
+ if (NT_SUCCESS(Status) && kvInfo->Type == REG_DWORD)
+ {
+ RtlMoveMemory(&startType,
+ (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
+ sizeof(startType));
+ ExFreePool(kvInfo);
+ }
+
+ // TODO: take into account other start types (like SERVICE_DEMAND_START)
+ if (startType >= DisableLoad)
+ {
+ if (!(context->DeviceNode->Flags & DNF_HAS_PROBLEM))
+ {
+ PiSetDevNodeProblem(context->DeviceNode, CM_PROB_DISABLED_SERVICE);
+ }
+
+ DPRINT("Service \"%wZ\" is disabled (start type %u)\n",
&serviceName, startType);
+ Status = STATUS_UNSUCCESSFUL;
+ goto Cleanup;
+ }
+
+ // check if the driver is already loaded
+ UNICODE_STRING driverName;
+ Status = IopGetDriverNames(serviceHandle, &driverName, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Unable to obtain the driver name for \"%wZ\"\n",
&serviceName);
+ goto Cleanup;
+ }
+
+ // try to open it
+ Status = ObReferenceObjectByName(&driverName,
+ OBJ_OPENIF | OBJ_KERNEL_HANDLE |
OBJ_CASE_INSENSITIVE,
+ NULL, /* PassedAccessState */
+ 0, /* DesiredAccess */
+ IoDriverObjectType,
+ KernelMode,
+ NULL, /* ParseContext */
+ (PVOID*)&DriverObject);
+ RtlFreeUnicodeString(&driverName);
+
+ // the driver was not probably loaded, try to load
+ if (!NT_SUCCESS(Status))
+ {
+ if (loadDrivers)
+ {
+ Status = IopLoadDriver(serviceHandle, &DriverObject);
+ }
+ else
+ {
+ DPRINT("Service \"%wZ\" will not be loaded now\n",
&serviceName);
+ // return failure, the driver will be loaded later (in a subsequent call)
+ Status = STATUS_UNSUCCESSFUL;
+ goto Cleanup;
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ driverEntry->DriverObject = DriverObject;
+ driverEntry->DriverType = context->DriverType;
+ InsertTailList(context->DriversListHead, &driverEntry->ListEntry);
+ ZwClose(serviceHandle);
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ if (!(context->DeviceNode->Flags & DNF_HAS_PROBLEM))
+ {
+ switch (Status)
+ {
+ case STATUS_INSUFFICIENT_RESOURCES:
+ PiSetDevNodeProblem(context->DeviceNode, CM_PROB_OUT_OF_MEMORY);
+ break;
+ case STATUS_FAILED_DRIVER_ENTRY:
+ PiSetDevNodeProblem(context->DeviceNode,
CM_PROB_FAILED_DRIVER_ENTRY);
+ break;
+ case STATUS_ILL_FORMED_SERVICE_ENTRY:
+ PiSetDevNodeProblem(context->DeviceNode,
CM_PROB_DRIVER_SERVICE_KEY_INVALID);
+ break;
+ default:
+ PiSetDevNodeProblem(context->DeviceNode,
CM_PROB_DRIVER_FAILED_LOAD);
+ break;
+ }
+ }
+
+ DPRINT1("Failed to load driver \"%wZ\" for %wZ (status
%x)\n",
+ &serviceName, &context->DeviceNode->InstancePath, Status);
+ }
+
+Cleanup:
+ ExFreePoolWithTag(driverEntry, TAG_PNP_DEVACTION);
+ if (serviceHandle)
+ {
+ ZwClose(serviceHandle);
+ }
+ return Status;
+}
+
+
+/**
+ * @brief Calls PiAttachFilterDriversCallback for filter drivers (if any)
+ */
+static
+NTSTATUS
+PiAttachFilterDrivers(
+ PLIST_ENTRY DriversListHead,
+ PDEVICE_NODE DeviceNode,
+ HANDLE EnumSubKey,
+ HANDLE ClassKey,
+ BOOLEAN Lower,
+ BOOLEAN LoadDrivers)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
+ ATTACH_FILTER_DRIVERS_CONTEXT routineContext;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ routineContext.DriversListHead = DriversListHead;
+ routineContext.DeviceNode = DeviceNode;
+
+ // First add device filters
+ routineContext.DriverType = Lower ? LowerFilter : UpperFilter;
+ QueryTable[0] = (RTL_QUERY_REGISTRY_TABLE){
+ .QueryRoutine = PiAttachFilterDriversCallback,
+ .Name = Lower ? L"LowerFilters" : L"UpperFilters",
+ .DefaultType = REG_NONE,
+ .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
+ };
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+ (PWSTR)EnumSubKey,
+ QueryTable,
+ &routineContext,
+ NULL);
+ if (ClassKey == NULL)
+ {
+ return Status;
+ }
+
+ // Then add device class filters
+ routineContext.DriverType = Lower ? LowerClassFilter : UpperClassFilter;
+ QueryTable[0] = (RTL_QUERY_REGISTRY_TABLE){
+ .QueryRoutine = PiAttachFilterDriversCallback,
+ .Name = Lower ? L"LowerFilters" : L"UpperFilters",
+ .DefaultType = REG_NONE,
+ .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
+ };
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+ (PWSTR)ClassKey,
+ QueryTable,
+ &routineContext,
+ NULL);
+ return Status;
+}
+
+/**
+ * @brief Loads all drivers for a device node (actual service and filters)
+ * and calls their AddDevice routine
+ *
+ * @param[in] DeviceNode The device node
+ * @param[in] LoadDrivers Whether to load drivers if they are not loaded yet
+ * (used when storage subsystem is not yet initialized)
+ */
+NTSTATUS
+PiCallDriverAddDevice(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ BOOLEAN LoadDrivers)
+{
+ NTSTATUS Status;
+ HANDLE EnumRootKey, SubKey;
+ HANDLE ClassKey = NULL;
+ UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
+ static UNICODE_STRING ccsControlClass =
+
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
+ PKEY_VALUE_FULL_INFORMATION kvInfo = NULL;
+
+ PAGED_CODE();
+
+ // open the enumeration root key
+ Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL, &EnumRoot, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status
%x)\n", &EnumRoot, Status);
+ return Status;
+ }
+
+ // open an instance subkey
+ Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
&DeviceNode->InstancePath, KEY_READ);
+ ZwClose(EnumRootKey);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status
%x)\n",
+ &DeviceNode->InstancePath, Status);
+ return Status;
+ }
+
+ // try to get the class GUID of an instance and its registry key
+ Status = IopGetRegistryValue(SubKey, REGSTR_VAL_CLASSGUID, &kvInfo);
+ if (NT_SUCCESS(Status) && kvInfo->Type == REG_SZ &&
kvInfo->DataLength > sizeof(WCHAR))
+ {
+ UNICODE_STRING classGUID = {
+ .MaximumLength = kvInfo->DataLength,
+ .Length = kvInfo->DataLength - sizeof(UNICODE_NULL),
+ .Buffer = (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset)
+ };
+ HANDLE ccsControlHandle;
+
+ Status = IopOpenRegistryKeyEx(&ccsControlHandle, NULL, &ccsControlClass,
KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status
%x)\n",
+ &ccsControlClass, Status);
+ }
+ else
+ {
+ // open the CCS\Constol\Class\<ClassGUID> key
+ Status = IopOpenRegistryKeyEx(&ClassKey, ccsControlHandle,
&classGUID, KEY_READ);
+ ZwClose(ccsControlHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to open class key \"%wZ\" (status
%x)\n", &classGUID, Status);
+ }
+ }
+
+ if (ClassKey)
+ {
+ // Check the Properties key of a class too
+ // Windows fills some device properties from this key (which is protected)
+ // TODO: add the device properties from this key
+
+ UNICODE_STRING properties =
RTL_CONSTANT_STRING(REGSTR_KEY_DEVICE_PROPERTIES);
+ HANDLE propertiesHandle;
+
+ Status = IopOpenRegistryKeyEx(&propertiesHandle, ClassKey,
&properties, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Properties key failed to open for \"%wZ\" (status
%x)\n",
+ &classGUID, Status);
+ }
+ else
+ {
+ ZwClose(propertiesHandle);
+ }
+ }
+ ExFreePool(kvInfo);
+ }
+
+ // the driver loading order:
+ // 1. LowerFilters
+ // 2. LowerClassFilters
+ // 3. Device driver (only one service!)
+ // 4. UpperFilters
+ // 5. UpperClassFilters
+
+ LIST_ENTRY drvListHead;
+ InitializeListHead(&drvListHead);
+
+ // lower (class) filters
+ Status = PiAttachFilterDrivers(&drvListHead, DeviceNode, SubKey, ClassKey, TRUE,
LoadDrivers);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ ATTACH_FILTER_DRIVERS_CONTEXT routineContext = {
+ .DriversListHead = &drvListHead,
+ .DriverType = DeviceDriver,
+ .DeviceNode = DeviceNode
+ };
+
+ RTL_QUERY_REGISTRY_TABLE queryTable[2] = {{
+ .QueryRoutine = PiAttachFilterDriversCallback,
+ .Name = L"Service",
+ .Flags = RTL_QUERY_REGISTRY_REQUIRED,
+ .DefaultType = REG_SZ, // REG_MULTI_SZ is not allowed here
+ .DefaultData = L"",
+ .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
+ },};
+
+ // device driver
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+ (PWSTR)SubKey,
+ queryTable,
+ &routineContext,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ // do nothing
+ }
+ // if a driver is not found, but a device allows raw access -> proceed
+ else if (Status == STATUS_OBJECT_NAME_NOT_FOUND &&
+ (DeviceNode->CapabilityFlags & 0x00000040)) // CM_DEVCAP_RAWDEVICEOK
+ {
+ // add a dummy entry to the drivers list (need for later processing)
+ PADD_DEV_DRIVERS_LIST driverEntry = ExAllocatePoolZero(PagedPool,
+ sizeof(*driverEntry),
+ TAG_PNP_DEVACTION);
+ driverEntry->DriverType = DeviceDriver;
+ InsertTailList(&drvListHead, &driverEntry->ListEntry);
+ DPRINT("No service for \"%wZ\" (RawDeviceOK)\n",
&DeviceNode->InstancePath);
+ }
+ else
+ {
+ if (Status == STATUS_OBJECT_TYPE_MISMATCH && !(DeviceNode->Flags &
DNF_HAS_PROBLEM))
+ {
+ PiSetDevNodeProblem(DeviceNode, CM_PROB_REGISTRY);
+ }
+ DPRINT("No service for \"%wZ\" (loadDrv: %u)\n",
&DeviceNode->InstancePath, LoadDrivers);
+ goto Cleanup;
+ }
+
+ // upper (class) filters
+ Status = PiAttachFilterDrivers(&drvListHead, DeviceNode, SubKey, ClassKey, FALSE,
LoadDrivers);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ // finally loop through the stack and call AddDevice for every driver
+ for (PLIST_ENTRY listEntry = drvListHead.Flink;
+ listEntry != &drvListHead;
+ listEntry = listEntry->Flink)
+ {
+ PADD_DEV_DRIVERS_LIST driverEntry;
+ driverEntry = CONTAINING_RECORD(listEntry, ADD_DEV_DRIVERS_LIST, ListEntry);
+ PDRIVER_OBJECT driverObject = driverEntry->DriverObject;
+
+ // FIXME: ReactOS is not quite ready for this assert
+ // (legacy drivers should not have AddDevice routine)
+ // ASSERT(!(DriverObject->Flags & DRVO_LEGACY_DRIVER));
+
+ if (driverObject && driverObject->DriverExtension->AddDevice)
+ {
+ Status =
driverObject->DriverExtension->AddDevice(driverEntry->DriverObject,
+
DeviceNode->PhysicalDeviceObject);
+ }
+ else if (driverObject == NULL)
+ {
+ // valid only for DeviceDriver
+ ASSERT(driverEntry->DriverType == DeviceDriver);
+ ASSERT(DeviceNode->CapabilityFlags & 0x00000040); //
CM_DEVCAP_RAWDEVICEOK
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ // HACK: the driver doesn't have a AddDevice routine. We shouldn't be
here,
+ // but ReactOS' PnP stack is not that correct yet
+ DeviceNode->Flags |= DNF_LEGACY_DRIVER;
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ // for filter drivers we don't care about the AddDevice result
+ if (driverEntry->DriverType == DeviceDriver)
+ {
+ if (NT_SUCCESS(Status))
+ {
+ PDEVICE_OBJECT fdo =
IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
+
+ // HACK: Check if we have a ACPI device (needed for power management)
+ if (fdo->DeviceType == FILE_DEVICE_ACPI)
+ {
+ static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
+
+ // There can be only one system power device
+ if (!SystemPowerDeviceNodeCreated)
+ {
+ PopSystemPowerDeviceNode = DeviceNode;
+
ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject);
+ SystemPowerDeviceNodeCreated = TRUE;
+ }
+ }
+
+ ObDereferenceObject(fdo);
+
+ IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
+ }
+ else
+ {
+ // lower filters (if already started) will be removed upon this request
+ PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_ADD);
+ IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
+ IopRemoveDevice(DeviceNode);
+ break;
+ }
+ }
+
+#if DBG
+ PDEVICE_OBJECT attachedDO =
IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject);
+ if (attachedDO->Flags & DO_DEVICE_INITIALIZING)
+ {
+ DPRINT1("DO_DEVICE_INITIALIZING is not cleared on a device
0x%p!\n", attachedDO);
+ }
+#endif
+ }
+
+Cleanup:
+ while (!IsListEmpty(&drvListHead))
+ {
+ PLIST_ENTRY listEntry = RemoveHeadList(&drvListHead);
+ PADD_DEV_DRIVERS_LIST driverEntry;
+ driverEntry = CONTAINING_RECORD(listEntry, ADD_DEV_DRIVERS_LIST, ListEntry);
+
+ // drivers which don't have any devices (in case of failure) will be cleaned
up
+ if (driverEntry->DriverObject)
+ {
+ ObDereferenceObject(driverEntry->DriverObject);
+ }
+ ExFreePoolWithTag(driverEntry, TAG_PNP_DEVACTION);
+ }
+
+ ZwClose(SubKey);
+ if (ClassKey != NULL)
+ {
+ ZwClose(ClassKey);
+ }
+
+ if (DeviceNode->Flags & DNF_ADDED)
+ {
+ IopStartDevice(DeviceNode);
+ }
+
+ return Status;
+}
+
NTSTATUS
NTAPI
IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
@@ -1008,8 +1527,6 @@ IopActionInitChildServices(PDEVICE_NODE DeviceNode,
PVOID Context)
{
PDEVICE_NODE ParentDeviceNode;
- NTSTATUS Status;
- BOOLEAN BootDrivers = !PnpSystemInit;
DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
@@ -1043,114 +1560,7 @@ IopActionInitChildServices(PDEVICE_NODE DeviceNode,
IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
return STATUS_SUCCESS;
- if (DeviceNode->ServiceName.Buffer == NULL)
- {
- /* We don't need to worry about loading the driver because we're
- * being driven in raw mode so our parent must be loaded to get here */
- Status = IopInitializeDevice(DeviceNode, NULL);
- if (NT_SUCCESS(Status))
- {
- Status = IopStartDevice(DeviceNode);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
- &DeviceNode->InstancePath, Status);
- }
- }
- }
- else
- {
- PLDR_DATA_TABLE_ENTRY ModuleObject;
- PDRIVER_OBJECT DriverObject;
-
- /* Get existing DriverObject pointer (in case the driver has
- already been loaded and initialized) */
- Status = IopGetDriverObject(
- &DriverObject,
- &DeviceNode->ServiceName,
- FALSE);
-
- if (!NT_SUCCESS(Status))
- {
- KeEnterCriticalRegion();
- ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
-
- /* Driver is not initialized, try to load it */
- Status = IopLoadServiceModule(&DeviceNode->ServiceName,
&ModuleObject);
-
- if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
- {
- UNICODE_STRING RegistryPath;
-
- // obtain a handle for driver's RegistryPath
- RegistryPath.Length = 0;
- RegistryPath.MaximumLength = sizeof(ServicesKeyName) +
DeviceNode->ServiceName.Length;
- RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
RegistryPath.MaximumLength, TAG_IO);
- if (RegistryPath.Buffer == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto OpenHandleFail;
- }
- RtlAppendUnicodeToString(&RegistryPath, ServicesKeyName);
- RtlAppendUnicodeStringToString(&RegistryPath,
&DeviceNode->ServiceName);
-
- HANDLE serviceHandle;
- Status = IopOpenRegistryKeyEx(&serviceHandle, NULL,
&RegistryPath, KEY_READ);
- RtlFreeUnicodeString(&RegistryPath);
- if (!NT_SUCCESS(Status))
- {
- goto OpenHandleFail;
- }
-
- /* Initialize the driver */
- NTSTATUS driverEntryStatus;
- Status = IopInitializeDriverModule(ModuleObject,
- serviceHandle,
- &DriverObject,
- &driverEntryStatus);
- ZwClose(serviceHandle);
-
- if (!NT_SUCCESS(Status))
- DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY;
- }
- else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD)
- {
- DPRINT1("Service '%wZ' is disabled\n",
&DeviceNode->ServiceName);
- DeviceNode->Problem = CM_PROB_DISABLED_SERVICE;
- }
- else
- {
- DPRINT("IopLoadServiceModule(%wZ) failed with status
0x%08x\n",
- &DeviceNode->ServiceName, Status);
- if (!BootDrivers)
- DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
- }
-OpenHandleFail:
- ExReleaseResourceLite(&IopDriverLoadResource);
- KeLeaveCriticalRegion();
- }
-
- /* Driver is loaded and initialized at this point */
- if (NT_SUCCESS(Status))
- {
- /* Initialize the device, including all filters */
- Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
-
- /* Remove the extra reference */
- ObDereferenceObject(DriverObject);
- }
- else
- {
- /*
- * Don't disable when trying to load only boot drivers
- */
- if (!BootDrivers)
- {
- IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
- }
- }
- }
-
+ PiCallDriverAddDevice(DeviceNode, PnPBootDriversLoaded);
return STATUS_SUCCESS;
}
diff --git a/ntoskrnl/io/pnpmgr/devnode.c b/ntoskrnl/io/pnpmgr/devnode.c
index 0442e1765c2..090419f18a9 100644
--- a/ntoskrnl/io/pnpmgr/devnode.c
+++ b/ntoskrnl/io/pnpmgr/devnode.c
@@ -100,6 +100,23 @@ PiInsertDevNode(
DeviceNode->Level = ParentNode->Level + 1;
}
+VOID
+PiSetDevNodeProblem(
+ _In_ PDEVICE_NODE DeviceNode,
+ _In_ UINT32 Problem)
+{
+ DeviceNode->Flags |= DNF_HAS_PROBLEM;
+ DeviceNode->Problem = Problem;
+}
+
+VOID
+PiClearDevNodeProblem(
+ _In_ PDEVICE_NODE DeviceNode)
+{
+ DeviceNode->Flags &= ~DNF_HAS_PROBLEM;
+ DeviceNode->Problem = 0;
+}
+
/**
* @brief Creates a device node
*
diff --git a/ntoskrnl/io/pnpmgr/pnpinit.c b/ntoskrnl/io/pnpmgr/pnpinit.c
index dd33a4b0258..e32c11e930d 100644
--- a/ntoskrnl/io/pnpmgr/pnpinit.c
+++ b/ntoskrnl/io/pnpmgr/pnpinit.c
@@ -286,145 +286,6 @@ Quickie:
return i;
}
-NTSTATUS
-NTAPI
-PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode,
- IN BOOLEAN LoadDriver,
- IN PDRIVER_OBJECT DriverObject)
-{
- NTSTATUS Status;
- HANDLE EnumRootKey, SubKey;
- HANDLE ControlKey, ClassKey = NULL, PropertiesKey;
- UNICODE_STRING ClassGuid, Properties;
- UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
- UNICODE_STRING ControlClass =
-
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
- PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
- PWCHAR Buffer;
-
- /* Open enumeration root key */
- Status = IopOpenRegistryKeyEx(&EnumRootKey,
- NULL,
- &EnumRoot,
- KEY_READ);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status
0x%lx\n",
- &EnumRoot, Status);
- return Status;
- }
-
- /* Open instance subkey */
- Status = IopOpenRegistryKeyEx(&SubKey,
- EnumRootKey,
- &DeviceNode->InstancePath,
- KEY_READ);
- ZwClose(EnumRootKey);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status
0x%lx\n",
- &DeviceNode->InstancePath, Status);
- return Status;
- }
-
- /* Get class GUID */
- Status = IopGetRegistryValue(SubKey,
- REGSTR_VAL_CLASSGUID,
- &KeyValueInformation);
- if (NT_SUCCESS(Status))
- {
- /* Convert to unicode string */
- Buffer = (PVOID)((ULONG_PTR)KeyValueInformation +
KeyValueInformation->DataOffset);
- PnpRegSzToString(Buffer, KeyValueInformation->DataLength,
&ClassGuid.Length);
- ClassGuid.MaximumLength = (USHORT)KeyValueInformation->DataLength;
- ClassGuid.Buffer = Buffer;
-
- /* Open the key */
- Status = IopOpenRegistryKeyEx(&ControlKey,
- NULL,
- &ControlClass,
- KEY_READ);
- if (!NT_SUCCESS(Status))
- {
- /* No class key */
- DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status
0x%lx\n",
- &ControlClass, Status);
- }
- else
- {
- /* Open the class key */
- Status = IopOpenRegistryKeyEx(&ClassKey,
- ControlKey,
- &ClassGuid,
- KEY_READ);
- ZwClose(ControlKey);
- if (!NT_SUCCESS(Status))
- {
- /* No class key */
- DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status
0x%lx\n",
- &ClassGuid, Status);
- }
- }
-
- /* Check if we made it till here */
- if (ClassKey)
- {
- /* Get the device properties */
- RtlInitUnicodeString(&Properties, REGSTR_KEY_DEVICE_PROPERTIES);
- Status = IopOpenRegistryKeyEx(&PropertiesKey,
- ClassKey,
- &Properties,
- KEY_READ);
- if (!NT_SUCCESS(Status))
- {
- /* No properties */
- DPRINT("IopOpenRegistryKeyEx() failed for '%wZ' with status
0x%lx\n",
- &Properties, Status);
- PropertiesKey = NULL;
- }
- else
- {
- ZwClose(PropertiesKey);
- }
- }
-
- /* Free the registry data */
- ExFreePool(KeyValueInformation);
- }
-
- /* Do ReactOS-style setup */
- Status = IopAttachFilterDrivers(DeviceNode, SubKey, ClassKey, TRUE);
- if (!NT_SUCCESS(Status))
- {
- IopRemoveDevice(DeviceNode);
- goto Exit;
- }
-
- Status = IopInitializeDevice(DeviceNode, DriverObject);
- if (!NT_SUCCESS(Status))
- {
- goto Exit;
- }
-
- Status = IopAttachFilterDrivers(DeviceNode, SubKey, ClassKey, FALSE);
- if (!NT_SUCCESS(Status))
- {
- IopRemoveDevice(DeviceNode);
- goto Exit;
- }
-
- Status = IopStartDevice(DeviceNode);
-
-Exit:
- /* Close keys and return status */
- ZwClose(SubKey);
- if (ClassKey != NULL)
- {
- ZwClose(ClassKey);
- }
- return Status;
-}
-
CODE_SEG("INIT")
NTSTATUS
NTAPI
diff --git a/ntoskrnl/io/pnpmgr/pnpmgr.c b/ntoskrnl/io/pnpmgr/pnpmgr.c
index 1a72481691b..37290335cfd 100644
--- a/ntoskrnl/io/pnpmgr/pnpmgr.c
+++ b/ntoskrnl/io/pnpmgr/pnpmgr.c
@@ -390,75 +390,6 @@ IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
ZwClose(CriticalDeviceKey);
}
-NTSTATUS
-FASTCALL
-IopInitializeDevice(PDEVICE_NODE DeviceNode,
- PDRIVER_OBJECT DriverObject)
-{
- PDEVICE_OBJECT Fdo;
- NTSTATUS Status;
-
- if (!DriverObject)
- {
- /* Special case for bus driven devices */
- DeviceNode->Flags |= DNF_ADDED;
- return STATUS_SUCCESS;
- }
-
- if (!DriverObject->DriverExtension->AddDevice)
- {
- DeviceNode->Flags |= DNF_LEGACY_DRIVER;
- }
-
- if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
- {
- DeviceNode->Flags |= (DNF_ADDED | DNF_STARTED);
- return STATUS_SUCCESS;
- }
-
- /* This is a Plug and Play driver */
- DPRINT("Plug and Play driver found\n");
- ASSERT(DeviceNode->PhysicalDeviceObject);
-
- DPRINT("Calling %wZ->AddDevice(%wZ)\n",
- &DriverObject->DriverName,
- &DeviceNode->InstancePath);
- Status = DriverObject->DriverExtension->AddDevice(DriverObject,
-
DeviceNode->PhysicalDeviceObject);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
- &DriverObject->DriverName,
- &DeviceNode->InstancePath,
- Status);
- IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
- DeviceNode->Problem = CM_PROB_FAILED_ADD;
- return Status;
- }
-
- Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
-
- /* Check if we have a ACPI device (needed for power management) */
- if (Fdo->DeviceType == FILE_DEVICE_ACPI)
- {
- static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
-
- /* There can be only one system power device */
- if (!SystemPowerDeviceNodeCreated)
- {
- PopSystemPowerDeviceNode = DeviceNode;
- ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject);
- SystemPowerDeviceNodeCreated = TRUE;
- }
- }
-
- ObDereferenceObject(Fdo);
-
- IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
-
- return STATUS_SUCCESS;
-}
-
NTSTATUS
IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
{