reactos/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestbase.hpp

963 lines
20 KiB
C++
Raw Normal View History

/*++
Copyright (c) Microsoft Corporation
Module Name:
FxRequestBase.hpp
Abstract:
This is the base class which request objects derive from for the driver
frameworks.
The request base object wraps the IRP, containing persistent
information required by the driver frameworks.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#ifndef _FXREQUESTBASE_H_
#define _FXREQUESTBASE_H_
#include "fxrequestcallbacks.hpp"
#define WDF_REQUEST_REUSE_MUST_COMPLETE 2
//
// COMPLETED - set when the request's i/o completion routine has executed
//
// PENDED - set when the request has been put onto the target's CSQ
//
// TIMER_SET - set when a timer has been queued along with sending the request
// down to the target
//
// CANCELLED_FROM_TIME - set by the timer to indicate that the request was
// cancelled by the timer DPC
//
// IGNORE_STATE - set when the request is going to be sent ignoring the
// state of the target.
//
enum FxRequestTargetFlags {
FX_REQUEST_COMPLETED = 0x01,
FX_REQUEST_PENDED = 0x02,
FX_REQUEST_TIMER_SET = 0x04,
FX_REQUEST_CANCELLED_FROM_TIMER = 0x08,
FX_REQUEST_IGNORE_STATE = 0x10,
};
//
// internal private constraints
//
#define WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND (0x80000000)
#define WDF_REQUEST_INTERNAL_CONSTRAINTS_VALID_FLAGS \
(WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND)
//
// Completion event callback prototype
//
typedef
VOID
(*PFN_COMPLETE_COPY_ROUTINE)(
__in FxIoTarget* This,
__in FxRequest* Request,
__in_opt FxRequestContext* Context
);
struct FxRequestTimer : public FxStump {
MxTimer Timer;
};
enum FxRequestAllocationSource {
REQUEST_ALLOCATED_FROM_IO = 0, // Irp came from the I/O package
REQUEST_ALLOCATED_INTERNAL = 1, // Irp was allocated internally and should be freed by the request
REQUEST_ALLOCATED_DRIVER = 2, // Irp was given to the request by the driver writer
};
enum FxRequestIrpOwnership {
FxRequestOwnsIrp = 1,
FxRequestDoesNotOwnIrp,
};
// begin_wpp config
// CUSTOM_TYPE(FxRequestIrpOwnership, ItemEnum(FxRequestIrpOwnership));
// end_wpp
enum FxRequestConstructorCaller {
FxRequestConstructorCallerIsFx = 1,
FxRequestConstructorCallerIsDriver,
};
//
// These defines are for VerifierFlags
//
enum FxRequestVerifierFlags {
// Request has been passed to the Driver
FXREQUEST_FLAG_DRIVER_OWNED = 0x0001,
// Request was returned as a "Tag" request to WdfIoQueuePeekNextRequest.
FXREQUEST_FLAG_TAG_REQUEST = 0x0002,
// Request has been forwarded from one queue to another
FXREQUEST_FLAG_FORWARDED = 0x0004,
// Request is being EvtIoDefault to the driver
FXREQUEST_FLAG_DRIVER_DISPATCH = 0x0008,
// The driver has specified the request as cancelable
FXREQUEST_FLAG_DRIVER_CANCELABLE = 0x0010,
FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT = 0x0020,
// The request has been cancelled
FXREQUEST_FLAG_CANCELLED = 0x0040,
// the next stack location has been formatted
FXREQUEST_FLAG_FORMATTED = 0x0080,
// the request has been sent on an I/O target and is in the target's sent list
FXREQUEST_FLAG_SENT_TO_TARGET = 0x0100,
// used to make sure the driver stop acknowledges in the context of EvtIoStop
FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT = 0x0200,
// used to indicate whether the Reserved Request is in use or on Free list
FXREQUEST_FLAG_RESERVED_REQUEST_ASSOCIATED_WITH_IRP = 0x0400,
};
enum FxRequestBaseFlags {
FxRequestBaseSystemMdlMapped = 0x1,
FxRequestBaseOutputMdlMapped = 0x2,
FxRequestBaseSyncCleanupContext = 0x10,
};
enum FxRequestBaseStaticFlags {
FxRequestBaseStaticSystemBufferValid = 0x1,
FxRequestBaseStaticOutputBufferValid = 0x2,
};
//
// Designed to fit into a byte. FxRequestCompletionPkgFlag is a bit value
// used to distinguish between calling back into the io package or the current
// queue. When calling back into the current queue, we assume m_IoQueue is valid
//
enum FxRequestCompletionState {
FxRequestCompletionStateIoPkgFlag = 0x80,
FxRequestCompletionStateNone = 0x00,
FxRequestCompletionStateQueue = 0x01,
FxRequestCompletionStateIoPkg = 0x02 | FxRequestCompletionStateIoPkgFlag,
};
class FxRequestBase : public FxNonPagedObject {
friend FxIoTarget;
friend FxSyncRequest;
public:
__inline
VOID
SetCompletionRoutine(
__in_opt PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine = NULL,
__in_opt WDFCONTEXT CompletionContext = NULL
)
{
m_CompletionRoutine.m_Completion = CompletionRoutine;
m_TargetCompletionContext = CompletionContext;
}
PFN_WDF_REQUEST_COMPLETION_ROUTINE
ClearCompletionRoutine(
VOID
)
{
PFN_WDF_REQUEST_COMPLETION_ROUTINE pRoutine;
pRoutine = m_CompletionRoutine.m_Completion;
m_CompletionRoutine.m_Completion = NULL;
return pRoutine;
}
WDFCONTEXT
ClearCompletionContext(
VOID
)
{
WDFCONTEXT pContext;
pContext = m_TargetCompletionContext;
m_TargetCompletionContext = NULL;
return pContext;
}
__inline
BOOLEAN
IsCompletionRoutineSet(
VOID
)
{
return (m_CompletionRoutine.m_Completion != NULL) ?
TRUE : FALSE;
}
__inline
BOOLEAN
IsCancelRoutineSet(
VOID
)
{
return (m_CancelRoutine.m_Cancel != NULL) ?
TRUE : FALSE;
}
__inline
FxRequestContext*
GetContext(
VOID
)
{
return m_RequestContext;
}
__inline
VOID
SetContext(
__in FxRequestContext* RequestContext = NULL
)
{
//
// If we are setting to the same value, just return
//
if (m_RequestContext == RequestContext) {
return;
}
//
// If we are changing the context to another unique pointer, free the
// old context.
//
if (m_RequestContext != NULL) {
delete m_RequestContext;
}
m_RequestContext = RequestContext;
}
VOID
ContextReleaseAndRestore(
VOID
)
{
//
// This does not free the context, rather it tells the context to release
// any references it is holding and restore fields back into the PIRP
//
if (m_RequestContext != NULL && m_Irp.GetIrp() != NULL) {
m_RequestContext->ReleaseAndRestore(this);
VerifierClearFormatted();
}
}
__inline
VOID
EnableContextDisposeNotification(
VOID
)
{
MarkDisposeOverride();
}
__inline
BOOLEAN
HasContextType(
__in FX_REQUEST_CONTEXT_TYPE Type
)
{
return (m_RequestContext != NULL &&
m_RequestContext->m_RequestType == Type) ? TRUE : FALSE;
}
__inline
BOOLEAN
HasContext(
VOID
)
{
return (m_RequestContext != NULL &&
m_RequestContext->m_RequestType !=
FX_REQUEST_CONTEXT_TYPE_NONE) ? TRUE : FALSE;
}
__inline
MdIrp
GetSubmitIrp(
VOID
)
{
return m_Irp.GetIrp();
}
__inline
FxIrp*
GetSubmitFxIrp(
VOID
)
{
return &m_Irp;
}
MdIrp
SetSubmitIrp(
__in_opt MdIrp NewIrp,
__in BOOLEAN FreeIrp = TRUE
);
__inline
BOOLEAN
CanComplete(
VOID
)
{
LONG count;
count = InterlockedDecrement(&m_IrpCompletionReferenceCount);
ASSERT(count >= 0);
return count == 0 ? TRUE : FALSE;
}
VOID
CompleteSubmitted(
VOID
);
_Must_inspect_result_
NTSTATUS
ValidateTarget(
__in FxIoTarget* Target
);
__inline
FxIoTarget*
GetTarget(
VOID
)
{
return m_Target;
}
VOID
__inline
SetTarget(
__in FxIoTarget* Target
)
{
m_Target = Target;
}
__inline
UCHAR
GetTargetFlags(
VOID
)
{
// Assumes caller is holding appropriate lock
return m_TargetFlags;
}
__inline
VOID
SetTargetFlags(
__in UCHAR Flags
)
{
// Assumes caller is holding appropriate lock
m_TargetFlags |= Flags;
}
__inline
ULONG
ClearTargetFlags(
__in UCHAR Flags
)
{
ULONG oldFlags;
oldFlags = m_TargetFlags;
// Assumes caller is holding appropriate lock
m_TargetFlags &= ~Flags;
return oldFlags;
}
__inline
VOID
SetRequestBaseFlags(
__in UCHAR Flags
)
{
// Assumes caller is holding appropriate lock
m_RequestBaseFlags|= Flags;
}
SHORT
GetVerifierFlagsLocked(
VOID
)
{
ASSERT(GetDriverGlobals()->FxVerifierOn);
return m_VerifierFlags;
}
__inline
SHORT
GetVerifierFlags(
VOID
)
{
SHORT flags;
KIRQL irql;
Lock(&irql);
flags = GetVerifierFlagsLocked();
Unlock(irql);
return flags;
}
__inline
VOID
SetVerifierFlagsLocked(
__in SHORT Flags
)
{
m_VerifierFlags |= Flags;
}
__inline
VOID
SetVerifierFlags(
__in SHORT Flags
)
{
KIRQL irql;
ASSERT(GetDriverGlobals()->FxVerifierOn);
Lock(&irql);
SetVerifierFlagsLocked(Flags);
Unlock(irql);
}
__inline
VOID
ClearVerifierFlagsLocked(
__in SHORT Flags
)
{
m_VerifierFlags &= ~Flags;
}
__inline
VOID
ClearVerifierFlags(
__in SHORT Flags
)
{
KIRQL irql;
ASSERT(GetDriverGlobals()->FxVerifierOn);
Lock(&irql);
ClearVerifierFlagsLocked(Flags);
Unlock(irql);
}
__inline
VOID
VerifierSetFormatted(
VOID
)
{
if (GetDriverGlobals()->FxVerifierOn &&
GetDriverGlobals()->FxVerifierIO) {
SetVerifierFlags(FXREQUEST_FLAG_FORMATTED);
}
}
__inline
VOID
VerifierClearFormatted(
VOID
)
{
if (GetDriverGlobals()->FxVerifierOn &&
GetDriverGlobals()->FxVerifierIO) {
ClearVerifierFlags(FXREQUEST_FLAG_FORMATTED);
}
}
__inline
BOOLEAN
VerifierIsFormatted(
VOID
)
{
if (GetDriverGlobals()->FxVerifierOn &&
GetDriverGlobals()->FxVerifierIO) {
return (GetVerifierFlags() & FXREQUEST_FLAG_FORMATTED) ? TRUE : FALSE;
}
else {
//
// we are not tracking the state
//
return TRUE;
}
}
__inline
BOOLEAN
ShouldClearContext(
VOID
)
{
return (m_RequestBaseFlags & FxRequestBaseSyncCleanupContext) ? TRUE
: FALSE;
}
_Must_inspect_result_
NTSTATUS
CreateTimer(
VOID
);
VOID
StartTimer(
__in LONGLONG Timeout
);
_Must_inspect_result_
BOOLEAN
CancelTimer(
VOID
);
BOOLEAN
Cancel(
VOID
);
BOOLEAN
__inline
IsAllocatedFromIo(
VOID
)
{
return m_IrpAllocation == REQUEST_ALLOCATED_FROM_IO ? TRUE : FALSE;
}
BOOLEAN
__inline
IsAllocatedDriver(
VOID
)
{
return m_IrpAllocation == REQUEST_ALLOCATED_DRIVER ? TRUE : FALSE;
}
BOOLEAN
__inline
IsCanComplete(
VOID
)
{
return m_CanComplete;
}
__inline
VOID
SetCompleted(
__in BOOLEAN Value
)
{
m_Completed = Value;
}
VOID
__inline
SetPriorityBoost(
CCHAR PriorityBoost
)
{
m_PriorityBoost = PriorityBoost;
}
CCHAR
__inline
GetPriorityBoost(
VOID
)
{
return m_PriorityBoost;
}
__inline
WDFREQUEST
GetHandle(
VOID
)
{
return (WDFREQUEST) GetObjectHandle();
}
__inline
static
FxRequestBase*
_FromListEntry(
__in PLIST_ENTRY Entry
)
{
return CONTAINING_RECORD(Entry, FxRequestBase, m_ListEntry);
}
__inline
static
FxRequestBase*
_FromDrainEntry(
__in PSINGLE_LIST_ENTRY Entry
)
{
return CONTAINING_RECORD(Entry, FxRequestBase, m_DrainSingleEntry);
}
__inline
static
FxRequestBase*
_FromCsqContext(
__in PMdIoCsqIrpContext Context
)
{
return CONTAINING_RECORD(Context, FxRequestBase, m_CsqContext);
}
__inline
PVOID
GetTraceObjectHandle(
VOID
)
{
PVOID handle;
handle = GetObjectHandle();
if (handle != NULL) {
return handle;
}
else {
return (PVOID) this;
}
}
VOID
FreeMdls(
VOID
);
DECLSPEC_NORETURN
VOID
FatalError(
__in NTSTATUS Status
);
VOID
ClearFieldsForReuse(
VOID
);
protected:
FxRequestBase(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in USHORT ObjectSize,
__in_opt MdIrp Irp,
__in FxRequestIrpOwnership Ownership,
__in FxRequestConstructorCaller Caller,
__in FxObjectType ObjectType = FxObjectTypeExternal
);
virtual
~FxRequestBase(
VOID
);
// Do not specify argument names
FX_DECLARE_VF_FUNCTION(
VOID,
VerifyDispose
);
// FxObject overrides
virtual
BOOLEAN
Dispose(
VOID
);
static
MdDeferredRoutineType _TimerDPC;
VOID
CompleteSubmittedNoContext(
VOID
);
VOID
ZeroOutDriverContext(
VOID
)
{
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
RtlZeroMemory(GetSubmitFxIrp()->GetDriverContext(),
GetSubmitFxIrp()->GetDriverContextSize());
#else
//
// UMDF host doesn't expose any easier way to zero out the contexts so
// set context to NULL one by one.
//
GetSubmitFxIrp()->SetContext(0, NULL);
GetSubmitFxIrp()->SetContext(1, NULL);
GetSubmitFxIrp()->SetContext(2, NULL);
GetSubmitFxIrp()->SetContext(3, NULL);
#endif
}
public:
union {
//
// The cancel safe queues use this context to identify
// the request in a race free manner.
//
MdIoCsqIrpContext m_CsqContext;
//
// IoTargets uses this to track the request when it is sent to the target.
// Since the request cannot be on an CSQ and sent to a target at the
// same time, we can unionize this with the CSQ context.
//
LIST_ENTRY m_ListEntry;
};
union {
//
// IoTargest uses this when it needs to create a list of requests to cancel
// when making a state transition
//
SINGLE_LIST_ENTRY m_DrainSingleEntry;
//
// If TRUE, the driver formatted the request by copying the current stack
// location to next or by manually passing in an IO_STACK_LOCATION. This
// is union'ed with m_DrainSingleEntry b/c it is only relevant during
// send and forget and the request is never enqueued on the target in
// this case and m_DrainSingleEntry is used when tracking requests sent
// on a target for cancelation due to a target state change.
//
BOOLEAN m_NextStackLocationFormatted;
};
protected:
//
// The NT IRP is wrapped by a frameworks FxIrp
//
// Note: If m_Irp is NULL after initialization, this means
// the IRP was cancelled by a FxIrpQueue cancellation
// callback, or completed.
//
FxIrp m_Irp;
//
// Target of the request. Access to this field is unguarded. The following
// have access to this field
// o The owning target itself
// o _TimerDPC()
// o Cancel() IFF it has successfully incremented the irp completion ref count
//
FxIoTarget* m_Target;
FxRequestContext* m_RequestContext;
FxRequestTimer* m_Timer;
//
// Client driver completion routine to call when the request has come back
// from the target device.
//
FxRequestCancelCallback m_CancelRoutine;
FxRequestCompletionCallback m_CompletionRoutine;
//
// Context to pass to CompletionRoutine when called
//
WDFCONTEXT m_TargetCompletionContext;
//
// Synchronization for this field is through Interlocked operations
//
LONG m_IrpCompletionReferenceCount;
//
// Access to flags guarded by FxIoTarget::Lock
//
// Values defined in the enum FxRequestTargetFlags
//
union {
UCHAR m_TargetFlags;
//
// These are used purely for debugging, not in live code anywhere!
// NOTE: if FxRequestTargetFlagschanges, so this this union
//
struct {
UCHAR Completed : 1;
UCHAR FlagsPended : 1;
UCHAR TimerSet : 1;
UCHAR CancelledFromTimer : 1;
UCHAR IgnoreState : 1;
} m_TargetFlagsByName;
};
//
// Contains a value from the enum type FxRequestAllocationSource describing
// how the irp was allocated
//
UCHAR m_IrpAllocation;
BOOLEAN m_Completed;
BOOLEAN m_Canceled;
WDFOBJECT_OFFSET_ALIGNED m_SystemBufferOffset;
union {
//
// These are flags used by verifier. Set with values from the enum
// FxRequestVerifierFlags
//
SHORT m_VerifierFlags;
struct {
SHORT DriverOwned : 1;
SHORT TagRequest : 1;
SHORT Forwarded : 1;
SHORT DriverDispatch : 1;
SHORT DriverCancelable : 1;
SHORT DriverInprocessContext : 1;
SHORT Cancelled : 1;
SHORT Formatted : 1;
SHORT SentToTarget : 1;
SHORT DriverInEvtIoStopContext : 1;
} m_VeriferFlagsByName;
};
//
// If this is !=0, its an indication of outstanding references
// on WDM IRP fields such as any system buffers.
//
LONG m_IrpReferenceCount;
// This field !=NULL if the request is on an IrpQueue.
FxIrpQueue* m_IrpQueue;
WDFOBJECT_OFFSET_ALIGNED m_OutputBufferOffset;
union {
//
// Bit field. Set with values from the enum FxRequestBaseFlags
//
UCHAR m_RequestBaseFlags;
struct {
UCHAR SystemMdlMapped : 1;
UCHAR OutputMdlMapped : 1;
UCHAR SyncCleanupContext : 1;
} m_RequestBaseFlagsByName;
};
union {
//
// Bit field. Set with values from the enum FxRequestBaseStaticFlags
//
//
UCHAR m_RequestBaseStaticFlags;
struct {
UCHAR SystemBufferValid : 1;
UCHAR OutputBufferValid : 1;
} m_RequestBaseStaticFlagsByName;
};
//
// Priority boost.
//
CCHAR m_PriorityBoost;
//
// Contains values from FxRequestCompletionState
//
BYTE m_CompletionState;
//
// TRUE, request can be completed by the driver.
//
BOOLEAN m_CanComplete;
//
// If !=NULL, MDL allocated and assocated with the request
//
PMDL m_AllocatedMdl;
};
#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
#include "fxrequestbasekm.hpp"
#elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE))
#include "fxrequestbaseum.hpp"
#endif
#endif // _FXREQUESTBASE_H_