mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 21:42:57 +00:00
[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:
parent
4c95339da0
commit
c4c0585f96
6 changed files with 677 additions and 835 deletions
|
@ -568,12 +568,9 @@ IopDetectResourceConflict(
|
||||||
// PNP Routines
|
// PNP Routines
|
||||||
//
|
//
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
PiCallDriverAddDevice(
|
||||||
PipCallDriverAddDevice(
|
_In_ PDEVICE_NODE DeviceNode,
|
||||||
IN PDEVICE_NODE DeviceNode,
|
_In_ BOOLEAN LoadDrivers);
|
||||||
IN BOOLEAN LoadDriver,
|
|
||||||
IN PDRIVER_OBJECT DriverObject
|
|
||||||
);
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -612,6 +609,15 @@ PiInsertDevNode(
|
||||||
_In_ PDEVICE_NODE DeviceNode,
|
_In_ PDEVICE_NODE DeviceNode,
|
||||||
_In_ PDEVICE_NODE ParentNode);
|
_In_ PDEVICE_NODE ParentNode);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
PiSetDevNodeProblem(
|
||||||
|
_In_ PDEVICE_NODE DeviceNode,
|
||||||
|
_In_ UINT32 Problem);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
PiClearDevNodeProblem(
|
||||||
|
_In_ PDEVICE_NODE DeviceNode);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
IopFreeDeviceNode(
|
IopFreeDeviceNode(
|
||||||
IN PDEVICE_NODE DeviceNode
|
IN PDEVICE_NODE DeviceNode
|
||||||
|
@ -811,13 +817,6 @@ IopReadyDeviceObjects(
|
||||||
IN PDRIVER_OBJECT Driver
|
IN PDRIVER_OBJECT Driver
|
||||||
);
|
);
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
FASTCALL
|
|
||||||
IopInitializeDevice(
|
|
||||||
IN PDEVICE_NODE DeviceNode,
|
|
||||||
IN PDRIVER_OBJECT DriverObject
|
|
||||||
);
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
IopStartDevice(
|
IopStartDevice(
|
||||||
IN PDEVICE_NODE DeviceNode
|
IN PDEVICE_NODE DeviceNode
|
||||||
|
@ -1110,26 +1109,17 @@ IopDeleteDriver(
|
||||||
IN PVOID ObjectBody
|
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
|
NTSTATUS
|
||||||
IopLoadDriver(
|
IopLoadDriver(
|
||||||
_In_ HANDLE ServiceHandle,
|
_In_ HANDLE ServiceHandle,
|
||||||
_Out_ PDRIVER_OBJECT *DriverObject);
|
_Out_ PDRIVER_OBJECT *DriverObject);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
IopGetDriverNames(
|
||||||
|
_In_ HANDLE ServiceHandle,
|
||||||
|
_Out_ PUNICODE_STRING DriverName,
|
||||||
|
_Out_opt_ PUNICODE_STRING ServiceName);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
IopInitializeDriverModule(
|
IopInitializeDriverModule(
|
||||||
_In_ PLDR_DATA_TABLE_ENTRY ModuleObject,
|
_In_ PLDR_DATA_TABLE_ENTRY ModuleObject,
|
||||||
|
|
|
@ -122,64 +122,127 @@ IopDeleteDriver(IN PVOID ObjectBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
FASTCALL
|
IopGetDriverNames(
|
||||||
IopGetDriverObject(
|
_In_ HANDLE ServiceHandle,
|
||||||
PDRIVER_OBJECT *DriverObject,
|
_Out_ PUNICODE_STRING DriverName,
|
||||||
PUNICODE_STRING ServiceName,
|
_Out_opt_ PUNICODE_STRING ServiceName)
|
||||||
BOOLEAN FileSystem)
|
|
||||||
{
|
{
|
||||||
PDRIVER_OBJECT Object;
|
UNICODE_STRING driverName = {.Buffer = NULL}, serviceName;
|
||||||
UNICODE_STRING Prefix;
|
PKEY_VALUE_FULL_INFORMATION kvInfo;
|
||||||
UNICODE_STRING DriverName;
|
NTSTATUS status;
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
|
PAGED_CODE();
|
||||||
DriverObject, ServiceName, FileSystem);
|
|
||||||
|
|
||||||
*DriverObject = NULL;
|
// 1. Check the "ObjectName" field in the driver's registry key (it has the priority)
|
||||||
|
status = IopGetRegistryValue(ServiceHandle, L"ObjectName", &kvInfo);
|
||||||
/* Create ModuleName string */
|
if (NT_SUCCESS(status))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
// we're got the ObjectName. Use it to create the DRIVER_OBJECT
|
||||||
}
|
if (kvInfo->Type != REG_SZ || kvInfo->DataLength == 0)
|
||||||
RtlAppendUnicodeStringToString(&DriverName, &Prefix);
|
{
|
||||||
RtlAppendUnicodeStringToString(&DriverName, ServiceName);
|
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 */
|
RtlMoveMemory(driverName.Buffer,
|
||||||
Status = ObReferenceObjectByName(&DriverName,
|
(PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
|
||||||
OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, /* Attributes */
|
driverName.Length);
|
||||||
NULL, /* PassedAccessState */
|
ExFreePool(kvInfo);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*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;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -317,162 +380,6 @@ IopNormalizeImagePath(
|
||||||
return STATUS_SUCCESS;
|
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
|
* @brief Initialize a loaded driver
|
||||||
*
|
*
|
||||||
|
@ -504,112 +411,18 @@ IopInitializeDriverModule(
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
// get the ServiceName
|
Status = IopGetDriverNames(ServiceHandle, &DriverName, &ServiceName);
|
||||||
PKEY_BASIC_INFORMATION basicInfo;
|
if (!NT_SUCCESS(Status))
|
||||||
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
|
|
||||||
{
|
{
|
||||||
MmUnloadSystemImage(ModuleObject);
|
MmUnloadSystemImage(ModuleObject);
|
||||||
return NT_SUCCESS(Status) ? STATUS_UNSUCCESSFUL : Status;
|
return 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("Driver name: '%wZ'\n", &DriverName);
|
DPRINT("Driver name: '%wZ'\n", &DriverName);
|
||||||
|
|
||||||
// obtain the registry path for the DriverInit routine
|
// obtain the registry path for the DriverInit routine
|
||||||
PKEY_NAME_INFORMATION nameInfo;
|
PKEY_NAME_INFORMATION nameInfo;
|
||||||
|
ULONG infoLength;
|
||||||
Status = ZwQueryKey(ServiceHandle, KeyNameInformation, NULL, 0, &infoLength);
|
Status = ZwQueryKey(ServiceHandle, KeyNameInformation, NULL, 0, &infoLength);
|
||||||
if (Status == STATUS_BUFFER_TOO_SMALL)
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
||||||
{
|
{
|
||||||
|
@ -644,7 +457,7 @@ IopInitializeDriverModule(
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
|
RtlFreeUnicodeString(&ServiceName);
|
||||||
RtlFreeUnicodeString(&DriverName);
|
RtlFreeUnicodeString(&DriverName);
|
||||||
MmUnloadSystemImage(ModuleObject);
|
MmUnloadSystemImage(ModuleObject);
|
||||||
return Status;
|
return Status;
|
||||||
|
@ -672,7 +485,7 @@ IopInitializeDriverModule(
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
|
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
|
||||||
ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
|
RtlFreeUnicodeString(&ServiceName);
|
||||||
RtlFreeUnicodeString(&DriverName);
|
RtlFreeUnicodeString(&DriverName);
|
||||||
MmUnloadSystemImage(ModuleObject);
|
MmUnloadSystemImage(ModuleObject);
|
||||||
DPRINT1("Error while creating driver object \"%wZ\" status %x\n", &DriverName, Status);
|
DPRINT1("Error while creating driver object \"%wZ\" status %x\n", &DriverName, Status);
|
||||||
|
@ -706,7 +519,7 @@ IopInitializeDriverModule(
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(nameInfo, TAG_IO);
|
ExFreePoolWithTag(nameInfo, TAG_IO);
|
||||||
ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
|
RtlFreeUnicodeString(&ServiceName);
|
||||||
RtlFreeUnicodeString(&DriverName);
|
RtlFreeUnicodeString(&DriverName);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -725,7 +538,7 @@ IopInitializeDriverModule(
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
|
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
|
||||||
ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
|
RtlFreeUnicodeString(&ServiceName);
|
||||||
RtlFreeUnicodeString(&DriverName);
|
RtlFreeUnicodeString(&DriverName);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -743,14 +556,14 @@ IopInitializeDriverModule(
|
||||||
ObMakeTemporaryObject(driverObject);
|
ObMakeTemporaryObject(driverObject);
|
||||||
ObDereferenceObject(driverObject);
|
ObDereferenceObject(driverObject);
|
||||||
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
|
ExFreePoolWithTag(nameInfo, TAG_IO); // container for RegistryPath
|
||||||
ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
|
RtlFreeUnicodeString(&ServiceName);
|
||||||
RtlFreeUnicodeString(&DriverName);
|
RtlFreeUnicodeString(&DriverName);
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the name and set it in the driver extension */
|
/* Copy the name and set it in the driver extension */
|
||||||
RtlCopyUnicodeString(&serviceKeyName, &ServiceName);
|
RtlCopyUnicodeString(&serviceKeyName, &ServiceName);
|
||||||
ExFreePoolWithTag(basicInfo, TAG_IO); // container for ServiceName
|
RtlFreeUnicodeString(&ServiceName);
|
||||||
driverObject->DriverExtension->ServiceKeyName = serviceKeyName;
|
driverObject->DriverExtension->ServiceKeyName = serviceKeyName;
|
||||||
|
|
||||||
/* Make a copy of the driver name to store in the driver object */
|
/* Make a copy of the driver name to store in the driver object */
|
||||||
|
@ -836,186 +649,6 @@ IopInitializeDriverModule(
|
||||||
return STATUS_SUCCESS;
|
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
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
MiResolveImageReferences(IN PVOID ImageBase,
|
MiResolveImageReferences(IN PVOID ImageBase,
|
||||||
|
|
|
@ -49,6 +49,8 @@ KSPIN_LOCK IopDeviceActionLock;
|
||||||
KEVENT PiEnumerationFinished;
|
KEVENT PiEnumerationFinished;
|
||||||
static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
|
static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
|
||||||
|
|
||||||
|
#define TAG_PNP_DEVACTION 'aDpP'
|
||||||
|
|
||||||
/* TYPES *********************************************************************/
|
/* TYPES *********************************************************************/
|
||||||
|
|
||||||
typedef struct _DEVICE_ACTION_REQUEST
|
typedef struct _DEVICE_ACTION_REQUEST
|
||||||
|
@ -60,6 +62,29 @@ typedef struct _DEVICE_ACTION_REQUEST
|
||||||
DEVICE_ACTION Action;
|
DEVICE_ACTION Action;
|
||||||
} DEVICE_ACTION_REQUEST, *PDEVICE_ACTION_REQUEST;
|
} 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 *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
PDEVICE_OBJECT
|
PDEVICE_OBJECT
|
||||||
|
@ -325,6 +350,500 @@ IopCreateDeviceInstancePath(
|
||||||
return STATUS_SUCCESS;
|
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
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
|
IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
|
||||||
|
@ -1008,8 +1527,6 @@ IopActionInitChildServices(PDEVICE_NODE DeviceNode,
|
||||||
PVOID Context)
|
PVOID Context)
|
||||||
{
|
{
|
||||||
PDEVICE_NODE ParentDeviceNode;
|
PDEVICE_NODE ParentDeviceNode;
|
||||||
NTSTATUS Status;
|
|
||||||
BOOLEAN BootDrivers = !PnpSystemInit;
|
|
||||||
|
|
||||||
DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
|
DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
|
||||||
|
|
||||||
|
@ -1043,114 +1560,7 @@ IopActionInitChildServices(PDEVICE_NODE DeviceNode,
|
||||||
IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
|
IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
if (DeviceNode->ServiceName.Buffer == NULL)
|
PiCallDriverAddDevice(DeviceNode, PnPBootDriversLoaded);
|
||||||
{
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,23 @@ PiInsertDevNode(
|
||||||
DeviceNode->Level = ParentNode->Level + 1;
|
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
|
* @brief Creates a device node
|
||||||
*
|
*
|
||||||
|
|
|
@ -286,145 +286,6 @@ Quickie:
|
||||||
return i;
|
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")
|
CODE_SEG("INIT")
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
|
|
@ -390,75 +390,6 @@ IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
|
||||||
ZwClose(CriticalDeviceKey);
|
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
|
NTSTATUS
|
||||||
IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
|
IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue