https://git.reactos.org/?p=reactos.git;a=commitdiff;h=34f4b218deb628e02a226…
commit 34f4b218deb628e02a2261177740d5b2ee8d982c
Author: Thomas Faber <thomas.faber(a)reactos.org>
AuthorDate: Sun Feb 23 16:18:18 2020 +0100
Commit: Thomas Faber <thomas.faber(a)reactos.org>
CommitDate: Mon Apr 6 11:12:47 2020 +0200
[NTOS:PO] Call power IRP handlers at PASSIVE_LEVEL when needed. CORE-11648 CORE-16704
This means we now correctly handle the DO_POWER_PAGABLE flag.
In particular, Windows's usbhub.sys calls KeDelayExecutionThread from a
power IRP dispatch routine. We now handle this correctly.
---
ntoskrnl/po/power.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 118 insertions(+), 7 deletions(-)
diff --git a/ntoskrnl/po/power.c b/ntoskrnl/po/power.c
index fe26c0f4620..d29c85658bc 100644
--- a/ntoskrnl/po/power.c
+++ b/ntoskrnl/po/power.c
@@ -30,6 +30,100 @@ SYSTEM_POWER_CAPABILITIES PopCapabilities;
/* PRIVATE FUNCTIONS *********************************************************/
+static WORKER_THREAD_ROUTINE PopPassivePowerCall;
+_Use_decl_annotations_
+static
+VOID
+NTAPI
+PopPassivePowerCall(
+ PVOID Parameter)
+{
+ PIRP Irp = Parameter;
+ PIO_STACK_LOCATION IoStack;
+
+ ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ _Analysis_assume_(Irp != NULL);
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ (VOID)IoCallDriver(IoStack->DeviceObject, Irp);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+_IRQL_requires_same_
+static
+NTSTATUS
+PopPresentIrp(
+ _In_ PIO_STACK_LOCATION NextStack,
+ _In_ PIRP Irp)
+{
+ NTSTATUS Status;
+ BOOLEAN CallAtPassiveLevel;
+ PDEVICE_OBJECT DeviceObject;
+ PWORK_QUEUE_ITEM WorkQueueItem;
+
+ ASSERT(NextStack->MajorFunction == IRP_MJ_POWER);
+
+ DeviceObject = NextStack->DeviceObject;
+
+ /* Determine whether the IRP must be handled at PASSIVE_LEVEL.
+ * Only SET_POWER to working state can happen at raised IRQL. */
+ CallAtPassiveLevel = TRUE;
+ if ((NextStack->MinorFunction == IRP_MN_SET_POWER) &&
+ !(DeviceObject->Flags & DO_POWER_PAGABLE))
+ {
+ if (NextStack->Parameters.Power.Type == DevicePowerState &&
+ NextStack->Parameters.Power.State.DeviceState == PowerDeviceD0)
+ {
+ CallAtPassiveLevel = FALSE;
+ }
+ if (NextStack->Parameters.Power.Type == SystemPowerState &&
+ NextStack->Parameters.Power.State.SystemState == PowerSystemWorking)
+ {
+ CallAtPassiveLevel = FALSE;
+ }
+ }
+
+ if (CallAtPassiveLevel)
+ {
+ /* We need to fit a work item into the DriverContext below */
+ C_ASSERT(sizeof(Irp->Tail.Overlay.DriverContext) >=
sizeof(WORK_QUEUE_ITEM));
+
+ if (KeGetCurrentIrql() == PASSIVE_LEVEL)
+ {
+ /* Already at passive, call next driver directly */
+ return IoCallDriver(DeviceObject, Irp);
+ }
+
+ /* Need to schedule a work item and return pending */
+ NextStack->Control |= SL_PENDING_RETURNED;
+
+ WorkQueueItem = (PWORK_QUEUE_ITEM)&Irp->Tail.Overlay.DriverContext;
+ ExInitializeWorkItem(WorkQueueItem,
+ PopPassivePowerCall,
+ Irp);
+ ExQueueWorkItem(WorkQueueItem, DelayedWorkQueue);
+
+ return STATUS_PENDING;
+ }
+
+ /* Direct call. Raise IRQL in debug to catch invalid paged memory access. */
+#if DBG
+ {
+ KIRQL OldIrql;
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+#endif
+
+ Status = IoCallDriver(DeviceObject, Irp);
+
+#if DBG
+ KeLowerIrql(OldIrql);
+ }
+#endif
+
+ return Status;
+}
+
static
NTSTATUS
NTAPI
@@ -480,18 +574,35 @@ PoSetHiberRange(IN PVOID HiberContext,
/*
* @implemented
*/
+_IRQL_requires_max_(DISPATCH_LEVEL)
NTSTATUS
NTAPI
-PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
- IN OUT PIRP Irp)
+PoCallDriver(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ __drv_aliasesMem PIRP Irp)
{
- NTSTATUS Status;
+ PIO_STACK_LOCATION NextStack;
- /* Forward to Io -- FIXME! */
- Status = IoCallDriver(DeviceObject, Irp);
+ ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
- /* Return status */
- return Status;
+ ASSERT(DeviceObject);
+ ASSERT(Irp);
+
+ NextStack = IoGetNextIrpStackLocation(Irp);
+ ASSERT(NextStack->MajorFunction == IRP_MJ_POWER);
+
+ /* Set DeviceObject for PopPresentIrp */
+ NextStack->DeviceObject = DeviceObject;
+
+ /* Only QUERY_POWER and SET_POWER use special handling */
+ if (NextStack->MinorFunction != IRP_MN_SET_POWER &&
+ NextStack->MinorFunction != IRP_MN_QUERY_POWER)
+ {
+ return IoCallDriver(DeviceObject, Irp);
+ }
+
+ /* Call the next driver, either directly or at PASSIVE_LEVEL */
+ return PopPresentIrp(NextStack, Irp);
}
/*