https://git.reactos.org/?p=reactos.git;a=commitdiff;h=34f4b218deb628e02a2261...
commit 34f4b218deb628e02a2261177740d5b2ee8d982c Author: Thomas Faber thomas.faber@reactos.org AuthorDate: Sun Feb 23 16:18:18 2020 +0100 Commit: Thomas Faber thomas.faber@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); }
/*