reactos/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestbase.hpp
Victor Perevertkin 1f377076d7
[WDF] Fix KMDF so it can compile with ReactOS SDK
Not all files are included, but these are necessary to compile cdrom driver.
So far it can only be statically linked with drivers, a proper
implementation requires wdfldr helper driver
2020-11-03 00:06:27 +03:00

962 lines
20 KiB
C++

/*++
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_