[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
This commit is contained in:
Victor Perevertkin 2020-11-26 04:39:38 +03:00
parent 4c95339da0
commit c4c0585f96
No known key found for this signature in database
GPG key ID: C750B7222E9C7830
6 changed files with 677 additions and 835 deletions

View file

@ -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,

View file

@ -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;
/* Create ModuleName string */
if (ServiceName == NULL || ServiceName->Buffer == NULL)
/* We don't know which DriverObject we have to open */
return STATUS_INVALID_PARAMETER_2;
if (FileSystem != FALSE)
RtlInitUnicodeString(&Prefix, FILESYSTEM_ROOT_NAME);
else
RtlInitUnicodeString(&Prefix, DRIVER_ROOT_NAME);
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)
// 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))
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlAppendUnicodeStringToString(&DriverName, &Prefix);
RtlAppendUnicodeStringToString(&DriverName, ServiceName);
// 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;
}
DPRINT("Driver name: '%wZ'\n", &DriverName);
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;
}
/* 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))
{
DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
return Status;
RtlMoveMemory(driverName.Buffer,
(PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
driverName.Length);
ExFreePool(kvInfo);
}
*DriverObject = Object;
// check if we need to get ServiceName as well
PKEY_BASIC_INFORMATION basicInfo;
if (!NT_SUCCESS(status) || ServiceName != NULL)
{
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 Object: %p\n", Object);
status = ZwQueryKey(ServiceHandle, KeyBasicInformation, basicInfo, infoLength, &infoLength);
if (!NT_SUCCESS(status))
{
ExFreePoolWithTag(basicInfo, TAG_IO);
return 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)
{
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);
}
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
*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,

View file

@ -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;
}

View file

@ -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
*

View file

@ -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

View file

@ -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)
{