2020-09-24 20:51:15 +00:00
|
|
|
/*++
|
|
|
|
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
|
|
|
|
Module Name:
|
|
|
|
|
|
|
|
FxIoTarget.hpp
|
|
|
|
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
Encapsulation of the target to which FxRequest are sent to. For example,
|
|
|
|
an FxTarget could represent the next device object in the pnp stack.
|
|
|
|
Derivations from this class could include bus specific formatters or device
|
|
|
|
objects outside of the pnp stack of the device.
|
|
|
|
|
|
|
|
Author:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
|
|
|
|
Both kernel and user mode
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#ifndef _FXIOTARGET_H_
|
|
|
|
#define _FXIOTARGET_H_
|
|
|
|
|
|
|
|
|
|
|
|
struct FxIoContext : public FxRequestContext {
|
|
|
|
|
|
|
|
FxIoContext(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
~FxIoContext(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
StoreAndReferenceOtherMemory(
|
|
|
|
__in FxRequestBuffer* Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
_StoreAndReferenceMemoryWorker(this, &m_OtherMemory, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
ReleaseAndRestore(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ClearBuffer(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SetBufferAndLength(
|
|
|
|
__in PVOID Buffer,
|
|
|
|
__in size_t BufferLength,
|
|
|
|
__in BOOLEAN CopyBackToBuffer
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CopyParameters(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CaptureState(
|
|
|
|
__in FxIrp* Irp
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SwapIrpBuffer(
|
|
|
|
_In_ FxRequestBase* Request,
|
|
|
|
_In_ ULONG NewInputBufferCb,
|
|
|
|
_In_reads_bytes_opt_(NewInputBufferCb) PVOID NewInputBuffer,
|
|
|
|
_In_ ULONG NewOutputBufferCb,
|
|
|
|
_In_reads_bytes_opt_(NewOutputBufferCb) PVOID NewOutputBuffer
|
|
|
|
);
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
|
|
|
PVOID m_BufferToFree;
|
|
|
|
PVOID m_OriginalSystemBuffer;
|
|
|
|
PVOID m_OriginalUserBuffer;
|
|
|
|
PMDL m_MdlToFree;
|
|
|
|
union {
|
|
|
|
PMDL m_OriginalMdl;
|
|
|
|
PFX_DRIVER_GLOBALS m_DriverGlobals;
|
|
|
|
};
|
|
|
|
|
|
|
|
ULONG m_OriginalFlags;
|
|
|
|
|
|
|
|
size_t m_BufferToFreeLength;
|
|
|
|
size_t m_MdlToFreeSize;
|
|
|
|
BOOLEAN m_CopyBackToBuffer;
|
|
|
|
BOOLEAN m_UnlockPages;
|
|
|
|
#else
|
|
|
|
//
|
|
|
|
// Captured state of the IRP before buffers are modified by Format
|
|
|
|
//
|
|
|
|
WUDFX_IRP_BUFFER_INFO m_OriginalBufferInfo;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BOOLEAN m_RestoreState;
|
|
|
|
UCHAR m_MajorFunction;
|
|
|
|
IFxMemory* m_OtherMemory;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FxInternalIoctlOthersContext : public FxRequestContext {
|
|
|
|
|
|
|
|
FxInternalIoctlOthersContext(
|
|
|
|
VOID
|
|
|
|
) :
|
|
|
|
FxRequestContext(FX_RCT_INTERNAL_IOCTL_OTHERS)
|
|
|
|
{
|
|
|
|
RtlZeroMemory(&m_MemoryObjects[0], sizeof(m_MemoryObjects));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
StoreAndReferenceOtherMemories(
|
|
|
|
__in FxRequestBuffer* Buffer1,
|
|
|
|
__in FxRequestBuffer* Buffer2,
|
|
|
|
__in FxRequestBuffer* Buffer4
|
|
|
|
)
|
|
|
|
{
|
|
|
|
StoreAndReferenceMemory(Buffer1);
|
|
|
|
_StoreAndReferenceMemoryWorker(this, &m_MemoryObjects[0], Buffer2);
|
|
|
|
_StoreAndReferenceMemoryWorker(this, &m_MemoryObjects[1], Buffer4);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
ReleaseAndRestore(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
for (i = 0;
|
|
|
|
i < sizeof(m_MemoryObjects)/sizeof(m_MemoryObjects[0]);
|
|
|
|
i++) {
|
|
|
|
|
|
|
|
if (m_MemoryObjects[i] != NULL) {
|
|
|
|
m_MemoryObjects[i]->RELEASE(this);
|
|
|
|
m_MemoryObjects[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-16 03:30:51 +00:00
|
|
|
FxRequestContext::ReleaseAndRestore(Request); // __super call
|
2020-09-24 20:51:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
StoreAndReferenceMemory(
|
|
|
|
__in FxRequestBuffer* Buffer
|
|
|
|
)
|
|
|
|
{
|
2020-10-16 03:30:51 +00:00
|
|
|
FxRequestContext::StoreAndReferenceMemory(Buffer); // __super call
|
2020-09-24 20:51:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
//
|
|
|
|
// __super has a field for one IFxMemory, so we don't need to store all
|
|
|
|
// 3 in the derivative, reuse the __super's field for one of them.
|
|
|
|
//
|
|
|
|
IFxMemory* m_MemoryObjects[FX_REQUEST_NUM_OTHER_PARAMS-1];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FxTargetSubmitSyncParams {
|
|
|
|
//
|
|
|
|
// Event to set if the request is synchronous after the request has completed
|
|
|
|
//
|
|
|
|
FxCREvent SynchEvent;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Status of the request if it was synchronous
|
|
|
|
//
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Original completion routine to be called in the synchronous case
|
|
|
|
//
|
|
|
|
PFN_WDF_REQUEST_COMPLETION_ROUTINE OrigTargetCompletionRoutine;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Original completion context to be passed in the synchronous case
|
|
|
|
//
|
|
|
|
WDFCONTEXT OrigTargetCompletionContext;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum SubmitActionFlags {
|
|
|
|
SubmitSend = 0x00000001,
|
|
|
|
SubmitQueued = 0x00000002,
|
|
|
|
SubmitSent = 0x00000004,
|
|
|
|
SubmitWait = 0x00000008,
|
|
|
|
SubmitTimeout = 0x00000010,
|
|
|
|
SubmitSyncCallCompletion = 0x00000020,
|
|
|
|
};
|
|
|
|
|
|
|
|
class FxIoTarget : public FxNonPagedObject {
|
|
|
|
|
|
|
|
friend FxRequestBase;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
FxIoTarget(
|
|
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
|
|
|
__in USHORT ObjectSize
|
|
|
|
);
|
|
|
|
|
|
|
|
FxIoTarget(
|
|
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
|
|
|
__in USHORT ObjectSize,
|
|
|
|
__in WDFTYPE WdfType
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
Start(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
Stop(
|
|
|
|
__in WDF_IO_TARGET_SENT_IO_ACTION Action
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
Purge(
|
|
|
|
__in WDF_IO_TARGET_PURGE_IO_ACTION Action
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
Remove(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// IFxObject override
|
|
|
|
//
|
|
|
|
NTSTATUS
|
|
|
|
_Must_inspect_result_
|
|
|
|
QueryInterface(
|
|
|
|
__inout FxQueryInterfaceParams* Params
|
|
|
|
);
|
|
|
|
|
|
|
|
__inline
|
|
|
|
WDF_IO_TARGET_STATE
|
|
|
|
GetState(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_State;
|
|
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
|
|
MdDeviceObject
|
|
|
|
GetTargetDevice(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_TargetDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
|
|
MdDeviceObject
|
|
|
|
GetTargetPDO(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_TargetPdo;
|
|
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
|
|
MdFileObject
|
|
|
|
GetTargetFileObject(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_TargetFileObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
|
|
WDFDEVICE
|
|
|
|
GetDeviceHandle(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_Device->GetHandle();
|
|
|
|
}
|
|
|
|
|
|
|
|
WDFIOTARGET
|
|
|
|
GetHandle(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return (WDFIOTARGET) GetObjectHandle();
|
|
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
|
|
FxDriver*
|
|
|
|
GetDriver(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return m_Driver;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual
|
|
|
|
_Must_inspect_result_
|
|
|
|
MdDeviceObject
|
|
|
|
GetTargetDeviceObject(
|
|
|
|
_In_ CfxDeviceBase* Device
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return Device->GetAttachedDevice();
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
Init(
|
|
|
|
__in CfxDeviceBase* Device
|
|
|
|
);
|
|
|
|
|
|
|
|
ULONG
|
|
|
|
Submit(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in_opt PWDF_REQUEST_SEND_OPTIONS Options,
|
|
|
|
__in_opt ULONG Flags
|
|
|
|
);
|
|
|
|
|
|
|
|
// Do not specify argument names
|
|
|
|
FX_DECLARE_VF_FUNCTION_P1(
|
|
|
|
NTSTATUS,
|
|
|
|
VerifySubmitLocked,
|
|
|
|
_In_ FxRequestBase*
|
|
|
|
);
|
|
|
|
|
|
|
|
ULONG
|
|
|
|
SubmitLocked(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in_opt PWDF_REQUEST_SEND_OPTIONS Options,
|
|
|
|
__in ULONG Flags
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
SubmitSync(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in_opt PWDF_REQUEST_SEND_OPTIONS Options = NULL,
|
|
|
|
__out_opt PULONG Action = NULL
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
TimerCallback(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CompleteCanceledRequest(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SubmitPendedRequest(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CompletePendedRequest(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
_CancelSentRequest(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
__inline
|
|
|
|
HasEnoughStackLocations(
|
|
|
|
__in FxIrp* Irp
|
|
|
|
)
|
|
|
|
{
|
|
|
|
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
|
|
|
//
|
|
|
|
// Check to make sure there are enough current stack locations available.
|
|
|
|
// When a IRP is initially created, Irp->CurrentLocation is set to
|
|
|
|
// StackSize + 1. When comparing against the target device, subtract
|
|
|
|
// off the extra space to see how many locations are left.
|
|
|
|
//
|
|
|
|
// Say Target->m_TargetStackSize == 1, then:
|
|
|
|
// irp = IoAllocateIrp(Target->m_TargetStackSize, FALSE);
|
|
|
|
// ASSERT(irp->CurrentLocation == 2);
|
|
|
|
//
|
|
|
|
return (Irp->GetCurrentIrpStackLocationIndex() - 1 >= m_TargetStackSize) ? TRUE : FALSE;
|
|
|
|
#else // FX_CORE_USER_MODE
|
|
|
|
//
|
|
|
|
// For UMDF, host does the necessary checks to ensure there are enough
|
|
|
|
// stack locations. In addition, UMDF drivers can't create WDM IRPs
|
|
|
|
// so they don't get to dictate the number of stack locations in the irp
|
|
|
|
// so this kind of check in framework for UMDF is redundant. Return TRUE
|
|
|
|
// always.
|
|
|
|
//
|
|
|
|
return TRUE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FormatIoRequest(
|
|
|
|
__inout FxRequestBase* Request,
|
|
|
|
__in UCHAR MajorCode,
|
|
|
|
__in FxRequestBuffer* IoBuffer,
|
|
|
|
__in_opt PLONGLONG StartingOffset,
|
|
|
|
__in_opt FxFileObject* FileObject = NULL
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FormatIoctlRequest(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in ULONG Ioctl,
|
|
|
|
__in BOOLEAN Internal,
|
|
|
|
__in FxRequestBuffer* InputBuffer,
|
|
|
|
__in FxRequestBuffer* OutputBuffer,
|
|
|
|
__in_opt FxFileObject* FileObject = NULL
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FormatInternalIoctlOthersRequest(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in ULONG Ioctl,
|
|
|
|
__in FxRequestBuffer* Buffers
|
|
|
|
);
|
|
|
|
|
|
|
|
static
|
|
|
|
FxIoTarget*
|
|
|
|
_FromEntry(
|
|
|
|
__in FxTransactionedEntry* Entry
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(Entry, FxIoTarget, m_TransactionedEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CancelSentIo(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
SubmitSyncRequestIgnoreTargetState(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in_opt PWDF_REQUEST_SEND_OPTIONS RequestOptions
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
UpdateTargetIoType(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
HasValidStackSize(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
Send(
|
|
|
|
_In_ MdIrp Irp
|
|
|
|
);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
//
|
|
|
|
// Hide destructor since we are reference counted object
|
|
|
|
//
|
|
|
|
~FxIoTarget();
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
InitModeSpecific(
|
|
|
|
__in CfxDeviceBase* Device
|
|
|
|
);
|
|
|
|
|
|
|
|
// FxObject overrides
|
|
|
|
virtual
|
|
|
|
BOOLEAN
|
|
|
|
Dispose(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
// FxObject overrides
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FailPendedRequest(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in NTSTATUS Status
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
DrainPendedRequestsLocked(
|
|
|
|
__in PLIST_ENTRY RequestListHead,
|
|
|
|
__in BOOLEAN RequestWillBeResent
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CompletePendedRequestList(
|
|
|
|
__in PLIST_ENTRY RequestListHead
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SubmitPendedRequests(
|
|
|
|
__in PLIST_ENTRY RequestListHeadHead
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GetSentRequestsListLocked(
|
|
|
|
__in PSINGLE_LIST_ENTRY RequestListHead,
|
|
|
|
__in PLIST_ENTRY SendList,
|
|
|
|
__out PBOOLEAN AddedToList
|
|
|
|
);
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
_CancelSentRequests(
|
|
|
|
__in PSINGLE_LIST_ENTRY RequestListHead
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
GotoStartState(
|
|
|
|
__in PLIST_ENTRY RequestListHead,
|
|
|
|
__in BOOLEAN Lock = TRUE
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
GotoStopState(
|
|
|
|
__in WDF_IO_TARGET_SENT_IO_ACTION Action,
|
|
|
|
__in PSINGLE_LIST_ENTRY SentRequestListHead,
|
|
|
|
__out PBOOLEAN Wait,
|
|
|
|
__in BOOLEAN LockSelf
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
GotoPurgeState(
|
|
|
|
__in WDF_IO_TARGET_PURGE_IO_ACTION Action,
|
|
|
|
__in PLIST_ENTRY PendedRequestListHead,
|
|
|
|
__in PSINGLE_LIST_ENTRY SentRequestListHead,
|
|
|
|
__out PBOOLEAN Wait,
|
|
|
|
__in BOOLEAN LockSelf
|
|
|
|
);
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
PendRequestLocked(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
__inline
|
|
|
|
VOID
|
|
|
|
CompleteRequest(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// This will remove the reference taken by this object on the request
|
|
|
|
//
|
|
|
|
Request->CompleteSubmitted();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Completion routine to handle the case when re-submitting a pended
|
|
|
|
// request fails.
|
|
|
|
//
|
|
|
|
VOID
|
|
|
|
HandleFailedResubmit(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Generic I/O completion routine and its static caller.
|
|
|
|
//
|
|
|
|
VOID
|
|
|
|
RequestCompletionRoutine(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
static
|
|
|
|
MdCompletionRoutineType
|
|
|
|
_RequestCompletionRoutine;
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
RemoveCompletedRequestLocked(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
ClearTargetPointers(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
m_TargetDevice = NULL;
|
|
|
|
m_TargetPdo = NULL;
|
|
|
|
m_TargetFileObject = NULL;
|
|
|
|
|
|
|
|
m_TargetStackSize = 0;
|
|
|
|
m_TargetIoType = WdfDeviceIoUndefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
UCHAR
|
|
|
|
GetTargetIoType(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ULONG flags;
|
|
|
|
MxDeviceObject deviceObject(m_TargetDevice);
|
|
|
|
|
|
|
|
flags = deviceObject.GetFlags();
|
|
|
|
|
|
|
|
if (flags & DO_BUFFERED_IO) {
|
|
|
|
return WdfDeviceIoBuffered;
|
|
|
|
}
|
|
|
|
else if (flags & DO_DIRECT_IO) {
|
|
|
|
return WdfDeviceIoDirect;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return WdfDeviceIoNeither;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
_RequestCancelled(
|
|
|
|
__in FxIrpQueue* Queue,
|
|
|
|
__in MdIrp Irp,
|
|
|
|
__in PMdIoCsqIrpContext pCsqContext,
|
|
|
|
__in KIRQL CallerIrql
|
|
|
|
);
|
|
|
|
|
|
|
|
static
|
|
|
|
EVT_WDF_REQUEST_COMPLETION_ROUTINE
|
|
|
|
_SyncCompletionRoutine;
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
GotoRemoveState(
|
|
|
|
__in WDF_IO_TARGET_STATE NewState,
|
|
|
|
__in PLIST_ENTRY PendedRequestListHead,
|
|
|
|
__in PSINGLE_LIST_ENTRY SentRequestListHead,
|
|
|
|
__in BOOLEAN Lock,
|
|
|
|
__out PBOOLEAN Wait
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
WaitForSentIoToComplete(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
|
|
|
|
|
|
|
|
m_SentIoEvent.EnterCRAndWaitAndLeave();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
WaitForDisposeEvent(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
|
|
|
//
|
|
|
|
//Making it a virtual function so that derived classes can override it
|
|
|
|
//For example, CWdfIoTargetLocal overrides it to set the file object
|
|
|
|
//before forwarding the request
|
|
|
|
//
|
|
|
|
virtual
|
|
|
|
VOID
|
|
|
|
Forward(
|
|
|
|
__in MdIrp Irp
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Ignore the return value because once we have sent the request, we
|
|
|
|
// want all processing to be done in the completion routine.
|
|
|
|
//
|
|
|
|
(void) Irp->Forward();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__inline
|
|
|
|
VOID
|
|
|
|
CopyFileObjectAndFlags(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
)
|
|
|
|
{
|
|
|
|
FxIrp* irp = Request->GetSubmitFxIrp();
|
|
|
|
|
|
|
|
if (Request->IsAllocatedFromIo()) {
|
|
|
|
irp->SetNextStackFlags(irp->GetCurrentStackFlags());
|
|
|
|
irp->SetNextStackFileObject(irp->GetCurrentStackFileObject());
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Use the target's fileobject if present, otherwise use the current
|
|
|
|
// stack location's fileobject (if there is a current stack location).
|
|
|
|
//
|
|
|
|
if (m_InStack == FALSE) {
|
|
|
|
irp->SetNextStackFileObject(m_TargetFileObject);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__inline
|
|
|
|
VOID
|
|
|
|
IncrementIoCount(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
LONG ret;
|
|
|
|
|
|
|
|
ret = InterlockedIncrement(&m_IoCount);
|
|
|
|
|
|
|
|
#if DBG
|
|
|
|
ASSERT(ret > 1);
|
|
|
|
#else
|
|
|
|
UNREFERENCED_PARAMETER(ret);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__inline
|
|
|
|
VOID
|
|
|
|
DecrementIoCount(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
LONG ret;
|
|
|
|
|
|
|
|
ret = InterlockedDecrement(&m_IoCount);
|
|
|
|
ASSERT(ret >= 0);
|
|
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
PrintDisposeMessage();
|
|
|
|
ASSERT(m_DisposeEvent != NULL);
|
|
|
|
m_DisposeEvent->Set();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
PrintDisposeMessage(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
VOID
|
|
|
|
Construct(
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ClearCompletedRequestVerifierFlags(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (GetDriverGlobals()->FxVerifierOn &&
|
|
|
|
GetDriverGlobals()->FxVerifierIO) {
|
|
|
|
KIRQL irql;
|
|
|
|
|
|
|
|
Request->Lock(&irql);
|
|
|
|
//
|
|
|
|
// IF we are completing a request that was pended in the target,
|
|
|
|
// this flag was not set.
|
|
|
|
//
|
|
|
|
// ASSERT(Request->GetVerifierFlagsLocked() & FXREQUEST_FLAG_SENT_TO_TARGET);
|
|
|
|
Request->ClearVerifierFlagsLocked(FXREQUEST_FLAG_SENT_TO_TARGET);
|
|
|
|
Request->Unlock(irql);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
SetCompletionRoutine(
|
|
|
|
__in FxRequestBase* Request
|
|
|
|
)
|
|
|
|
{
|
|
|
|
FxIrp* irp = Request->GetSubmitFxIrp();
|
|
|
|
|
|
|
|
irp->SetCompletionRoutineEx(
|
|
|
|
m_InStackDevice,
|
|
|
|
_RequestCompletionRoutine,
|
|
|
|
Request,
|
|
|
|
TRUE,
|
|
|
|
TRUE,
|
|
|
|
TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
//
|
|
|
|
// Transaction entry for FxDevice to queue this target on
|
|
|
|
//
|
|
|
|
FxTransactionedEntry m_TransactionedEntry;
|
|
|
|
|
|
|
|
BOOLEAN m_InStack;
|
|
|
|
|
|
|
|
//
|
|
|
|
// TRUE when FxDevice::AddIoTarget has been called
|
|
|
|
//
|
|
|
|
BOOLEAN m_AddedToDeviceList;
|
|
|
|
|
|
|
|
static const PVOID m_SentRequestTag;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
//
|
|
|
|
// List of requests that have been sent to the target
|
|
|
|
//
|
|
|
|
LIST_ENTRY m_SentIoListHead;
|
|
|
|
|
|
|
|
//
|
|
|
|
// List of requests which were sent ignoring the state of the target
|
|
|
|
//
|
|
|
|
LIST_ENTRY m_IgnoredIoListHead;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Event used to wait for sent I/O to complete
|
|
|
|
//
|
|
|
|
FxCREvent m_SentIoEvent;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Event used to wait by Dispose to make sure all I/O's are completed.
|
|
|
|
// This is required to make sure that all the I/O are completed before
|
|
|
|
// disposing the target. This acts like remlock.
|
|
|
|
//
|
|
|
|
FxCREvent *m_DisposeEvent;
|
|
|
|
|
|
|
|
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
|
|
|
//
|
|
|
|
// Eventy initialization can fail in user-mode so we define one as
|
|
|
|
// part of object.
|
|
|
|
//
|
|
|
|
FxCREvent m_DisposeEventUm;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
FxIrpQueue m_PendedQueue;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Back link to the object that represents our devobj
|
|
|
|
//
|
|
|
|
FxDriver* m_Driver;
|
|
|
|
|
|
|
|
//
|
|
|
|
// The PDEVICE_OBJECT that is owned by m_Device
|
|
|
|
//
|
|
|
|
MdDeviceObject m_InStackDevice;
|
|
|
|
|
|
|
|
//
|
|
|
|
// The device object which is our "target"
|
|
|
|
//
|
|
|
|
MdDeviceObject m_TargetDevice;
|
|
|
|
|
|
|
|
//
|
|
|
|
// The PDO for m_TargetDevice. For this class, it would be the same PDO
|
|
|
|
// as the owning WDFDEVICE. In a derived class (like FxIoTargetRemote),
|
|
|
|
// this would not be the PDO of the owning WDFDEVICE, rather the PDO for
|
|
|
|
// the other stack.
|
|
|
|
//
|
|
|
|
MdDeviceObject m_TargetPdo;
|
|
|
|
|
|
|
|
//
|
|
|
|
// File object that is attached to all I/O sent to m_TargetDevice
|
|
|
|
//
|
|
|
|
MdFileObject m_TargetFileObject;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Current state
|
|
|
|
//
|
|
|
|
WDF_IO_TARGET_STATE m_State;
|
|
|
|
|
|
|
|
//
|
|
|
|
// This is used to track the I/O's sent to the lower driver
|
|
|
|
// and is used to make sure all I/Os are completed before disposing the
|
|
|
|
// Iotarget.
|
|
|
|
//
|
|
|
|
LONG m_IoCount;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Cached value of m_TargetDevice->StackSize. The value is cached so that
|
|
|
|
// we can still format to the target during query remove transitions.
|
|
|
|
//
|
|
|
|
CCHAR m_TargetStackSize;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Cached value of m_TargetDevice->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)
|
|
|
|
// which uses WDF_DEVICE_IO_TYPE to indicate state.
|
|
|
|
//
|
|
|
|
UCHAR m_TargetIoType;
|
|
|
|
|
|
|
|
//
|
|
|
|
// TRUE if we are in the processing of stopping/purging and there are
|
|
|
|
// requests that have been sent and must be waited upon for completion.
|
|
|
|
//
|
|
|
|
BOOLEAN m_WaitingForSentIo;
|
|
|
|
|
|
|
|
BOOLEAN m_Removing;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
|
2020-10-16 03:30:51 +00:00
|
|
|
#include "fxiotargetkm.hpp"
|
|
|
|
#elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE))
|
|
|
|
#include "fxiotargetum.hpp"
|
2020-09-24 20:51:15 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif //_FXIOTARGET_H_
|