From 59a5dba443eaafd7b34d7a7920912b3e18b1b2eb Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Tue, 16 Mar 2021 02:17:14 +0300 Subject: [PATCH] [NTOS:PNP] Implement PlugPlayControlStartDevice control class This control class is triggered when a driver is being installed for a non-critical device. The driver info should already be in the registry so we just need to push the device through the state graph Meanwhile, combine the code for similar control classes into PiControlSyncDeviceAction routine CORE-17463 CORE-17490 --- ntoskrnl/include/internal/io.h | 3 +- ntoskrnl/io/pnpmgr/devaction.c | 18 +++++++ ntoskrnl/io/pnpmgr/plugplay.c | 90 +++++++++++++++------------------- 3 files changed, 60 insertions(+), 51 deletions(-) diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h index 269264b9e27..5e84f8e120f 100644 --- a/ntoskrnl/include/internal/io.h +++ b/ntoskrnl/include/internal/io.h @@ -534,7 +534,8 @@ typedef enum _DEVICE_ACTION PiActionEnumDeviceTree, PiActionEnumRootDevices, PiActionResetDevice, - PiActionAddBootDevices + PiActionAddBootDevices, + PiActionStartDevice } DEVICE_ACTION; // diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c index 7bf77afae3e..5d354ddc62c 100644 --- a/ntoskrnl/io/pnpmgr/devaction.c +++ b/ntoskrnl/io/pnpmgr/devaction.c @@ -2482,6 +2482,8 @@ ActionToStr( return "PiActionResetDevice"; case PiActionAddBootDevices: return "PiActionAddBootDevices"; + case PiActionStartDevice: + return "PiActionStartDevice"; default: return "(request unknown)"; } @@ -2540,6 +2542,22 @@ PipDeviceActionWorker( status = STATUS_SUCCESS; break; + case PiActionStartDevice: + // This action is triggered from usermode, when a driver is installed + // for a non-critical PDO + if (deviceNode->State == DeviceNodeInitialized && + !(deviceNode->Flags & DNF_HAS_PROBLEM)) + { + PiDevNodeStateMachine(deviceNode); + } + else + { + DPRINT1("NOTE: attempt to start an already started/uninitialized device %wZ\n", + &deviceNode->InstancePath); + status = STATUS_UNSUCCESSFUL; + } + break; + default: DPRINT1("Unimplemented device action %u\n", Request->Action); status = STATUS_NOT_IMPLEMENTED; diff --git a/ntoskrnl/io/pnpmgr/plugplay.c b/ntoskrnl/io/pnpmgr/plugplay.c index 6c0e84fdb92..28e243dcd79 100644 --- a/ntoskrnl/io/pnpmgr/plugplay.c +++ b/ntoskrnl/io/pnpmgr/plugplay.c @@ -186,40 +186,6 @@ IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName) return Status; } -static NTSTATUS -IopPnpEnumerateDevice(PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA DeviceData) -{ - PDEVICE_OBJECT DeviceObject; - UNICODE_STRING DeviceInstance; - NTSTATUS Status = STATUS_SUCCESS; - - Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->DeviceInstance); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - DPRINT("IopPnpEnumerateDevice(%wZ)\n", &DeviceInstance); - - /* Get the device object */ - DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); - if (DeviceInstance.Buffer != NULL) - { - ExFreePool(DeviceInstance.Buffer); - } - if (DeviceObject == NULL) - { - return STATUS_NO_SUCH_DEVICE; - } - - Status = PiPerformSyncDeviceAction(DeviceObject, PiActionEnumDeviceTree); - - ObDereferenceObject(DeviceObject); - - return Status; -} - - /* * Remove the current PnP event from the tail of the event queue * and signal IopPnpNotifyEvent if there is yet another event in the queue. @@ -1042,23 +1008,26 @@ IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData) return Status; } - -static NTSTATUS -IopResetDevice(PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData) +static +NTSTATUS +PiControlSyncDeviceAction( + _In_ PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceData, + _In_ PLUGPLAY_CONTROL_CLASS ControlClass) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status; UNICODE_STRING DeviceInstance; - Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance); + ASSERT(ControlClass == PlugPlayControlEnumerateDevice || + ControlClass == PlugPlayControlStartDevice || + ControlClass == PlugPlayControlResetDevice); + + Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->DeviceInstance); if (!NT_SUCCESS(Status)) { return Status; } - DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance); - - /* Get the device object */ DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); if (DeviceInstance.Buffer != NULL) { @@ -1069,7 +1038,25 @@ IopResetDevice(PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData) return STATUS_NO_SUCH_DEVICE; } - Status = PiPerformSyncDeviceAction(DeviceObject, PiActionResetDevice); + DEVICE_ACTION Action; + + switch (ControlClass) + { + case PlugPlayControlEnumerateDevice: + Action = PiActionEnumDeviceTree; + break; + case PlugPlayControlStartDevice: + Action = PiActionStartDevice; + break; + case PlugPlayControlResetDevice: + Action = PiActionResetDevice; + break; + default: + UNREACHABLE; + break; + } + + Status = PiPerformSyncDeviceAction(DeviceObject, Action); ObDereferenceObject(DeviceObject); @@ -1309,12 +1296,21 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, case PlugPlayControlEnumerateDevice: if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA)) return STATUS_INVALID_PARAMETER; - return IopPnpEnumerateDevice((PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA)Buffer); + // the Flags field is not used anyway + return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer, + PlugPlayControlClass); // case PlugPlayControlRegisterNewDevice: // case PlugPlayControlDeregisterDevice: // case PlugPlayControlInitializeDevice: -// case PlugPlayControlStartDevice: + + case PlugPlayControlStartDevice: + case PlugPlayControlResetDevice: + if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) + return STATUS_INVALID_PARAMETER; + return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer, + PlugPlayControlClass); + // case PlugPlayControlUnlockDevice: // case PlugPlayControlQueryAndRemoveDevice: @@ -1362,12 +1358,6 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, // case PlugPlayControlTargetDeviceRelation: // case PlugPlayControlQueryConflictList: // case PlugPlayControlRetrieveDock: - - case PlugPlayControlResetDevice: - if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) - return STATUS_INVALID_PARAMETER; - return IopResetDevice((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer); - // case PlugPlayControlHaltDevice: // case PlugPlayControlGetBlockedDriverList: