Windows-Server-2003/base/ntos/verifier/vfpower.c

536 lines
13 KiB
C

/*++
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
);
}
}