You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
535 lines
14 KiB
535 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
vfpower.c
|
|
|
|
Abstract:
|
|
|
|
This module handles Power Irp verification.
|
|
|
|
Author:
|
|
|
|
Adrian J. Oney (adriao) 20-Apr-1998
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
AdriaO 06/15/2000 - Seperated out from ntos\io\flunkirp.c
|
|
|
|
--*/
|
|
|
|
#include "vfdef.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, VfPowerInit)
|
|
#pragma alloc_text(PAGEVRFY, VfPowerDumpIrpStack)
|
|
#pragma alloc_text(PAGEVRFY, VfPowerVerifyNewRequest)
|
|
#pragma alloc_text(PAGEVRFY, VfPowerVerifyIrpStackDownward)
|
|
#pragma alloc_text(PAGEVRFY, VfPowerVerifyIrpStackUpward)
|
|
#pragma alloc_text(PAGEVRFY, VfPowerIsSystemRestrictedIrp)
|
|
#pragma alloc_text(PAGEVRFY, VfPowerAdvanceIrpStatus)
|
|
#pragma alloc_text(PAGEVRFY, VfPowerTestStartedPdoStack)
|
|
#endif
|
|
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma const_seg("PAGEVRFC")
|
|
#endif
|
|
|
|
const PCHAR PowerIrpNames[] = {
|
|
"IRP_MN_WAIT_WAKE", // 0x00
|
|
"IRP_MN_POWER_SEQUENCE", // 0x01
|
|
"IRP_MN_SET_POWER", // 0x02
|
|
"IRP_MN_QUERY_POWER", // 0x03
|
|
NULL
|
|
};
|
|
|
|
#define MAX_NAMED_POWER_IRP 0x3
|
|
|
|
const PCHAR SystemStateNames[] = {
|
|
"PowerSystemUnspecified", // 0x00
|
|
"PowerSystemWorking.S0", // 0x01
|
|
"PowerSystemSleeping1.S1", // 0x02
|
|
"PowerSystemSleeping2.S2", // 0x03
|
|
"PowerSystemSleeping3.S3", // 0x04
|
|
"PowerSystemHibernate.S4", // 0x05
|
|
"PowerSystemShutdown.S5", // 0x06
|
|
NULL
|
|
};
|
|
|
|
#define MAX_NAMED_SYSTEM_STATES 0x6
|
|
|
|
const PCHAR DeviceStateNames[] = {
|
|
"PowerDeviceUnspecified", // 0x00
|
|
"PowerDeviceD0", // 0x01
|
|
"PowerDeviceD1", // 0x02
|
|
"PowerDeviceD2", // 0x03
|
|
"PowerDeviceD3", // 0x04
|
|
NULL
|
|
};
|
|
|
|
#define MAX_NAMED_DEVICE_STATES 0x4
|
|
|
|
const PCHAR ActionNames[] = {
|
|
"PowerActionNone", // 0x00
|
|
"PowerActionReserved", // 0x01
|
|
"PowerActionSleep", // 0x02
|
|
"PowerActionHibernate", // 0x03
|
|
"PowerActionShutdown", // 0x04
|
|
"PowerActionShutdownReset", // 0x05
|
|
"PowerActionShutdownOff", // 0x06
|
|
"PowerActionWarmEject", // 0x07
|
|
NULL
|
|
};
|
|
|
|
#define MAX_ACTION_NAMES 0x7
|
|
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma const_seg()
|
|
#endif // ALLOC_DATA_PRAGMA
|
|
|
|
|
|
VOID
|
|
VfPowerInit(
|
|
VOID
|
|
)
|
|
{
|
|
VfMajorRegisterHandlers(
|
|
IRP_MJ_POWER,
|
|
VfPowerDumpIrpStack,
|
|
VfPowerVerifyNewRequest,
|
|
VfPowerVerifyIrpStackDownward,
|
|
VfPowerVerifyIrpStackUpward,
|
|
VfPowerIsSystemRestrictedIrp,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
VfPowerTestStartedPdoStack,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
VfPowerVerifyNewRequest(
|
|
IN PIOV_REQUEST_PACKET IovPacket,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PIOV_STACK_LOCATION StackLocationData,
|
|
IN PVOID CallerAddress OPTIONAL
|
|
)
|
|
{
|
|
PIRP irp;
|
|
NTSTATUS currentStatus;
|
|
|
|
UNREFERENCED_PARAMETER (DeviceObject);
|
|
UNREFERENCED_PARAMETER (IrpSp);
|
|
UNREFERENCED_PARAMETER (IrpLastSp);
|
|
|
|
irp = IovPacket->TrackedIrp;
|
|
currentStatus = irp->IoStatus.Status;
|
|
|
|
//
|
|
// Verify new IRPs start out life accordingly
|
|
//
|
|
if (currentStatus!=STATUS_NOT_SUPPORTED) {
|
|
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_POWER_IRP_BAD_INITIAL_STATUS,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
CallerAddress,
|
|
irp
|
|
));
|
|
|
|
//
|
|
// Don't blame anyone else for this driver's mistake.
|
|
//
|
|
if (!NT_SUCCESS(currentStatus)) {
|
|
|
|
StackLocationData->Flags |= STACKFLAG_FAILURE_FORWARDED;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
VfPowerVerifyIrpStackDownward(
|
|
IN PIOV_REQUEST_PACKET IovPacket,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PIOV_STACK_LOCATION RequestHeadLocationData,
|
|
IN PIOV_STACK_LOCATION StackLocationData,
|
|
IN PVOID CallerAddress OPTIONAL
|
|
)
|
|
{
|
|
PIRP irp = IovPacket->TrackedIrp;
|
|
NTSTATUS currentStatus, lastStatus;
|
|
BOOLEAN statusChanged;
|
|
PDRIVER_OBJECT driverObject;
|
|
PIOV_SESSION_DATA iovSessionData;
|
|
|
|
UNREFERENCED_PARAMETER (IrpSp);
|
|
|
|
currentStatus = irp->IoStatus.Status;
|
|
lastStatus = RequestHeadLocationData->LastStatusBlock.Status;
|
|
statusChanged = (BOOLEAN)(currentStatus != lastStatus);
|
|
iovSessionData = VfPacketGetCurrentSessionData(IovPacket);
|
|
|
|
//
|
|
// Verify the IRP was forwarded properly
|
|
//
|
|
if (iovSessionData->ForwardMethod == SKIPPED_A_DO) {
|
|
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_SKIPPED_DEVICE_OBJECT,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
CallerAddress,
|
|
irp
|
|
));
|
|
}
|
|
|
|
//
|
|
// For some IRP major's going down a stack, there *must* be a handler
|
|
//
|
|
driverObject = DeviceObject->DriverObject;
|
|
|
|
if (!IovUtilHasDispatchHandler(driverObject, IRP_MJ_POWER)) {
|
|
|
|
RequestHeadLocationData->Flags |= STACKFLAG_BOGUS_IRP_TOUCHED;
|
|
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_MISSING_DISPATCH_FUNCTION,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
driverObject->DriverInit,
|
|
irp
|
|
));
|
|
|
|
StackLocationData->Flags |= STACKFLAG_NO_HANDLER;
|
|
}
|
|
|
|
//
|
|
// The following is only executed if we are not a new IRP...
|
|
//
|
|
if (IrpLastSp == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The only legit failure code to pass down is STATUS_NOT_SUPPORTED
|
|
//
|
|
if ((!NT_SUCCESS(currentStatus)) && (currentStatus != STATUS_NOT_SUPPORTED) &&
|
|
(!(RequestHeadLocationData->Flags & STACKFLAG_FAILURE_FORWARDED))) {
|
|
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_POWER_FAILURE_FORWARDED,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
CallerAddress,
|
|
irp
|
|
));
|
|
|
|
//
|
|
// Don't blame anyone else for this drivers's mistakes.
|
|
//
|
|
RequestHeadLocationData->Flags |= STACKFLAG_FAILURE_FORWARDED;
|
|
}
|
|
|
|
//
|
|
// Status of a Power IRP may not be converted to STATUS_NOT_SUPPORTED on
|
|
// the way down.
|
|
//
|
|
if ((currentStatus == STATUS_NOT_SUPPORTED)&&statusChanged) {
|
|
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_POWER_IRP_STATUS_RESET,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
CallerAddress,
|
|
irp
|
|
));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
VfPowerVerifyIrpStackUpward(
|
|
IN PIOV_REQUEST_PACKET IovPacket,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PIOV_STACK_LOCATION RequestHeadLocationData,
|
|
IN PIOV_STACK_LOCATION StackLocationData,
|
|
IN BOOLEAN IsNewlyCompleted,
|
|
IN BOOLEAN RequestFinalized
|
|
)
|
|
{
|
|
PIRP irp;
|
|
NTSTATUS currentStatus;
|
|
BOOLEAN mustPassDown, isBogusIrp, isPdo;
|
|
PVOID routine;
|
|
|
|
UNREFERENCED_PARAMETER (IrpSp);
|
|
UNREFERENCED_PARAMETER (RequestFinalized);
|
|
|
|
irp = IovPacket->TrackedIrp;
|
|
currentStatus = irp->IoStatus.Status;
|
|
|
|
//
|
|
// Who'd we call for this one?
|
|
//
|
|
routine = StackLocationData->LastDispatch;
|
|
ASSERT(routine) ;
|
|
|
|
//
|
|
// If this "Request" has been "Completed", perform some checks
|
|
//
|
|
if (IsNewlyCompleted) {
|
|
|
|
//
|
|
// Remember bogosity...
|
|
//
|
|
isBogusIrp = (BOOLEAN)((IovPacket->Flags&TRACKFLAG_BOGUS)!=0);
|
|
|
|
//
|
|
// Is this a PDO?
|
|
//
|
|
isPdo = (BOOLEAN)((StackLocationData->Flags&STACKFLAG_REACHED_PDO)!=0);
|
|
|
|
//
|
|
// Was anything completed too early?
|
|
// A driver may outright fail almost anything but a bogus IRP
|
|
//
|
|
mustPassDown = (BOOLEAN)(!(StackLocationData->Flags&STACKFLAG_NO_HANDLER));
|
|
mustPassDown &= (!isPdo);
|
|
|
|
mustPassDown &= (isBogusIrp || NT_SUCCESS(currentStatus) || (currentStatus == STATUS_NOT_SUPPORTED));
|
|
if (mustPassDown) {
|
|
|
|
//
|
|
// Print appropriate error message
|
|
//
|
|
if (IovPacket->Flags&TRACKFLAG_BOGUS) {
|
|
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_BOGUS_POWER_IRP_COMPLETED,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
routine,
|
|
irp
|
|
));
|
|
|
|
} else if (NT_SUCCESS(currentStatus)) {
|
|
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_SUCCESSFUL_POWER_IRP_NOT_FORWARDED,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
routine,
|
|
irp
|
|
));
|
|
|
|
} else if (currentStatus == STATUS_NOT_SUPPORTED) {
|
|
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_UNTOUCHED_POWER_IRP_NOT_FORWARDED,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
routine,
|
|
irp
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Did anyone stomp the status erroneously?
|
|
//
|
|
if ((currentStatus == STATUS_NOT_SUPPORTED) &&
|
|
(currentStatus != RequestHeadLocationData->LastStatusBlock.Status)) {
|
|
|
|
//
|
|
// Status of a PnP or Power IRP may not be converted from success to
|
|
// STATUS_NOT_SUPPORTED on the way down.
|
|
//
|
|
WDM_FAIL_ROUTINE((
|
|
DCERROR_POWER_IRP_STATUS_RESET,
|
|
DCPARAM_IRP + DCPARAM_ROUTINE,
|
|
routine,
|
|
irp
|
|
));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
VfPowerDumpIrpStack(
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
{
|
|
DbgPrint("IRP_MJ_POWER.");
|
|
|
|
if (IrpSp->MinorFunction <= MAX_NAMED_POWER_IRP) {
|
|
|
|
DbgPrint(PowerIrpNames[IrpSp->MinorFunction]);
|
|
|
|
if ((IrpSp->MinorFunction == IRP_MN_QUERY_POWER) ||
|
|
(IrpSp->MinorFunction == IRP_MN_SET_POWER)) {
|
|
|
|
DbgPrint("(");
|
|
|
|
if (IrpSp->Parameters.Power.Type == SystemPowerState) {
|
|
|
|
if (IrpSp->Parameters.Power.State.SystemState <= MAX_NAMED_SYSTEM_STATES) {
|
|
|
|
DbgPrint(SystemStateNames[IrpSp->Parameters.Power.State.SystemState]);
|
|
}
|
|
|
|
} else {
|
|
|
|
if (IrpSp->Parameters.Power.State.DeviceState <= MAX_NAMED_DEVICE_STATES) {
|
|
|
|
DbgPrint(DeviceStateNames[IrpSp->Parameters.Power.State.DeviceState]);
|
|
}
|
|
}
|
|
|
|
if (IrpSp->Parameters.Power.ShutdownType <= MAX_ACTION_NAMES) {
|
|
|
|
DbgPrint(".%s", ActionNames[IrpSp->Parameters.Power.ShutdownType]);
|
|
}
|
|
|
|
DbgPrint(")");
|
|
}
|
|
|
|
} else if (IrpSp->MinorFunction == 0xFF) {
|
|
|
|
DbgPrint("IRP_MN_BOGUS");
|
|
|
|
} else {
|
|
|
|
DbgPrint("(Bogus)");
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
VfPowerIsSystemRestrictedIrp(
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
{
|
|
switch(IrpSp->MinorFunction) {
|
|
case IRP_MN_POWER_SEQUENCE:
|
|
return FALSE;
|
|
case IRP_MN_QUERY_POWER:
|
|
case IRP_MN_SET_POWER:
|
|
case IRP_MN_WAIT_WAKE:
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
VfPowerAdvanceIrpStatus(
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN NTSTATUS OriginalStatus,
|
|
IN OUT NTSTATUS *StatusToAdvance
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Given an IRP stack pointer, is it legal to change the status for
|
|
debug-ability? If so, this function determines what the new status
|
|
should be. Note that for each stack location, this function is iterated
|
|
over n times where n is equal to the number of drivers who IoSkip'd this
|
|
location.
|
|
|
|
Arguments:
|
|
|
|
IrpSp - Current stack right after complete for the given stack
|
|
location, but before the completion routine for the
|
|
stack location above has been called.
|
|
|
|
OriginalStatus - The status of the IRP at the time listed above. Does
|
|
not change over iteration per skipping driver.
|
|
|
|
StatusToAdvance - Pointer to the current status that should be updated.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the status has been adjusted, FALSE otherwise (in this case
|
|
StatusToAdvance is untouched).
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER (IrpSp);
|
|
|
|
if (((ULONG) OriginalStatus) >= 256) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
(*StatusToAdvance)++;
|
|
if ((*StatusToAdvance) == STATUS_PENDING) {
|
|
(*StatusToAdvance)++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
VfPowerTestStartedPdoStack(
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
As per the title, we are going to throw some IRPs at the stack to
|
|
see if they are handled correctly.
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
--*/
|
|
{
|
|
IO_STACK_LOCATION irpSp;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Initialize the stack location to pass to IopSynchronousCall()
|
|
//
|
|
RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
|
|
|
|
if (VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_SEND_BOGUS_POWER_IRPS)) {
|
|
|
|
//
|
|
// And a bogus Power IRP
|
|
//
|
|
irpSp.MajorFunction = IRP_MJ_POWER;
|
|
irpSp.MinorFunction = 0xff;
|
|
VfIrpSendSynchronousIrp(
|
|
PhysicalDeviceObject,
|
|
&irpSp,
|
|
TRUE,
|
|
STATUS_NOT_SUPPORTED,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
|