mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-27 11:53:32 +00:00
[WDF] Add Windows Driver Framework files
Takern from Microsoft GitHub repo: https://github.com/microsoft/Windows-Driver-Frameworks/commit/d9c6040fe9fa787964ea99c48a8b35cf1aa978f7 Licensed under MIT
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
Fx.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the main driver framework include file.
|
||||
|
||||
Author:
|
||||
WDF team
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _FX_H
|
||||
#define _FX_H
|
||||
|
||||
extern "C" {
|
||||
#include "mx.h"
|
||||
}
|
||||
|
||||
#include "FxMacros.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "wdf.h"
|
||||
#include "wdmsec.h"
|
||||
#include "wdmguid.h"
|
||||
|
||||
#include "wdfdevicepri.h"
|
||||
#include "wdfiotargetpri.h"
|
||||
#include "wdfcx.h"
|
||||
#include "wdfldr.h"
|
||||
|
||||
#include <FxDynamicsWrapper.h>
|
||||
|
||||
#include "wdf10.h"
|
||||
#include "wdf11.h"
|
||||
#include "wdf15.h"
|
||||
#include "wdf17.h"
|
||||
#include "wdf19.h"
|
||||
#include "wdf111.h"
|
||||
#include "wdf113.h"
|
||||
#include "wdf115.h"
|
||||
}
|
||||
|
||||
#define KMDF_ONLY_CODE_PATH_ASSERT()
|
||||
|
||||
// Integer overflow functions
|
||||
#include "ntintsafe.h"
|
||||
|
||||
#include "FxForward.hpp"
|
||||
|
||||
//KMDF defines for shared type names
|
||||
#include "FxTypeDefsKm.hpp"
|
||||
|
||||
#include "fxwmicompat.h"
|
||||
#include "fxtrace.h"
|
||||
#include "fxtypes.h"
|
||||
#include "fxrequestcontexttypes.h"
|
||||
#include "fxpool.h"
|
||||
#include "FxGlobalsKM.h"
|
||||
#include "FxPoolInlines.hpp"
|
||||
#include "fxverifier.h"
|
||||
#include "fxverifierkm.h"
|
||||
#include "FxMdl.h"
|
||||
#include "FxProbeAndLock.h"
|
||||
|
||||
#include "FxPerfTraceKm.hpp"
|
||||
#include "DriverFrameworks-KernelMode-KmEvents.h"
|
||||
|
||||
#include <NtStrSafe.h>
|
||||
|
||||
#include "FxStump.hpp"
|
||||
|
||||
#include "FxRequestBuffer.hpp"
|
||||
|
||||
#include "FxTagTracker.hpp"
|
||||
|
||||
// internal locks
|
||||
#include "FxVerifierLock.hpp"
|
||||
#include "FxLock.hpp"
|
||||
|
||||
// base objects
|
||||
#include "fxobject.hpp"
|
||||
#include "FxPagedObject.hpp"
|
||||
#include "FxNonPagedObject.hpp"
|
||||
|
||||
#include "fxhandle.h"
|
||||
|
||||
// external locks
|
||||
#include "FxWaitLock.hpp"
|
||||
#include "FxSpinLock.hpp"
|
||||
|
||||
// utitilty classes and functions
|
||||
#include "FxTransactionedList.hpp"
|
||||
#include "FxRelatedDeviceList.hpp"
|
||||
#include "FxDisposeList.hpp"
|
||||
#include "FxCollection.hpp"
|
||||
#include "StringUtil.hpp"
|
||||
|
||||
// abstract classes
|
||||
#include "IFxHasCallbacks.hpp"
|
||||
|
||||
// callback delegation and locking
|
||||
#include "FxSystemThread.hpp"
|
||||
#include "FxSystemWorkItem.hpp"
|
||||
#include "FxCallbackLock.hpp"
|
||||
#include "FxCallbackSpinLock.hpp"
|
||||
#include "FxCallbackMutexLock.hpp"
|
||||
#include "FxCallback.hpp"
|
||||
#include "FxSystemThread.hpp"
|
||||
|
||||
#include "IFxMemory.hpp"
|
||||
#include "FxLookasideList.hpp"
|
||||
#include "FxNPagedLookasideList.hpp"
|
||||
#include "FxPagedLookasideList.hpp"
|
||||
#include "FxMemoryObject.hpp"
|
||||
#include "FxMemoryBuffer.hpp"
|
||||
#include "FxMemoryBufferFromPool.hpp"
|
||||
#include "FxMemoryBufferPreallocated.hpp"
|
||||
#include "FxMemoryBufferFromLookaside.hpp"
|
||||
#include "FxRequestMemory.hpp"
|
||||
#include "FxRegKey.hpp"
|
||||
#include "FxAutoRegistry.hpp"
|
||||
#include "FxAutoString.hpp"
|
||||
#include "FxString.hpp"
|
||||
|
||||
#include "FxValidateFunctions.hpp"
|
||||
#include "FxRequestValidateFunctions.hpp"
|
||||
|
||||
#include "FxResource.hpp"
|
||||
#include "FxRelatedDevice.hpp"
|
||||
#include "FxDeviceInterface.hpp"
|
||||
#include "FxQueryInterface.hpp"
|
||||
#include "FxDeviceText.hpp"
|
||||
|
||||
#include "FxIrp.hpp"
|
||||
#include "FxDriver.hpp"
|
||||
|
||||
// generic package interface
|
||||
#include "FxPackage.hpp"
|
||||
#include "FxPkgGeneral.hpp"
|
||||
#include "FxDefaultIrpHandler.hpp"
|
||||
#include "FxPkgPnp.hpp"
|
||||
#include "FxWatchDog.hpp"
|
||||
|
||||
// Device support
|
||||
#include "FxChildList.hpp"
|
||||
#include "FxCxDeviceInfo.hpp"
|
||||
#include "FxDevice.hpp"
|
||||
|
||||
#include "FxPkgIo.hpp"
|
||||
|
||||
#include "FxDeviceToMxInterface.hpp"
|
||||
|
||||
#include "FxIrpQueue.hpp"
|
||||
#include "FxRequestContext.hpp"
|
||||
#include "FxRequestCallbacks.hpp"
|
||||
#include "FxRequestBase.hpp"
|
||||
#include "FxRequest.hpp"
|
||||
#include "FxSyncRequest.hpp"
|
||||
|
||||
// specialized irp handlers (ie packages)
|
||||
#include "FxPkgFdo.hpp"
|
||||
#include "FxPkgPdo.hpp"
|
||||
#include "FxWmiIrpHandler.hpp"
|
||||
#include "FxWmiProvider.hpp"
|
||||
#include "FxWmiInstance.hpp"
|
||||
|
||||
// queus for read, write, (internal) IOCTL
|
||||
#include "FxIoQueue.hpp"
|
||||
#include "FxFileObject.hpp"
|
||||
#include "FxIrpPreprocessInfo.hpp"
|
||||
#include "FxIrpDynamicDispatchInfo.hpp"
|
||||
|
||||
#include "FxDpc.hpp"
|
||||
#include "FxWorkItem.hpp"
|
||||
#include "FxTimer.hpp"
|
||||
#include "FxInterruptKm.hpp"
|
||||
|
||||
// IO targets (device lower edge interface)
|
||||
#include "FxIoTarget.hpp"
|
||||
#include "FxIoTargetRemote.hpp"
|
||||
#include "FxIoTargetSelf.hpp"
|
||||
|
||||
#include "FxUsbDevice.hpp"
|
||||
#include "FxUsbInterface.hpp"
|
||||
#include "FxUsbPipe.hpp"
|
||||
|
||||
// DMA support
|
||||
#include "FxDmaEnabler.hpp"
|
||||
#include "FxDmaTransaction.hpp"
|
||||
#include "FxCommonBuffer.hpp"
|
||||
|
||||
// Triage info.
|
||||
#include "wdftriage.h"
|
||||
|
||||
#include "FxTelemetry.hpp"
|
||||
#endif // _FX_H
|
||||
@@ -0,0 +1,91 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxBugcheck.h
|
||||
|
||||
Abstract:
|
||||
This module contains private macros/defines for crashdumps.
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __FXBUGCHECK_H__
|
||||
#define __FXBUGCHECK_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//
|
||||
// Macro for doing pointer arithmetic.
|
||||
//
|
||||
#define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I)))
|
||||
|
||||
//
|
||||
// This macro takes a length & rounds it up to a multiple of the alignment
|
||||
// Alignment is given as a power of 2
|
||||
//
|
||||
#define EXP_ALIGN_UP_PTR_ON_BOUNDARY(_length, _alignment) \
|
||||
(PVOID) ((((ULONG_PTR) (_length)) + ((_alignment)-1)) & \
|
||||
~(ULONG_PTR)((_alignment) - 1))
|
||||
|
||||
//
|
||||
// Checks if 1st argument is aligned on given power of 2 boundary specified
|
||||
// by 2nd argument
|
||||
//
|
||||
#define EXP_IS_PTR_ALIGNED_ON_BOUNDARY(_pointer, _alignment) \
|
||||
((((ULONG_PTR) (_pointer)) & ((_alignment) - 1)) == 0)
|
||||
|
||||
|
||||
//
|
||||
// This macro takes a size and rounds it down to a multiple of the alignemnt.
|
||||
// Alignment doesn't need to be a power of 2.
|
||||
//
|
||||
#define EXP_ALIGN_DOWN_ON_BOUNDARY(_size, _alignment) \
|
||||
((_size) - ((_size) % _alignment))
|
||||
|
||||
//
|
||||
// Define the max data size the bugcheck callback can write. Per callback the
|
||||
// total size is around 16K on 32bit OS (32K on 64bit OS).
|
||||
//
|
||||
#ifdef _WIN64
|
||||
#define FX_MAX_DUMP_SIZE (32*1024)
|
||||
#else
|
||||
#define FX_MAX_DUMP_SIZE (16*1024)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Maximum number of CPUs supported by the driver tracker.
|
||||
//
|
||||
#define FX_DRIVER_TRACKER_MAX_CPUS 256 // Max Win7 processors.
|
||||
|
||||
//
|
||||
// The initial/increment size of the array to hold driver info.
|
||||
//
|
||||
#define FX_DUMP_DRIVER_INFO_INCREMENT 10 // # entries.
|
||||
|
||||
//
|
||||
// The max size of the array to hold the driver info. This is the max data
|
||||
// we can write into the minidump.
|
||||
//
|
||||
#define FX_MAX_DUMP_DRIVER_INFO_COUNT \
|
||||
(FX_MAX_DUMP_SIZE/sizeof(FX_DUMP_DRIVER_INFO_ENTRY))
|
||||
|
||||
//
|
||||
// During run-time we store info about the loaded drivers in an array
|
||||
// of FX_DUMP_DRIVER_INFO_ENTRY struct entries, on a crash we write the
|
||||
// entire array in the minidump for postmortem analysis.
|
||||
//
|
||||
typedef struct _FX_DUMP_DRIVER_INFO_ENTRY {
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals;
|
||||
WDF_VERSION Version;
|
||||
CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN];
|
||||
} FX_DUMP_DRIVER_INFO_ENTRY, *PFX_DUMP_DRIVER_INFO_ENTRY;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // __FXBUGCHECK_H__
|
||||
@@ -0,0 +1,161 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxCommonBuffer.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
WDF CommonBuffer Object support
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only.
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _FXCOMMONBUFFER_H_
|
||||
#define _FXCOMMONBUFFER_H_
|
||||
|
||||
//
|
||||
// Calculate an "aligned" address (Logical or Virtual) per
|
||||
// a specific alignment value.
|
||||
//
|
||||
FORCEINLINE
|
||||
PVOID
|
||||
FX_ALIGN_VIRTUAL_ADDRESS(
|
||||
__in PVOID VA,
|
||||
__in size_t AlignTo
|
||||
)
|
||||
{
|
||||
return (PVOID)(((ULONG_PTR)VA + AlignTo) & ~AlignTo);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
ULONGLONG
|
||||
FX_ALIGN_LOGICAL_ADDRESS(
|
||||
__in PHYSICAL_ADDRESS LA,
|
||||
__in size_t AlignTo
|
||||
)
|
||||
{
|
||||
return (LA.QuadPart + AlignTo) & ~((ULONGLONG)AlignTo);
|
||||
}
|
||||
|
||||
//
|
||||
// Declare the FxCommonBuffer class
|
||||
//
|
||||
class FxCommonBuffer : public FxNonPagedObject {
|
||||
|
||||
public:
|
||||
|
||||
FxCommonBuffer(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in FxDmaEnabler * pDmaEnabler
|
||||
);
|
||||
|
||||
virtual
|
||||
BOOLEAN
|
||||
Dispose(
|
||||
VOID
|
||||
);
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
AllocateCommonBuffer(
|
||||
__in size_t Length
|
||||
);
|
||||
|
||||
VOID
|
||||
FreeCommonBuffer(
|
||||
VOID
|
||||
);
|
||||
|
||||
__forceinline
|
||||
PHYSICAL_ADDRESS
|
||||
GetAlignedLogicalAddress(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_BufferAlignedLA;
|
||||
}
|
||||
|
||||
__forceinline
|
||||
PVOID
|
||||
GetAlignedVirtualAddress(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_BufferAlignedVA;
|
||||
}
|
||||
|
||||
__forceinline
|
||||
size_t
|
||||
GetLength(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_Length;
|
||||
}
|
||||
|
||||
__forceinline
|
||||
VOID
|
||||
SetAlignment(
|
||||
__in ULONG Alignment
|
||||
)
|
||||
{
|
||||
m_Alignment = Alignment;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Unaligned virtual address
|
||||
//
|
||||
PVOID m_BufferRawVA;
|
||||
|
||||
//
|
||||
// Aligned virtual address
|
||||
//
|
||||
PVOID m_BufferAlignedVA;
|
||||
|
||||
//
|
||||
// Aligned logical address
|
||||
//
|
||||
PHYSICAL_ADDRESS m_BufferAlignedLA;
|
||||
|
||||
//
|
||||
// Unaligned logical address
|
||||
//
|
||||
PHYSICAL_ADDRESS m_BufferRawLA;
|
||||
|
||||
//
|
||||
// Pointer to the DMA enabler
|
||||
//
|
||||
FxDmaEnabler * m_DmaEnabler;
|
||||
|
||||
//
|
||||
// Length specified by the caller
|
||||
//
|
||||
size_t m_Length;
|
||||
|
||||
//
|
||||
// Actual length used to allocate buffer after adding the alignement
|
||||
// value.
|
||||
//
|
||||
size_t m_RawLength;
|
||||
|
||||
//
|
||||
// Alignment of the allocated buffer.
|
||||
//
|
||||
size_t m_Alignment;
|
||||
|
||||
};
|
||||
|
||||
#endif // _FXCOMMONBUFFER_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,168 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDmaTransactionCallbacks.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the FxDmaTransaction object callbacks
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _FXDMATRANSACTIONCALLBACKS_H
|
||||
#define _FXDMATRANSACTIONCALLBACKS_H
|
||||
|
||||
//
|
||||
// FxDmaTransactionProgramDma or FxDmaTransactionReserveDma callback delegate
|
||||
// These are mutually exclusive callbacks and are packed together in
|
||||
// the callback structure (C++ won't allow two classes with constructors
|
||||
// to be together in a union, so the containing class can't do the
|
||||
// packing)
|
||||
//
|
||||
class FxDmaTransactionProgramOrReserveDma : public FxCallback {
|
||||
|
||||
public:
|
||||
union {
|
||||
PFN_WDF_PROGRAM_DMA ProgramDma;
|
||||
PFN_WDF_RESERVE_DMA ReserveDma;
|
||||
} Method;
|
||||
|
||||
FxDmaTransactionProgramOrReserveDma(
|
||||
VOID
|
||||
) :
|
||||
FxCallback()
|
||||
{
|
||||
Method.ProgramDma = NULL;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
InvokeProgramDma(
|
||||
__in WDFDMATRANSACTION Transaction,
|
||||
__in WDFDEVICE Device,
|
||||
__in PVOID Context,
|
||||
__in WDF_DMA_DIRECTION Direction,
|
||||
__in PSCATTER_GATHER_LIST SgList
|
||||
)
|
||||
{
|
||||
if (Method.ProgramDma) {
|
||||
BOOLEAN cc;
|
||||
|
||||
CallbackStart();
|
||||
cc = Method.ProgramDma( Transaction,
|
||||
Device,
|
||||
Context,
|
||||
Direction,
|
||||
SgList );
|
||||
CallbackEnd();
|
||||
|
||||
return cc;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
InvokeReserveDma(
|
||||
__in WDFDMATRANSACTION Transaction,
|
||||
__in PVOID Context
|
||||
)
|
||||
{
|
||||
if (Method.ReserveDma) {
|
||||
CallbackStart();
|
||||
Method.ReserveDma( Transaction, Context );
|
||||
CallbackEnd();
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
Clear(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
Method.ProgramDma = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// FxDmaTransactionConfigureChannel callback delegate
|
||||
//
|
||||
|
||||
class FxDmaTransactionConfigureChannel : public FxCallback {
|
||||
|
||||
public:
|
||||
PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL Method;
|
||||
|
||||
FxDmaTransactionConfigureChannel(
|
||||
VOID
|
||||
) :
|
||||
FxCallback()
|
||||
{
|
||||
Method = NULL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
BOOLEAN
|
||||
Invoke(
|
||||
__in WDFDMATRANSACTION DmaTransaction,
|
||||
__in WDFDEVICE Device,
|
||||
__in PVOID Context,
|
||||
__in_opt PMDL Mdl,
|
||||
__in size_t Offset,
|
||||
__in size_t Length
|
||||
)
|
||||
{
|
||||
BOOLEAN b = TRUE;
|
||||
if (Method) {
|
||||
CallbackStart();
|
||||
b = Method( DmaTransaction, Device, Context, Mdl, Offset, Length );
|
||||
CallbackEnd();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// FxDmaTransactionTransferComplete callback delegate
|
||||
//
|
||||
|
||||
class FxDmaTransactionTransferComplete : public FxCallback {
|
||||
|
||||
public:
|
||||
PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE Method;
|
||||
|
||||
FxDmaTransactionTransferComplete(
|
||||
VOID
|
||||
) :
|
||||
FxCallback()
|
||||
{
|
||||
Method = NULL;
|
||||
}
|
||||
|
||||
VOID
|
||||
Invoke(
|
||||
__in WDFDMATRANSACTION Transaction,
|
||||
__in WDFDEVICE Device,
|
||||
__in WDFCONTEXT Context,
|
||||
__in WDF_DMA_DIRECTION Direction,
|
||||
__in DMA_COMPLETION_STATUS Status
|
||||
)
|
||||
{
|
||||
if (Method) {
|
||||
CallbackStart();
|
||||
Method( Transaction, Device, Context, Direction, Status );
|
||||
CallbackEnd();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _FXDMATRANSACTIONCALLBACKS_H
|
||||
@@ -0,0 +1,201 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDpc.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed DPC that
|
||||
can synchrononize with driver frameworks object locks.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _FXDPC_H_
|
||||
#define _FXDPC_H_
|
||||
|
||||
//
|
||||
// Driver Frameworks DPC Design:
|
||||
//
|
||||
// The driver frameworks provides an optional DPC wrapper object that allows
|
||||
// the creation of a reference counted DPC object that can synchronize
|
||||
// automatically with certain frameworks objects.
|
||||
//
|
||||
// This provides automatic synchronization between the DPC's execution, and the
|
||||
// frameworks objects' event callbacks into the device driver.
|
||||
//
|
||||
// The WDFDPC object is designed to be re-useable, in which it can be re-linked
|
||||
// into the DPC queue after firing.
|
||||
//
|
||||
// In many cases, the KDPC struct is embedded inside another structure that
|
||||
// represents a device command block. These device command blocks are typically
|
||||
// submitted to another device driver. So the calling driver, which is utilizing
|
||||
// the driver frameworks would not likely have an opportunity to make
|
||||
// changes to this. In order to support this, the caller can optionally supply
|
||||
// a DPC object pointer to Initialize, and the WDFDPC object will use this
|
||||
// embedded user supplied DPC object, and pass its address as the RawDpc
|
||||
// parameter to the callback function.
|
||||
//
|
||||
// If the user does not supply a DPC pointer by passing NULL, then the
|
||||
// internal DPC object is used, and RawDPC is NULL.
|
||||
//
|
||||
// Calling GetDpcPtr returns the DPC to be used, and could be
|
||||
// the caller supplied DPC, or the embedded one depending on
|
||||
// whether the caller supplied a user DPC pointer to Initialize.
|
||||
//
|
||||
// The GetDpcPtr allows linking of the WDFDPC object into various DPC
|
||||
// lists by the driver.
|
||||
//
|
||||
|
||||
class FxDpc : public FxNonPagedObject {
|
||||
|
||||
private:
|
||||
|
||||
KDPC m_Dpc;
|
||||
|
||||
//
|
||||
// This is the Framework object who is associated with the DPC
|
||||
// if supplied
|
||||
//
|
||||
FxObject* m_Object;
|
||||
|
||||
//
|
||||
// This is the callback lock for the object this DPC will
|
||||
// synchronize with
|
||||
//
|
||||
FxCallbackLock* m_CallbackLock;
|
||||
|
||||
//
|
||||
// This is the object whose reference count actually controls
|
||||
// the lifetime of the m_CallbackLock
|
||||
//
|
||||
FxObject* m_CallbackLockObject;
|
||||
|
||||
//
|
||||
// This is the user supplied callback function
|
||||
//
|
||||
PFN_WDF_DPC m_Callback;
|
||||
|
||||
// Ensures only one of either Delete or Cleanup runs down the object
|
||||
BOOLEAN m_RunningDown;
|
||||
|
||||
public:
|
||||
static
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PWDF_DPC_CONFIG Config,
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in FxObject* ParentObject,
|
||||
__out WDFDPC* Dpc
|
||||
);
|
||||
|
||||
FxDpc(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
);
|
||||
|
||||
virtual
|
||||
~FxDpc(
|
||||
VOID
|
||||
);
|
||||
|
||||
KDPC*
|
||||
GetDpcPtr(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &m_Dpc;
|
||||
}
|
||||
|
||||
WDFOBJECT
|
||||
GetObject(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (m_Object != NULL) {
|
||||
return m_Object->GetObjectHandle();
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize the DPC using either the caller supplied DPC
|
||||
struct, or if NULL, our own internal one.
|
||||
|
||||
Arguments:
|
||||
|
||||
Returns:
|
||||
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
Initialize(
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in PWDF_DPC_CONFIG Config,
|
||||
__in FxObject* ParentObject,
|
||||
__out WDFDPC* Dpc
|
||||
);
|
||||
|
||||
virtual
|
||||
BOOLEAN
|
||||
Dispose(
|
||||
VOID
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
Cancel(
|
||||
__in BOOLEAN Wait
|
||||
);
|
||||
|
||||
VOID
|
||||
DpcHandler(
|
||||
__in PKDPC Dpc,
|
||||
__in PVOID SystemArgument1,
|
||||
__in PVOID SystemArgument2
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Called from Dispose, or cleanup list to perform final flushing of any
|
||||
// outstanding DPC's and dereferencing of objects.
|
||||
//
|
||||
VOID
|
||||
FlushAndRundown(
|
||||
);
|
||||
|
||||
static
|
||||
KDEFERRED_ROUTINE
|
||||
FxDpcThunk;
|
||||
|
||||
static
|
||||
VOID
|
||||
WorkItemThunk(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PVOID Context
|
||||
);
|
||||
};
|
||||
|
||||
#endif // _FXDPC_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
//
|
||||
//
|
||||
// Since #include'ing FxDymamics.h requires a bunch of headers before it, we
|
||||
// do this in one place because multiple spots in the code include this header.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#pragma warning(disable:4200) // zero-sized array in struct/union
|
||||
#include <usbdrivr.h>
|
||||
#pragma warning(default:4200)
|
||||
|
||||
#include <wdfusb.h>
|
||||
#include <wdfminiport.h>
|
||||
#include "FxDynamics.h"
|
||||
#include "VfFxDynamics.h"
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
//
|
||||
#ifndef __FX_LIBRARY_COMMON_H__
|
||||
#define __FX_LIBRARY_COMMON_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
extern ULONG WdfLdrDbgPrintOn;
|
||||
extern PCHAR WdfLdrType;
|
||||
|
||||
extern WDFVERSION WdfVersion;
|
||||
|
||||
extern RTL_OSVERSIONINFOW gOsVersion;
|
||||
|
||||
#define _LIT_(a) # a
|
||||
#define LITERAL(a) _LIT_(a)
|
||||
|
||||
#define __PrintUnfiltered(...) \
|
||||
DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__);
|
||||
|
||||
#define __Print(_x_) \
|
||||
{ \
|
||||
if (WdfLdrDbgPrintOn) { \
|
||||
DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, "%s: ", WdfLdrType); \
|
||||
__PrintUnfiltered _x_ \
|
||||
} \
|
||||
}
|
||||
|
||||
#define WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME L"EnhancedVerifierOptions"
|
||||
|
||||
typedef
|
||||
NTSTATUS
|
||||
(*PFN_RTL_GET_VERSION)(
|
||||
__out PRTL_OSVERSIONINFOW VersionInformation
|
||||
);
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCommonCommission(
|
||||
VOID
|
||||
);
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCommonDecommission(
|
||||
VOID
|
||||
);
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCommonRegisterClient(
|
||||
__inout PWDF_BIND_INFO Info,
|
||||
__deref_out PWDF_DRIVER_GLOBALS * WdfDriverGlobals,
|
||||
__in_opt PCLIENT_INFO ClientInfo
|
||||
);
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCommonUnregisterClient(
|
||||
__in PWDF_BIND_INFO Info,
|
||||
__in PWDF_DRIVER_GLOBALS WdfDriverGlobals
|
||||
);
|
||||
|
||||
VOID
|
||||
GetEnhancedVerifierOptions(
|
||||
__in PCLIENT_INFO ClientInfo,
|
||||
__out PULONG Options
|
||||
);
|
||||
|
||||
VOID
|
||||
LibraryLogEvent(
|
||||
__in PDRIVER_OBJECT DriverObject,
|
||||
__in NTSTATUS ErrorCode,
|
||||
__in NTSTATUS FinalStatus,
|
||||
__in PWSTR ErrorInsertionString,
|
||||
__in_bcount(RawDataLen) PVOID RawDataBuf,
|
||||
__in USHORT RawDataLen
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // __FX_LIBRARY_COMMON_H__
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
//
|
||||
#ifndef __FXPROBEANDLOCK_H__
|
||||
#define __FXPROBEANDLOCK_H__
|
||||
|
||||
extern "C" {
|
||||
|
||||
//
|
||||
// These are defined in a C file in src\support\ProbeAndLock.c
|
||||
// to avoid C++ exception handling issues.
|
||||
//
|
||||
// They do not raise the exception beyond the C function, but
|
||||
// translate it into an NTSTATUS before returning.
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
FxProbeAndLockForRead(
|
||||
__in PMDL Mdl,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
FxProbeAndLockForWrite(
|
||||
__in PMDL Mdl,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
FxProbeAndLockWithAccess(
|
||||
__in PMDL Mdl,
|
||||
__in KPROCESSOR_MODE AccessMode,
|
||||
__in LOCK_OPERATION Operation
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#endif __FXPROBEANDLOCK_H__
|
||||
@@ -0,0 +1,161 @@
|
||||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
//
|
||||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
IFxMemory.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract base class for a memory object. It is necessary to split the
|
||||
memory interface away from an FxObject derived base class so that we can
|
||||
hand out WDFMEMORY handles that are embedded within other FxObject derived
|
||||
classes without having to embed another FxObject derived class within the
|
||||
parent.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __IFX_MEMORY_HPP__
|
||||
#define __IFX_MEMORY_HPP__
|
||||
|
||||
// begin_wpp enum
|
||||
enum IFxMemoryFlags {
|
||||
IFxMemoryFlagReadOnly = 0x0001,
|
||||
};
|
||||
// end_wpp
|
||||
|
||||
|
||||
class IFxMemory {
|
||||
public:
|
||||
virtual
|
||||
PVOID
|
||||
GetBuffer(
|
||||
VOID
|
||||
) =0;
|
||||
|
||||
virtual
|
||||
size_t
|
||||
GetBufferSize(
|
||||
VOID
|
||||
) =0;
|
||||
|
||||
virtual
|
||||
PMDL
|
||||
GetMdl(
|
||||
VOID
|
||||
) =0;
|
||||
|
||||
virtual
|
||||
WDFMEMORY
|
||||
GetHandle(
|
||||
VOID
|
||||
) =0;
|
||||
|
||||
//
|
||||
// Value returned is a bit field from the enum IFxMemoryFlags
|
||||
//
|
||||
virtual
|
||||
USHORT
|
||||
GetFlags(
|
||||
VOID
|
||||
) =0;
|
||||
|
||||
virtual
|
||||
PFX_DRIVER_GLOBALS
|
||||
GetDriverGlobals(
|
||||
VOID
|
||||
) =0;
|
||||
|
||||
virtual
|
||||
ULONG
|
||||
AddRef(
|
||||
__in PVOID Tag,
|
||||
__in LONG Line,
|
||||
__in_opt PSTR File
|
||||
) =0;
|
||||
|
||||
virtual
|
||||
ULONG
|
||||
Release(
|
||||
__in PVOID Tag,
|
||||
__in LONG Line,
|
||||
__in_opt PSTR File
|
||||
) =0;
|
||||
|
||||
virtual
|
||||
VOID
|
||||
Delete(
|
||||
VOID
|
||||
) =0;
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
ValidateMemoryOffsets(
|
||||
__in_opt PWDFMEMORY_OFFSET Offsets
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
size_t total;
|
||||
|
||||
if (Offsets == NULL) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
status = RtlSizeTAdd(Offsets->BufferLength, Offsets->BufferOffset, &total);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (total > GetBufferSize()) {
|
||||
return STATUS_INTEGER_OVERFLOW;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
CopyFromPtr(
|
||||
__in_opt PWDFMEMORY_OFFSET DestinationOffsets,
|
||||
__in_bcount(SourceBufferLength) PVOID SourceBuffer,
|
||||
__in size_t SourceBufferLength,
|
||||
__in_opt PWDFMEMORY_OFFSET SourceOffsets
|
||||
);
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
CopyToPtr(
|
||||
__in_opt PWDFMEMORY_OFFSET SourceOffsets,
|
||||
__out_bcount(DestinationBufferLength) PVOID DestinationBuffer,
|
||||
__in size_t DestinationBufferLength,
|
||||
__in_opt PWDFMEMORY_OFFSET DestinationOffsets
|
||||
);
|
||||
|
||||
protected:
|
||||
static
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
_CopyPtrToPtr(
|
||||
__in_bcount(SourceBufferLength) PVOID SourceBuffer,
|
||||
__in size_t SourceBufferLength,
|
||||
__in_opt PWDFMEMORY_OFFSET SourceOffsets,
|
||||
__out_bcount(DestinationBufferLength) PVOID DestinationBuffer,
|
||||
__in size_t DestinationBufferLength,
|
||||
__in_opt PWDFMEMORY_OFFSET DestinationOffsets
|
||||
);
|
||||
};
|
||||
|
||||
#endif // __IFX_MEMORY_HPP__
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
corepriv.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Main driver framework private header.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
extern "C" {
|
||||
#include <ntddk.h>
|
||||
#include "wdf.h"
|
||||
}
|
||||
|
||||
#define WDF_REGISTRY_BASE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wdf"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,804 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxChildListApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module exposes the "C" interface to the FxChildList object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxcorepch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxChildListAPI.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfChildListCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PWDF_CHILD_LIST_CONFIG Config,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES DeviceListAttributes,
|
||||
__out
|
||||
WDFCHILDLIST* DeviceList
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice* pDevice;
|
||||
FxChildList* pList;
|
||||
size_t totalDescriptionSize = 0;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*)&pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter, WDFDEVICE %p", Device);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Config);
|
||||
FxPointerNotNull(pFxDriverGlobals, DeviceList);
|
||||
|
||||
*DeviceList = NULL;
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxChildList::_ValidateConfig(pFxDriverGlobals,
|
||||
Config,
|
||||
&totalDescriptionSize);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WDFDEVICE 0x%p Config is invalid", Device);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals,
|
||||
DeviceListAttributes,
|
||||
FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pDevice->AllocateEnumInfo();
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxChildList::_CreateAndInit(&pList,
|
||||
pFxDriverGlobals,
|
||||
DeviceListAttributes,
|
||||
totalDescriptionSize,
|
||||
pDevice,
|
||||
Config);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pList->Commit(DeviceListAttributes,
|
||||
(WDFOBJECT*)DeviceList,
|
||||
pDevice);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Could not convert object to handle, %!STATUS!",
|
||||
status);
|
||||
pList->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
pDevice->SetDeviceTelemetryInfoFlags(DeviceInfoHasDynamicChildren);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDEVICE
|
||||
WDFEXPORT(WdfChildListGetDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxChildList* pList;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
return pList->GetDevice();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfChildListRetrieveAddressDescription)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList,
|
||||
__in
|
||||
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription,
|
||||
__inout
|
||||
PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxChildList* pList;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, IdentificationDescription);
|
||||
FxPointerNotNull(pFxDriverGlobals, AddressDescription);
|
||||
|
||||
if (pList->GetIdentificationDescriptionSize() !=
|
||||
IdentificationDescription->IdentificationDescriptionSize) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"identification description size %d incorrect, expected %d, %!STATUS!",
|
||||
IdentificationDescription->IdentificationDescriptionSize,
|
||||
pList->GetIdentificationDescriptionSize(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pList->HasAddressDescriptions() == FALSE) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"cannot retrieve an address description from a list"
|
||||
" which was not initialized to use them, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pList->GetAddressDescriptionSize() !=
|
||||
AddressDescription->AddressDescriptionSize) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"description size %d incorrect, expected %d, %!STATUS!",
|
||||
AddressDescription->AddressDescriptionSize,
|
||||
pList->GetAddressDescriptionSize(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pList->GetAddressDescription(IdentificationDescription,
|
||||
AddressDescription);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Exit: WDFCHILDLIST %p, %!STATUS!",
|
||||
DeviceList, status);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfChildListBeginScan)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxChildList* pList;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
pList->BeginScan();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfChildListEndScan)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxChildList* pList;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
pList->EndScan();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfChildListBeginIteration)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList,
|
||||
__in
|
||||
PWDF_CHILD_LIST_ITERATOR Iterator
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxChildList* pList;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Iterator);
|
||||
|
||||
if (Iterator->Size != sizeof(WDF_CHILD_LIST_ITERATOR)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Iterator Size %d not correct, expected %d, %!STATUS!",
|
||||
Iterator->Size, sizeof(WDF_CHILD_LIST_ITERATOR),
|
||||
STATUS_INFO_LENGTH_MISMATCH);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Iterator->Flags & ~WdfRetrieveAllChildren) != 0) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Iterator Flags 0x%x not correct, valid mask 0x%x, %!STATUS!",
|
||||
Iterator->Flags, WdfRetrieveAllChildren, STATUS_INVALID_PARAMETER);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlZeroMemory(&Iterator->Reserved[0], sizeof(Iterator->Reserved));
|
||||
|
||||
pList->BeginIteration(Iterator);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfChildListRetrieveNextDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList,
|
||||
__in
|
||||
PWDF_CHILD_LIST_ITERATOR Iterator,
|
||||
__out
|
||||
WDFDEVICE* Device,
|
||||
__inout_opt
|
||||
PWDF_CHILD_RETRIEVE_INFO Info
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxChildList* pList;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Iterator);
|
||||
FxPointerNotNull(pFxDriverGlobals, Device);
|
||||
|
||||
*Device = NULL;
|
||||
|
||||
if (Iterator->Size != sizeof(WDF_CHILD_LIST_ITERATOR)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Iterator Size %d not correct, expected %d, %!STATUS!",
|
||||
Iterator->Size, sizeof(WDF_CHILD_LIST_ITERATOR), status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((Iterator->Flags & ~WdfRetrieveAllChildren) != 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Iterator Flags 0x%x not correct, valid mask 0x%x, %!STATUS!",
|
||||
Iterator->Flags, WdfRetrieveAllChildren, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Info != NULL) {
|
||||
if (Info->Size != sizeof(WDF_CHILD_RETRIEVE_INFO)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Invalid RetrieveInfo Size %d, expected %d, %!STATUS!",
|
||||
Info->Size, sizeof(WDF_CHILD_RETRIEVE_INFO), status);
|
||||
return status;
|
||||
}
|
||||
if (Info->IdentificationDescription != NULL
|
||||
&&
|
||||
pList->GetIdentificationDescriptionSize() !=
|
||||
Info->IdentificationDescription->IdentificationDescriptionSize) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"identification description size %d incorrect, expected %d"
|
||||
"%!STATUS!",
|
||||
Info->IdentificationDescription->IdentificationDescriptionSize,
|
||||
pList->GetIdentificationDescriptionSize(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Info->AddressDescription != NULL) {
|
||||
if (pList->HasAddressDescriptions() == FALSE) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"cannot retrieve an address description from a list"
|
||||
" which was not initialized to use them, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
else if (pList->GetAddressDescriptionSize() !=
|
||||
Info->AddressDescription->AddressDescriptionSize) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"address description size %d incorrect, expected %d, %!STATUS!",
|
||||
Info->AddressDescription->AddressDescriptionSize,
|
||||
pList->GetAddressDescriptionSize(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pList->GetNextDevice(Device, Iterator, Info);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfChildListEndIteration)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList,
|
||||
__in
|
||||
PWDF_CHILD_LIST_ITERATOR Iterator
|
||||
)
|
||||
{
|
||||
FxChildList* pList;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Iterator);
|
||||
|
||||
if (Iterator->Size != sizeof(WDF_CHILD_LIST_ITERATOR)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Iterator Size %d not correct, expected %d, %!STATUS!",
|
||||
Iterator->Size, sizeof(WDF_CHILD_LIST_ITERATOR),
|
||||
STATUS_INFO_LENGTH_MISMATCH);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Iterator->Flags & ~WdfRetrieveAllChildren) != 0) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Iterator Flags 0x%x not correct, valid mask 0x%x, %!STATUS!",
|
||||
Iterator->Flags, WdfRetrieveAllChildren, STATUS_INVALID_PARAMETER);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
pList->EndIteration(Iterator);
|
||||
}
|
||||
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfChildListAddOrUpdateChildDescriptionAsPresent)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList,
|
||||
__in
|
||||
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription,
|
||||
__in_opt
|
||||
PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxChildList* pList;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, IdentificationDescription);
|
||||
|
||||
if (AddressDescription != NULL) {
|
||||
if (pList->HasAddressDescriptions() == FALSE) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"cannot retrieve an address description from a list"
|
||||
" which was not initialized to use them, %!STATUS!", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
if (pList->GetAddressDescriptionSize() !=
|
||||
AddressDescription->AddressDescriptionSize) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"address description size %d incorrect, expected %d, %!STATUS!",
|
||||
AddressDescription->AddressDescriptionSize,
|
||||
pList->GetAddressDescriptionSize(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (pList->HasAddressDescriptions()) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Must provide a valid AddressDescription because the"
|
||||
" WDFCHILDLIST 0x%p is configured with AddressDescriptionSize,"
|
||||
" %!STATUS!", DeviceList, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (pList->GetIdentificationDescriptionSize() !=
|
||||
IdentificationDescription->IdentificationDescriptionSize) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"identification description size %d incorrect, expected %d, %!STATUS!",
|
||||
IdentificationDescription->IdentificationDescriptionSize,
|
||||
pList->GetIdentificationDescriptionSize(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pList->Add(IdentificationDescription, AddressDescription);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Exit: WDFCHILDLIST %p, %!STATUS!", DeviceList, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfChildListUpdateChildDescriptionAsMissing)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList,
|
||||
__in
|
||||
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxChildList* pList;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, IdentificationDescription);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
if (pList->GetIdentificationDescriptionSize() !=
|
||||
IdentificationDescription->IdentificationDescriptionSize) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"identification description size %d incorrect, expected %d, %!STATUS!",
|
||||
IdentificationDescription->IdentificationDescriptionSize,
|
||||
pList->GetIdentificationDescriptionSize(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pList->UpdateAsMissing(IdentificationDescription);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Exit: WDFCHILDLIST %p, %!STATUS!",
|
||||
DeviceList, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfChildListUpdateAllChildDescriptionsAsPresent)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxChildList* pList;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
pList->UpdateAllAsPresent();
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Exit: WDFCHILDLIST %p", DeviceList);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDEVICE
|
||||
WDFEXPORT(WdfChildListRetrievePdo)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList,
|
||||
__inout
|
||||
PWDF_CHILD_RETRIEVE_INFO RetrieveInfo
|
||||
)
|
||||
{
|
||||
FxChildList* pList;
|
||||
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER pId;
|
||||
PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER pAddr;
|
||||
FxDevice* device;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, RetrieveInfo);
|
||||
|
||||
if (RetrieveInfo->Size != sizeof(WDF_CHILD_RETRIEVE_INFO)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Invalid RetrieveInfo Size %x, expected %d, %!STATUS!",
|
||||
RetrieveInfo->Size, sizeof(WDF_CHILD_RETRIEVE_INFO),
|
||||
STATUS_INFO_LENGTH_MISMATCH);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pId = RetrieveInfo->IdentificationDescription;
|
||||
if (pId == NULL) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Invalid ID Description, %!STATUS!",
|
||||
STATUS_INVALID_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pList->GetIdentificationDescriptionSize() !=
|
||||
pId->IdentificationDescriptionSize) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"identification description size %d incorrect, expected %d",
|
||||
pId->IdentificationDescriptionSize,
|
||||
pList->GetIdentificationDescriptionSize());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pAddr = RetrieveInfo->AddressDescription;
|
||||
if (pAddr != NULL) {
|
||||
if (pList->HasAddressDescriptions() == FALSE) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"cannot retrieve an address description from a list"
|
||||
" which was not initialized to use them, %!STATUS!",
|
||||
STATUS_INVALID_DEVICE_REQUEST);
|
||||
return NULL;
|
||||
}
|
||||
else if (pList->GetAddressDescriptionSize() != pAddr->AddressDescriptionSize) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"address description size %d incorrect, expected %d",
|
||||
pAddr->AddressDescriptionSize, pList->GetAddressDescriptionSize());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
RetrieveInfo->Status = WdfChildListRetrieveDeviceUndefined;
|
||||
|
||||
device = pList->GetDeviceFromId(RetrieveInfo);
|
||||
|
||||
WDFDEVICE handle;
|
||||
|
||||
if (device != NULL) {
|
||||
handle = device->GetHandle();
|
||||
}
|
||||
else {
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Exit: WDFCHILDLIST %p, WDFDEVICE Pdo %p, "
|
||||
"%!WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS!",
|
||||
DeviceList, handle, RetrieveInfo->Status);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
WDFEXPORT(WdfChildListRequestChildEject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCHILDLIST DeviceList,
|
||||
__in
|
||||
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription
|
||||
)
|
||||
{
|
||||
FxChildList* pList;
|
||||
FxDevice* device;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DeviceList,
|
||||
FX_TYPE_CHILD_LIST,
|
||||
(PVOID*)&pList,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter: WDFCHILDLIST %p", DeviceList);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, IdentificationDescription);
|
||||
|
||||
if (pList->GetIdentificationDescriptionSize() !=
|
||||
IdentificationDescription->IdentificationDescriptionSize) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"identification description size 0x%x incorrect, expected 0x%x",
|
||||
IdentificationDescription->IdentificationDescriptionSize,
|
||||
pList->GetIdentificationDescriptionSize());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WDF_CHILD_RETRIEVE_INFO info;
|
||||
|
||||
WDF_CHILD_RETRIEVE_INFO_INIT(&info, IdentificationDescription);
|
||||
|
||||
device = pList->GetDeviceFromId(&info);
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"found: WDFCHILDLIST %p, WDFDEVICE PDO %p",
|
||||
DeviceList, device == NULL ? NULL : device->GetHandle());
|
||||
|
||||
if (device != NULL) {
|
||||
PDEVICE_OBJECT pdo;
|
||||
|
||||
//
|
||||
// Make sure we have a valid PDO that can be ejected
|
||||
//
|
||||
pdo = device->GetSafePhysicalDevice();
|
||||
|
||||
if (pdo != NULL) {
|
||||
IoRequestDeviceEject(pdo);
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"PDO WDFDEVICE %p not reported yet to pnp, cannot eject!",
|
||||
device->GetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
} // extern "C" of entire file
|
||||
@@ -0,0 +1,29 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fxcorepch.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains header definitions and include files needed by all
|
||||
modules in fx\core
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __FX_CORE_PCH_H__
|
||||
#define __FX_CORE_PCH_H__
|
||||
|
||||
#include "corepriv.hpp"
|
||||
#include <fx.hpp>
|
||||
|
||||
#endif // __FX_CORE_PCH_H__
|
||||
@@ -0,0 +1,464 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceFdoApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module exposes the "C" interface to the FxDevice object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxcorepch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceFdoApi.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern "C" the rest of the file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfFdoAddStaticChild)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Fdo,
|
||||
__in
|
||||
WDFDEVICE Child
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Adds a statically enumerated child to the static device list.
|
||||
|
||||
Arguments:
|
||||
Fdo - the parent of the child
|
||||
|
||||
Child - the child to add
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxStaticChildDescription description;
|
||||
FxDevice* pFdo;
|
||||
FxDevice* pPdo;
|
||||
FxPkgFdo* pPkgFdo;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Fdo,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*)&pFdo);
|
||||
|
||||
//
|
||||
// Verify type
|
||||
//
|
||||
if (pFdo->IsLegacy() || pFdo->IsFdo() == FALSE) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFdo->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p is either legacy or is not a Fdo, %!STATUS!",
|
||||
Fdo, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Child,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*)&pPdo);
|
||||
|
||||
if (pPdo->IsLegacy() || pPdo->IsPdo() == FALSE) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFdo->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE Child 0x%p is either legacy or is not a PDO, %!STATUS!",
|
||||
Child, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
pPkgFdo = pFdo->GetFdoPkg();
|
||||
|
||||
//
|
||||
// Try to add the device to the list. We use the FxDevice* of the PDO as the
|
||||
// unique ID in the list.
|
||||
//
|
||||
description.Header.IdentificationDescriptionSize = sizeof(description);
|
||||
description.Pdo = pPdo;
|
||||
|
||||
status = pPkgFdo->m_StaticDeviceList->Add(&description.Header, NULL, NULL);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
pFdo->SetDeviceTelemetryInfoFlags(DeviceInfoHasStaticChildren);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfFdoLockStaticChildListForIteration)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Fdo
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Locks the static child list for iteration. Any adds or removes that occur
|
||||
while the list is locked are pended until it is unlocked. Locking can
|
||||
be nested. When the unlock count is zero, the changes are evaluated.
|
||||
|
||||
Arguments:
|
||||
Fdo - the parent who owns the list of static children
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
WDF_CHILD_LIST_ITERATOR iterator;
|
||||
FxDevice* pDevice;
|
||||
FxPkgFdo* pPkgFdo;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Fdo,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*)&pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// Verify type
|
||||
//
|
||||
if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Invalid WDFDEVICE %p is not an FDO", Fdo);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
pPkgFdo = pDevice->GetFdoPkg();
|
||||
|
||||
//
|
||||
// Create a fake iterator to begin iteration. We will not need it in the
|
||||
// retrieve next static child call.
|
||||
//
|
||||
WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrieveAllChildren);
|
||||
|
||||
pPkgFdo->m_StaticDeviceList->BeginIteration(&iterator);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDEVICE
|
||||
WDFEXPORT(WdfFdoRetrieveNextStaticChild)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Fdo,
|
||||
__in
|
||||
WDFDEVICE PreviousChild,
|
||||
__in
|
||||
ULONG Flags
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the next static child in the list based on the PreviousChild and
|
||||
Flags values.
|
||||
|
||||
Arguments:
|
||||
Fdo - the parent which owns the static child list
|
||||
|
||||
PreviousChild - The child returned on the last call to this DDI. If NULL,
|
||||
returns the first static child specified by the Flags criteria
|
||||
|
||||
Flags - combination of values from WDF_RETRIEVE_CHILD_FLAGS.
|
||||
WdfRetrievePresentChildren - reports children who have been reported as
|
||||
present to pnp
|
||||
WdfRetrieveMissingChildren = reports children who have been reported as
|
||||
missing to pnp
|
||||
WdfRetrievePendingChildren = reports children who have been added to the
|
||||
list, but not yet reported to pnp
|
||||
|
||||
Return Value:
|
||||
next WDFDEVICE handle representing a static child or NULL
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice* pDevice;
|
||||
FxPkgFdo* pPkgFdo;
|
||||
WDFDEVICE next;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Fdo,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*)&pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// validate Flags
|
||||
//
|
||||
if (Flags == 0 || (Flags & ~WdfRetrieveAllChildren) != 0) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Invalid Flags 0x%x", Flags);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Verify type
|
||||
//
|
||||
if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p is not an FDO", Fdo);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pPkgFdo = pDevice->GetFdoPkg();
|
||||
|
||||
next = pPkgFdo->m_StaticDeviceList->GetNextStaticDevice(PreviousChild, Flags);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfFdoUnlockStaticChildListFromIteration)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Fdo
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Unlocks the static child list from iteration. Upon the last unlock, any
|
||||
pended modifications to the list will be applied.
|
||||
|
||||
Arguments:
|
||||
Fdo - the parent who owns the static child list
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
WDF_CHILD_LIST_ITERATOR iterator;
|
||||
FxDevice* pDevice;
|
||||
FxPkgFdo* pPkgFdo;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Fdo,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*)&pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// Verify type
|
||||
//
|
||||
if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p is not an FDO", Fdo);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Local iterator used to end iteration. WdfRetrieveAllChildren is an
|
||||
// arbitrary value.
|
||||
//
|
||||
WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrieveAllChildren);
|
||||
|
||||
pPkgFdo = pDevice->GetFdoPkg();
|
||||
pPkgFdo->m_StaticDeviceList->EndIteration(&iterator);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfFdoQueryForInterface)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Fdo,
|
||||
__in
|
||||
LPCGUID InterfaceType,
|
||||
__out
|
||||
PINTERFACE Interface,
|
||||
__in
|
||||
USHORT Size,
|
||||
__in
|
||||
USHORT Version,
|
||||
__in_opt
|
||||
PVOID InterfaceSpecificData
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Sends a query interface pnp request to the top of the stack (which means that
|
||||
the request will travel through this device before going down the stack).
|
||||
|
||||
Arguments:
|
||||
Fdo - the device stack which is being queried
|
||||
|
||||
InterfaceType - interface type specifier
|
||||
|
||||
Interface - Interface block which will be filled in by the component which
|
||||
responds to the query interface
|
||||
|
||||
Size - size in bytes of Interfce
|
||||
|
||||
Version - version of InterfaceType being requested
|
||||
|
||||
InterfaceSpecificData - Additional data associated with Interface
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDeviceBase* pDeviceBase;
|
||||
FxDevice* pDevice;
|
||||
FxQueryInterfaceParams params = { (PVOID*) &pDevice, FX_TYPE_DEVICE, 0 };
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Fdo,
|
||||
FX_TYPE_DEVICE_BASE,
|
||||
(PVOID*)&pDeviceBase,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
pDevice = NULL;
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, InterfaceType);
|
||||
FxPointerNotNull(pFxDriverGlobals, Interface);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// See if we have a full fledged WDFDEVICE or a miniport WDFDEVICE
|
||||
//
|
||||
if (NT_SUCCESS(pDeviceBase->QueryInterface(¶ms))) {
|
||||
//
|
||||
// Verify type
|
||||
//
|
||||
if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p Device is either legacy or is not a Fdo %!STATUS!",
|
||||
Fdo, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// miniport WDFDEVICE, nothing to check
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
|
||||
return pDeviceBase->QueryForInterface(
|
||||
InterfaceType, Interface, Size, Version, InterfaceSpecificData);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFCHILDLIST
|
||||
WDFEXPORT(WdfFdoGetDefaultChildList)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Fdo
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the default dynamic child list associated with the FDO. For a
|
||||
valid handle to be returned, the driver must have configured the default
|
||||
list in its device init phase.
|
||||
|
||||
Arguments:
|
||||
Fdo - the FDO being asked to return the handle
|
||||
|
||||
Return Value:
|
||||
a valid handle value or NULL
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice* pDevice;
|
||||
FxPkgFdo* pPkgFdo;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Fdo,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*)&pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// Verify type
|
||||
//
|
||||
if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p is not an FDO", Fdo);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pPkgFdo = pDevice->GetFdoPkg();
|
||||
|
||||
if (pPkgFdo->m_DefaultDeviceList != NULL) {
|
||||
return (WDFCHILDLIST) pPkgFdo->m_DefaultDeviceList->GetObjectHandle();
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Default child list for FDO %p not configured, call "
|
||||
"WdfFdoInitSetDefaultChildListConfig to do so", Fdo);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,491 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDevicePdoApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module exposes the "C" interface to the FxDevice object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxcorepch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDevicePdoApi.tmh"
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
GetPdoPackageFromDeviceHandle(
|
||||
__in
|
||||
IN PFX_DRIVER_GLOBALS CallersGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PCHAR FunctionName,
|
||||
__out
|
||||
FxPkgPdo **Package,
|
||||
__out
|
||||
PFX_DRIVER_GLOBALS* ObjectGlobals,
|
||||
__out_opt
|
||||
FxDevice **OutDevice = NULL
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
FxDevice *pDevice;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(CallersGlobals,
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice,
|
||||
ObjectGlobals);
|
||||
|
||||
//
|
||||
// If the optional "OutDevice" argument is present, return the pointer
|
||||
// to the device.
|
||||
//
|
||||
if (OutDevice != NULL) {
|
||||
*OutDevice = pDevice;
|
||||
}
|
||||
|
||||
//
|
||||
// Check to see if a PDO package is installed on the device.
|
||||
//
|
||||
if (pDevice->IsPdo()) {
|
||||
*Package = (FxPkgPdo *) pDevice->GetPdoPkg();
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage((*ObjectGlobals), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"%s: Incorrect device handle supplied (0x%p). "
|
||||
"Device is not a PDO.", FunctionName, Device);
|
||||
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Extern "C" the rest of the file file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfPdoMarkMissing)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxPkgPdo *pPkgPdo;
|
||||
FxDevice *pDevice;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals,
|
||||
&pDevice);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Check to see if the device is enumerated off of a child list. If so,
|
||||
// have the child list object perform any necessary actions.
|
||||
//
|
||||
status = pPkgPdo->m_OwningChildList->UpdateDeviceAsMissing(pDevice);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFAPI
|
||||
VOID
|
||||
WDFEXPORT(WdfPdoRequestEject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
FxPkgPdo *pPkgPdo;
|
||||
FxDevice *pDevice;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals,
|
||||
&pDevice);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
PDEVICE_OBJECT pdo;
|
||||
|
||||
pdo = pDevice->GetSafePhysicalDevice();
|
||||
|
||||
if (pdo != NULL) {
|
||||
IoRequestDeviceEject(pdo);
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"PDO WDFDEVICE %p not reported yet to pnp, cannot eject!",
|
||||
Device);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Can only eject PDOs, %!STATUS!", status);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDEVICE
|
||||
WDFEXPORT(WdfPdoGetParent)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxPkgPdo *pPkgPdo;
|
||||
FxDevice *pDevice;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals,
|
||||
&pDevice);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
return pDevice->m_ParentDevice->GetHandle();
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Can only eject PDOs, %!STATUS!", status);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFAPI
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfPdoRetrieveIdentificationDescription)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__inout
|
||||
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxPkgPdo *pPkgPdo;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, IdentificationDescription);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
FxChildList* pList;
|
||||
|
||||
if (pPkgPdo->m_Description == NULL) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
pList = pPkgPdo->m_Description->GetParentList();
|
||||
|
||||
//
|
||||
// The fact that a statically enumerated PDO is enumerated using an
|
||||
// FxChildList should not be exposed to the driver. Besides, the driver
|
||||
// does not know the definition of the identificaiton descirption anyways.
|
||||
//
|
||||
if (pList->IsStaticList() ||
|
||||
pList->GetIdentificationDescriptionSize() !=
|
||||
IdentificationDescription->IdentificationDescriptionSize) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
pList->CopyId(IdentificationDescription,
|
||||
pPkgPdo->m_Description->GetId());
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFAPI
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfPdoRetrieveAddressDescription)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__inout
|
||||
PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxPkgPdo *pPkgPdo;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, AddressDescription);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
FxChildList* pList;
|
||||
|
||||
if (pPkgPdo->m_Description == NULL) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
pList = pPkgPdo->m_Description->GetParentList();
|
||||
|
||||
//
|
||||
// A call to pList->IsStaticList() in the if below is not needed because
|
||||
// a static list does not have address descriptions. Make sure this
|
||||
// assumption is not violated through the ASSERT().
|
||||
//
|
||||
ASSERT(pList->IsStaticList() == FALSE);
|
||||
|
||||
if (pList->HasAddressDescriptions() == FALSE ||
|
||||
pList->GetAddressDescriptionSize() !=
|
||||
AddressDescription->AddressDescriptionSize) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
pList->GetAddressDescriptionFromEntry(pPkgPdo->m_Description,
|
||||
AddressDescription);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFAPI
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfPdoUpdateAddressDescription)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__inout
|
||||
PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxPkgPdo *pPkgPdo;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, AddressDescription);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
FxChildList* pList;
|
||||
|
||||
if (pPkgPdo->m_Description == NULL) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
pList = pPkgPdo->m_Description->GetParentList();
|
||||
|
||||
if (pList->GetAddressDescriptionSize() !=
|
||||
AddressDescription->AddressDescriptionSize) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
pList->UpdateAddressDescriptionFromEntry(pPkgPdo->m_Description,
|
||||
AddressDescription);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfPdoAddEjectionRelationsPhysicalDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PDEVICE_OBJECT PhysicalDevice
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Registers a PDO from another non descendant (not verifiable though) pnp
|
||||
stack to be reported as also requiring eject when this PDO is ejected.
|
||||
|
||||
The PDO could be another device enumerated by this driver.
|
||||
|
||||
Arguments:
|
||||
Device - the PDO for this driver
|
||||
|
||||
PhysicalDevice - PDO for the other stack
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxPkgPdo* pPkgPdo;
|
||||
NTSTATUS status;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, PhysicalDevice);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pPkgPdo->AddEjectionDevice(PhysicalDevice);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfPdoRemoveEjectionRelationsPhysicalDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PDEVICE_OBJECT PhysicalDevice
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Deregisters a PDO from another non descendant (not verifiable though) pnp
|
||||
stack so that it will not be reported as also requiring eject when this PDO
|
||||
is ejected.
|
||||
|
||||
Arguments:
|
||||
Device - the PDO for this driver
|
||||
|
||||
PhysicalDevice - PDO for the other stack
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxPkgPdo* pPkgPdo;
|
||||
NTSTATUS status;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, PhysicalDevice);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return; // status;
|
||||
}
|
||||
|
||||
pPkgPdo->RemoveEjectionDevice(PhysicalDevice);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfPdoClearEjectionRelationsDevices)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Deregisters all PDOs so that they will not be reported as also requiring
|
||||
eject when this PDO is ejected.
|
||||
|
||||
Arguments:
|
||||
Device - this driver's PDO
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxPkgPdo* pPkgPdo;
|
||||
NTSTATUS status;
|
||||
|
||||
status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
__FUNCTION__,
|
||||
&pPkgPdo,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return; // status;
|
||||
}
|
||||
|
||||
pPkgPdo->ClearEjectionDevicesList();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDpc.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed DPC that
|
||||
can synchrononize with driver frameworks object locks.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxcorepch.hpp"
|
||||
|
||||
#include "FxDpc.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxDpc.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Public constructors
|
||||
//
|
||||
|
||||
FxDpc::FxDpc(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_DPC, sizeof(FxDpc), FxDriverGlobals)
|
||||
{
|
||||
m_Object = NULL;
|
||||
m_CallbackLock = NULL;
|
||||
m_CallbackLockObject = NULL;
|
||||
m_Callback = NULL;
|
||||
m_RunningDown = FALSE;
|
||||
|
||||
//
|
||||
// Mark the object has having passive level dispose so that KeFlushQueuedDpcs
|
||||
// can be called in Dispose().
|
||||
//
|
||||
MarkPassiveDispose(ObjectDoNotLock);
|
||||
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
}
|
||||
|
||||
|
||||
FxDpc::~FxDpc()
|
||||
{
|
||||
//
|
||||
// If this hits, its because someone destroyed the DPC by
|
||||
// removing too many references by mistake without calling WdfObjectDelete
|
||||
//
|
||||
if (m_Object != NULL) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Destroy WDFDPC %p destroyed without calling WdfObjectDelete, or by"
|
||||
" Framework processing DeviceRemove. Possible reference count "
|
||||
"problem?", GetObjectHandleUnchecked());
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDpc::_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PWDF_DPC_CONFIG Config,
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in FxObject* ParentObject,
|
||||
__out WDFDPC* Dpc
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Create an FxDpc factory method
|
||||
|
||||
Arguments:
|
||||
|
||||
All arguments have been valided by the FxDpcApi stub.
|
||||
|
||||
Returns:
|
||||
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
FxDpc* pFxDpc;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDpc = new(FxDriverGlobals, Attributes) FxDpc(FxDriverGlobals);
|
||||
|
||||
if (pFxDpc == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = pFxDpc->Initialize(
|
||||
Attributes,
|
||||
Config,
|
||||
ParentObject,
|
||||
Dpc
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pFxDpc->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDpc::Initialize(
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in PWDF_DPC_CONFIG Config,
|
||||
__in FxObject* ParentObject,
|
||||
__out WDFDPC* Dpc
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
IFxHasCallbacks* pCallbacks;
|
||||
NTSTATUS status;
|
||||
KDPC* pDpc;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
pDpc = NULL;
|
||||
pCallbacks = NULL;
|
||||
|
||||
pDpc = &m_Dpc;
|
||||
|
||||
//
|
||||
// Set user's callback function
|
||||
//
|
||||
m_Callback = Config->EvtDpcFunc;
|
||||
|
||||
//
|
||||
// Initialize the DPC to point to our thunk
|
||||
//
|
||||
KeInitializeDpc(
|
||||
pDpc, // Dpc
|
||||
FxDpcThunk, // DeferredRoutine
|
||||
this // DeferredContext
|
||||
);
|
||||
|
||||
//
|
||||
// As long as we are associated, the parent object holds a reference
|
||||
// count on the DPC.
|
||||
//
|
||||
// We keep an extra reference count since on Dispose, we wait until
|
||||
// all outstanding DPC's complete before allowing finalization.
|
||||
//
|
||||
// This reference must be taken early before we return any failure,
|
||||
// since Dispose() expects this extra reference, and Dispose() will
|
||||
// be called even if we return a failure status right now.
|
||||
//
|
||||
ADDREF(this);
|
||||
|
||||
//
|
||||
// DPC's can be parented by, and optionally serialize with an FxDevice or
|
||||
// an FxQueue.
|
||||
//
|
||||
m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks);
|
||||
|
||||
if (m_DeviceBase == NULL) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
//
|
||||
// Configure Serialization for the DPC and callbacks on the supplied object
|
||||
//
|
||||
status = _GetEffectiveLock(
|
||||
ParentObject,
|
||||
pCallbacks,
|
||||
Config->AutomaticSerialization,
|
||||
FALSE,
|
||||
&m_CallbackLock,
|
||||
&m_CallbackLockObject
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (status == STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"ParentObject %p can not automatically synchronize callbacks "
|
||||
"with a DPC since it is configured for passive level callback "
|
||||
"constraints. Set AutomaticSerialization to FALSE. %!STATUS!",
|
||||
Attributes->ParentObject, status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// We automatically synchronize with and reference count
|
||||
// the lifetime of the framework object to prevent any DPC races
|
||||
// that can access the object while it is going away.
|
||||
//
|
||||
|
||||
//
|
||||
// The caller supplied object is the object the caller wants the
|
||||
// DPC to be associated with, and the framework must ensure this
|
||||
// object remains live until the DPC object is destroyed. Otherwise,
|
||||
// it could access either object context memory, or an object API
|
||||
// on a freed object.
|
||||
//
|
||||
// Due to the locking model of the framework, the lock may actually
|
||||
// be owned by a higher level object as well. This is the lockObject
|
||||
// returned. As long was we are a child of this object, the lockObject
|
||||
// does not need to be dereferenced since it will notify us of Cleanup
|
||||
// before it goes away.
|
||||
//
|
||||
|
||||
//
|
||||
// Associate the FxDpc with the object. When this object gets deleted or
|
||||
// disposed, it will notify our Dispose function as well.
|
||||
//
|
||||
|
||||
//
|
||||
// Add a reference to the parent object we are associated with.
|
||||
// We will be notified of Cleanup to release this reference.
|
||||
//
|
||||
ParentObject->ADDREF(this);
|
||||
|
||||
// Save the ptr to the object the DPC is associated with
|
||||
m_Object = ParentObject;
|
||||
|
||||
//
|
||||
// Attributes->ParentObject is the same as ParentObject. Since we already
|
||||
// converted it to an object, use that.
|
||||
//
|
||||
status = Commit(Attributes, (WDFOBJECT*)Dpc, ParentObject);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxDpc::Cancel(
|
||||
__in BOOLEAN Wait
|
||||
)
|
||||
{
|
||||
BOOLEAN result;
|
||||
|
||||
result = KeRemoveQueueDpc(GetDpcPtr());
|
||||
|
||||
//
|
||||
// If result == FALSE, then the DPC could already be running.
|
||||
//
|
||||
// If the caller supplies Wait == TRUE, they want to wait and
|
||||
// ensure on return the DPC has finished running.
|
||||
//
|
||||
// The trick here is to implement this without adding execessive
|
||||
// overhead to the "normal" path, such as tracking reference counts,
|
||||
// locking, signaling events to waiting threads, etc.
|
||||
//
|
||||
// So we take the expensive approach for the Cancel call in the
|
||||
// case the caller wants to wait, and misses the DPC window. In
|
||||
// this case we will just do the system wide FlushQueuedDpc's to
|
||||
// ensure the DPC has finished running before return.
|
||||
//
|
||||
if( Wait && !result ) {
|
||||
|
||||
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
KeFlushQueuedDpcs();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDpc::DpcHandler(
|
||||
__in PKDPC Dpc,
|
||||
__in PVOID SystemArgument1,
|
||||
__in PVOID SystemArgument2
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Dpc);
|
||||
UNREFERENCED_PARAMETER(SystemArgument1);
|
||||
UNREFERENCED_PARAMETER(SystemArgument2);
|
||||
|
||||
FX_TRACK_DRIVER(GetDriverGlobals());
|
||||
|
||||
if (m_Callback != NULL) {
|
||||
|
||||
FxPerfTraceDpc(&m_Callback);
|
||||
|
||||
if (m_CallbackLock != NULL) {
|
||||
KIRQL irql = 0;
|
||||
|
||||
m_CallbackLock->Lock(&irql);
|
||||
m_Callback((WDFDPC)(this->GetObjectHandle()));
|
||||
m_CallbackLock->Unlock(irql);
|
||||
}
|
||||
else {
|
||||
m_Callback((WDFDPC)(this->GetObjectHandle()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDpc::FxDpcThunk(
|
||||
__in PKDPC Dpc,
|
||||
__in PVOID DeferredContext,
|
||||
__in PVOID SystemArgument1,
|
||||
__in PVOID SystemArgument2
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the C routine called by the kernels DPC handler
|
||||
|
||||
Arguments:
|
||||
|
||||
Dpc - our DPC object associated with our Timer
|
||||
DeferredContext - Context for the DPC that we setup in DriverEntry
|
||||
SystemArgument1 -
|
||||
SystemArgument2 -
|
||||
|
||||
Return Value:
|
||||
|
||||
Nothing.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxDpc* pDpc = (FxDpc*)DeferredContext;
|
||||
|
||||
pDpc->DpcHandler(
|
||||
Dpc,
|
||||
SystemArgument1,
|
||||
SystemArgument2
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Called when DeleteObject is called, or when the parent
|
||||
// is being deleted or Disposed.
|
||||
//
|
||||
// Also invoked directly by the cleanup list at our request after
|
||||
// a Dispose occurs and must be deferred if not at passive level.
|
||||
//
|
||||
BOOLEAN
|
||||
FxDpc::Dispose()
|
||||
{
|
||||
// MarkPassiveDispose() in Initialize ensures this
|
||||
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
m_RunningDown = TRUE;
|
||||
|
||||
FlushAndRundown();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Called by the system work item to finish the rundown
|
||||
//
|
||||
VOID
|
||||
FxDpc::FlushAndRundown()
|
||||
{
|
||||
FxObject* pObject;
|
||||
|
||||
//
|
||||
// If we have the KeFlushQueuedDpcs function call it
|
||||
// to ensure the DPC routine is no longer running before
|
||||
// we release the final reference and memory to the framework objects
|
||||
//
|
||||
KeFlushQueuedDpcs();
|
||||
|
||||
//
|
||||
// Release our reference count to the associated parent object if present
|
||||
//
|
||||
if (m_Object != NULL) {
|
||||
pObject = m_Object;
|
||||
m_Object = NULL;
|
||||
|
||||
pObject->RELEASE(this);
|
||||
}
|
||||
|
||||
//
|
||||
// Perform our final release to ourselves, destroying the FxDpc
|
||||
//
|
||||
RELEASE(this);
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDpcApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This implements the WDFDPC API's
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxcorepch.hpp"
|
||||
|
||||
#include "FxDpc.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDpcApi.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDpcCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PWDF_DPC_CONFIG Config,
|
||||
__in
|
||||
PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__out
|
||||
WDFDPC * Dpc
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Create a DPC object that will call the supplied function with
|
||||
context when it fires. It returns a handle to the WDFDPC object.
|
||||
|
||||
Arguments:
|
||||
|
||||
Config - WDF_DPC_CONFIG structure.
|
||||
|
||||
Attributes - WDF_OBJECT_ATTRIBUTES to set the parent object and to request
|
||||
a context memory allocation, and a DestroyCallback.
|
||||
|
||||
Dpc - Pointer to location to returnt he resulting WDFDPC handle.
|
||||
|
||||
Returns:
|
||||
|
||||
STATUS_SUCCESS - A WDFDPC handle has been created.
|
||||
|
||||
Notes:
|
||||
|
||||
The WDFDPC object is deleted either when the DEVICE or QUEUE it is
|
||||
associated as its parent with is deleted, or WdfObjectDelete is called.
|
||||
|
||||
If the DPC is used to access WDM objects, a Cleanup callback should
|
||||
be registered to allow references to be released.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxObject* pParent;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
|
||||
Attributes,
|
||||
FX_VALIDATE_OPTION_PARENT_REQUIRED);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
Attributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Config);
|
||||
FxPointerNotNull(pFxDriverGlobals, Dpc);
|
||||
|
||||
if (Config->Size != sizeof(WDF_DPC_CONFIG)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDF_DPC_CONFIG got Size %d, expected %d, %!STATUS!",
|
||||
Config->Size, sizeof(WDF_DPC_CONFIG), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(
|
||||
pFxDriverGlobals,
|
||||
Attributes
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxDpc::_Create(pFxDriverGlobals, Config, Attributes, pParent, Dpc);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
__drv_maxIRQL(HIGH_LEVEL)
|
||||
KDPC*
|
||||
WDFEXPORT(WdfDpcWdmGetDpc)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDPC Dpc
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Return the KDPC* object pointer so that it may be linked into
|
||||
a DPC list.
|
||||
|
||||
Arguments:
|
||||
|
||||
WDFDPC - Handle to WDFDPC object created with WdfDpcCreate.
|
||||
|
||||
Returns:
|
||||
|
||||
KDPC*
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxDpc* pFxDpc;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Dpc,
|
||||
FX_TYPE_DPC,
|
||||
(PVOID*)&pFxDpc);
|
||||
|
||||
return pFxDpc->GetDpcPtr();
|
||||
}
|
||||
|
||||
|
||||
__drv_maxIRQL(HIGH_LEVEL)
|
||||
BOOLEAN
|
||||
WDFEXPORT(WdfDpcEnqueue)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDPC Dpc
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Enqueue the DPC to run at a system determined time
|
||||
|
||||
Arguments:
|
||||
|
||||
WDFDPC - Handle to WDFDPC object created with WdfDpcCreate.
|
||||
|
||||
Returns:
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxDpc* pFxDpc;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Dpc,
|
||||
FX_TYPE_DPC,
|
||||
(PVOID*)&pFxDpc);
|
||||
|
||||
return KeInsertQueueDpc(pFxDpc->GetDpcPtr(), NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
__drv_when(Wait == __true, __drv_maxIRQL(PASSIVE_LEVEL))
|
||||
__drv_when(Wait == __false, __drv_maxIRQL(HIGH_LEVEL))
|
||||
BOOLEAN
|
||||
WDFEXPORT(WdfDpcCancel)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDPC Dpc,
|
||||
__in
|
||||
BOOLEAN Wait
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Attempt to cancel the DPC and returns status
|
||||
|
||||
Arguments:
|
||||
|
||||
WDFDPC - Handle to WDFDPC object created with WdfDpcCreate.
|
||||
|
||||
Returns:
|
||||
|
||||
TRUE - DPC was cancelled, and was not run
|
||||
|
||||
FALSE - DPC was not cancelled, has run, is running, or will run
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDpc* pFxDpc;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Dpc,
|
||||
FX_TYPE_DPC,
|
||||
(PVOID*)&pFxDpc,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
if (Wait) {
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return pFxDpc->Cancel(Wait);
|
||||
}
|
||||
|
||||
|
||||
|
||||
__drv_maxIRQL(HIGH_LEVEL)
|
||||
WDFOBJECT
|
||||
WDFEXPORT(WdfDpcGetParentObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDPC Dpc
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Return the parent parent object supplied to WdfDpcCreate.
|
||||
|
||||
Arguments:
|
||||
|
||||
WDFDPC - Handle to WDFDPC object created with WdfDpcCreate.
|
||||
|
||||
Returns:
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxDpc* pFxDpc;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Dpc,
|
||||
FX_TYPE_DPC,
|
||||
(PVOID*)&pFxDpc);
|
||||
|
||||
return pFxDpc->GetObject();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,677 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxSystemThread.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the implementation of the FxSystemThread object.
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxcorepch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxSystemThread.tmh"
|
||||
}
|
||||
|
||||
|
||||
FxSystemThread::FxSystemThread(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_SYSTEMTHREAD, 0, FxDriverGlobals)
|
||||
{
|
||||
|
||||
m_Initialized = FALSE;
|
||||
m_ThreadPtr = NULL;
|
||||
m_Exit = FALSE;
|
||||
m_PEThread = NULL;
|
||||
|
||||
//m_Spinup.WorkerRoutine = NULL; // Async-Thread-Spinup
|
||||
m_Reaper.WorkerRoutine = NULL;
|
||||
|
||||
InitializeListHead(&m_WorkList);
|
||||
m_InitEvent.Initialize(NotificationEvent, FALSE);
|
||||
m_WorkEvent.Initialize(NotificationEvent, FALSE);
|
||||
}
|
||||
|
||||
FxSystemThread::~FxSystemThread() {
|
||||
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxSystemThread::_CreateAndInit(
|
||||
__deref_out FxSystemThread** SystemThread,
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in WDFDEVICE Device,
|
||||
__in PDEVICE_OBJECT DeviceObject
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
FxSystemThread *pThread = NULL;
|
||||
|
||||
*SystemThread = NULL;
|
||||
|
||||
pThread = new(FxDriverGlobals) FxSystemThread(FxDriverGlobals);
|
||||
if (pThread == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WDFDEVICE 0x%p !devobj %p could not allocate a thread for handling "
|
||||
"power requests %!STATUS!",
|
||||
Device, DeviceObject, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pThread->Initialize() == FALSE) {
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WDFDEVICE 0x%p, !devobj %p, could not initialize power thread, "
|
||||
"%!STATUS!",
|
||||
Device, DeviceObject, status);
|
||||
|
||||
pThread->DeleteFromFailedCreate();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
*SystemThread = pThread;
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Create the system thread in order to be able to service work items
|
||||
//
|
||||
// It is recommended this is done from the system process context
|
||||
// since the threads handle is available to the user mode process
|
||||
// for a temporary window. XP and later supports OBJ_KERNELHANDLE, but
|
||||
// DriverFrameworks must support W2K with the same binary.
|
||||
//
|
||||
// It is safe to call this at DriverEntry which is in the system process
|
||||
// to create an initial driver thread, and this driver thread should be
|
||||
// used for creating any child driver threads on demand.
|
||||
//
|
||||
BOOLEAN
|
||||
FxSystemThread::Initialize()
|
||||
{
|
||||
NTSTATUS status;
|
||||
KIRQL irql;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
// Frameworks bug if this is called with a thread already running
|
||||
ASSERT(m_ThreadPtr == NULL);
|
||||
|
||||
ASSERT(m_Initialized == FALSE);
|
||||
|
||||
m_Initialized = TRUE;
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
status = CreateThread();
|
||||
|
||||
return NT_SUCCESS(status) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxSystemThread::CreateThread(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HANDLE threadHandle;
|
||||
NTSTATUS status;
|
||||
|
||||
//
|
||||
// Take an extra object reference on ourselves to account
|
||||
// for the system thread referencing the object while it is running.
|
||||
//
|
||||
// The thread itself will release this reference in its exit routine
|
||||
//
|
||||
ADDREF(FxSystemThread::StaticThreadThunk);
|
||||
|
||||
status = PsCreateSystemThread(
|
||||
&threadHandle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL, // Obja
|
||||
NULL, // hProcess
|
||||
NULL, // CLIENT_ID,
|
||||
FxSystemThread::StaticThreadThunk,
|
||||
this
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
m_Initialized = FALSE;
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not create system thread %!STATUS!", status);
|
||||
//
|
||||
// Release the reference taken above due to failure
|
||||
//
|
||||
RELEASE(FxSystemThread::StaticThreadThunk);
|
||||
}
|
||||
else {
|
||||
status = ObReferenceObjectByHandle(
|
||||
threadHandle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
KernelMode,
|
||||
&m_ThreadPtr,
|
||||
NULL
|
||||
);
|
||||
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
|
||||
// We can now close the thread handle since we have a pointer reference
|
||||
ZwClose(threadHandle);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// This is called to tell the thread to exit.
|
||||
//
|
||||
// It must be called from thread context such as
|
||||
// the driver unload routine since it will wait for the
|
||||
// thread to exit.
|
||||
//
|
||||
BOOLEAN
|
||||
FxSystemThread::ExitThread()
|
||||
{
|
||||
NTSTATUS Status;
|
||||
KIRQL irql;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
if( !m_Initialized ) {
|
||||
Unlock(irql);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( m_Exit ) {
|
||||
ASSERT(FALSE); // This is not race free, so don't allow it
|
||||
Unlock(irql);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Tell the system thread to exit
|
||||
m_Exit = TRUE;
|
||||
|
||||
//
|
||||
// The thread could still be spinning up, so we must handle this condition.
|
||||
//
|
||||
if( m_ThreadPtr == NULL ) {
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
KeEnterCriticalRegion();
|
||||
|
||||
// Wait for thread to start
|
||||
Status = m_InitEvent.WaitFor(Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
UNREFERENCED_PARAMETER(Status);
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
|
||||
//
|
||||
// Now we have a thread, wait for it to go away
|
||||
//
|
||||
ASSERT(m_ThreadPtr != NULL);
|
||||
}
|
||||
else {
|
||||
Unlock(irql);
|
||||
}
|
||||
|
||||
m_WorkEvent.Set();
|
||||
|
||||
//
|
||||
// We can't be waiting in our own thread for the thread to exit.
|
||||
//
|
||||
ASSERT(IsCurrentThread() == FALSE);
|
||||
|
||||
KeEnterCriticalRegion();
|
||||
|
||||
// Wait for thread to exit
|
||||
Status = KeWaitForSingleObject(
|
||||
m_ThreadPtr,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL
|
||||
);
|
||||
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
UNREFERENCED_PARAMETER(Status);
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
|
||||
ObDereferenceObject(m_ThreadPtr);
|
||||
|
||||
//
|
||||
// Now safe to unload the driver or object
|
||||
// the thread worker is pointing to
|
||||
//
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxSystemThread::ExitThreadAsync(
|
||||
__inout FxSystemThread* Reaper
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
//
|
||||
// Without a top level reaper, the frameworks can not ensure
|
||||
// all worker threads have exited at driver unload in the async
|
||||
// case. If this is a top level thread, then DriverUnload should
|
||||
// call the synchronous ExitThread() method.
|
||||
//
|
||||
ASSERT(Reaper != NULL);
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
if( !m_Initialized ) {
|
||||
Unlock(irql);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( m_Exit ) {
|
||||
ASSERT(FALSE);
|
||||
Unlock(irql);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Tell the system thread to exit
|
||||
m_Exit = TRUE;
|
||||
|
||||
// Add a reference which will be released by the reaper
|
||||
ADDREF(FxSystemThread::StaticReaperThunk);
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
m_WorkEvent.Set();
|
||||
|
||||
ASSERT(m_Reaper.WorkerRoutine == NULL);
|
||||
|
||||
// We are the only user of this field protected by setting m_Exit
|
||||
m_Reaper.WorkerRoutine = FxSystemThread::StaticReaperThunk;
|
||||
m_Reaper.Parameter = this;
|
||||
|
||||
Reaper->QueueWorkItem(&m_Reaper);
|
||||
|
||||
//
|
||||
// It is not safe to unload the driver until the reaper
|
||||
// thread has processed the work item and waited for this
|
||||
// thread to exit.
|
||||
//
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxSystemThread::QueueWorkItem(
|
||||
__inout PWORK_QUEUE_ITEM WorkItem
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
BOOLEAN result;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
if (m_Exit) {
|
||||
result = FALSE;
|
||||
}
|
||||
else {
|
||||
result = TRUE;
|
||||
InsertTailList(&m_WorkList, &WorkItem->List);
|
||||
|
||||
m_WorkEvent.Set();
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Attempt to cancel the work item.
|
||||
//
|
||||
// Returns TRUE if success.
|
||||
//
|
||||
// If returns FALSE, the work item
|
||||
// routine either has been called, is running,
|
||||
// or is about to be called.
|
||||
//
|
||||
BOOLEAN
|
||||
FxSystemThread::CancelWorkItem(
|
||||
__inout PWORK_QUEUE_ITEM WorkItem
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
KIRQL irql;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
Entry = m_WorkList.Flink;
|
||||
|
||||
while( Entry != &this->m_WorkList ) {
|
||||
|
||||
if( Entry == &WorkItem->List ) {
|
||||
RemoveEntryList(&WorkItem->List);
|
||||
Unlock(irql);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Entry = Entry->Flink;
|
||||
}
|
||||
|
||||
// Not found
|
||||
Unlock(irql);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxSystemThread::Thread()
|
||||
{
|
||||
NTSTATUS status;
|
||||
LIST_ENTRY head;
|
||||
PLIST_ENTRY ple;
|
||||
PWORK_QUEUE_ITEM pItem;
|
||||
|
||||
//DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
// "Created, entering work loop");
|
||||
|
||||
//
|
||||
// The worker thread will process all list entries before
|
||||
// checking for exit. This allows the top level FxDriver
|
||||
// thread to process all deferred cleanup work items at
|
||||
// driver unload.
|
||||
//
|
||||
// CancelWorkItem may be used to remove entries
|
||||
// before requesting a thread exit if the caller wants to
|
||||
// interrupt work queue processing.
|
||||
//
|
||||
|
||||
InitializeListHead(&head);
|
||||
|
||||
// Initialize for IsCurrentThread()
|
||||
m_PEThread = Mx::GetCurrentEThread();
|
||||
|
||||
// Set the event that the thread now exists
|
||||
m_InitEvent.Set();
|
||||
|
||||
for ( ; ; ) {
|
||||
KIRQL irql;
|
||||
|
||||
//
|
||||
// Lock the list so we are in sync with QueueWorkItem
|
||||
//
|
||||
Lock(&irql);
|
||||
|
||||
while(!IsListEmpty(&m_WorkList)) {
|
||||
//
|
||||
// Instead of popping each LIST_ENTRY off of the old list and
|
||||
// enqueueing it to the local list head, manipulate the first and
|
||||
// last entry in the list to point to our new head.
|
||||
//
|
||||
head.Flink = m_WorkList.Flink;
|
||||
head.Blink = m_WorkList.Blink;
|
||||
|
||||
// First link in the list point backwrad to the new head
|
||||
m_WorkList.Flink->Blink = &head;
|
||||
|
||||
// Last link in the list point fwd to the new head
|
||||
m_WorkList.Blink->Flink = &head;
|
||||
|
||||
ASSERT(!IsListEmpty(&head));
|
||||
|
||||
//
|
||||
// Reinitialize the work list head
|
||||
//
|
||||
InitializeListHead(&m_WorkList);
|
||||
|
||||
//
|
||||
// Process the workitems while unlocked so that the work item can
|
||||
// requeue itself if needed and work at passive level.
|
||||
//
|
||||
Unlock(irql);
|
||||
|
||||
while (!IsListEmpty(&head)) {
|
||||
ple = RemoveHeadList(&head);
|
||||
pItem = CONTAINING_RECORD(ple, WORK_QUEUE_ITEM, List);
|
||||
pItem->WorkerRoutine(pItem->Parameter);
|
||||
|
||||
//
|
||||
// NOTE: pItem may have been pool released by the called worker
|
||||
// routine, so it may not be accessed after the callback
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
// Relock the list and repeat until the work list is empty
|
||||
//
|
||||
Lock(&irql);
|
||||
}
|
||||
|
||||
// No more items on list, check for exit
|
||||
if (m_Exit) {
|
||||
//DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
// "Terminating");
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
// Release the object reference held by the thread
|
||||
RELEASE(FxSystemThread::StaticThreadThunk);
|
||||
|
||||
status = PsTerminateSystemThread(STATUS_SUCCESS);
|
||||
UNREFERENCED_PARAMETER(status);
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
|
||||
// NOT REACHED
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// No work to do, clear event under lock to prevent a race with a work
|
||||
// enqueue
|
||||
//
|
||||
m_WorkEvent.Clear();
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
// We are a system thread, so we do not need KeEnterCriticalRegion()
|
||||
status = m_WorkEvent.WaitFor(
|
||||
Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
UNREFERENCED_PARAMETER(status);
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
}
|
||||
|
||||
// NOT REACHED
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
FxSystemThread::Reaper()
|
||||
{
|
||||
NTSTATUS Status;
|
||||
KIRQL irql;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
ASSERT(m_Initialized);
|
||||
ASSERT(m_Exit);
|
||||
|
||||
//
|
||||
// The thread could still be spinning up, so we must handle this condition.
|
||||
//
|
||||
if( m_ThreadPtr == NULL ) {
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
KeEnterCriticalRegion();
|
||||
|
||||
// Wait for thread to start
|
||||
Status = m_InitEvent.WaitFor(Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
UNREFERENCED_PARAMETER(Status);
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
|
||||
//
|
||||
// Now we have a thread, wait for it to go away
|
||||
//
|
||||
ASSERT(m_ThreadPtr != NULL);
|
||||
}
|
||||
else {
|
||||
Unlock(irql);
|
||||
}
|
||||
|
||||
KeEnterCriticalRegion();
|
||||
|
||||
// Wait for thread to exit
|
||||
Status = KeWaitForSingleObject(
|
||||
m_ThreadPtr,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL
|
||||
);
|
||||
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
UNREFERENCED_PARAMETER(Status);
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
|
||||
ObDereferenceObject(m_ThreadPtr);
|
||||
|
||||
RELEASE(FxSystemThread::StaticReaperThunk);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxSystemThread::StaticThreadThunk(
|
||||
__inout PVOID Context
|
||||
)
|
||||
{
|
||||
FxSystemThread* thread = (FxSystemThread*)Context;
|
||||
|
||||
thread->Thread();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
FxSystemThread::StaticReaperThunk(
|
||||
__inout PVOID Context
|
||||
)
|
||||
{
|
||||
FxSystemThread* thread = (FxSystemThread*)Context;
|
||||
|
||||
thread->Reaper();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,530 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
Tracing.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements tracing for the driver frameworks
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxcorepch.hpp"
|
||||
|
||||
// We use DoTraceMessage
|
||||
extern "C" {
|
||||
#include "tracing.tmh"
|
||||
}
|
||||
|
||||
#include <initguid.h>
|
||||
#include "fxIFR.h" // shared struct between IFR and debug ext.
|
||||
#include "fxIFRKm.h" // kernel mode only IFR definitions
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxTraceInitialize(
|
||||
VOID
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine initializes the frameworks tracing.
|
||||
|
||||
It must be called early on in the frameworks DriverEntry
|
||||
initialization.
|
||||
|
||||
Arguments:
|
||||
|
||||
None
|
||||
|
||||
Returns:
|
||||
|
||||
NTSTATUS code
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Initialize the tracing package: Vista or later
|
||||
//
|
||||
WPP_INIT_TRACING(NULL, NULL);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
TraceUninitialize(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
This routine uninitializes the frameworks tracing. It must be called just
|
||||
before DriverUnload
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Vista and later
|
||||
//
|
||||
WPP_CLEANUP(NULL);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiTraceMessage(
|
||||
__in TRACEHANDLE LoggerHandle,
|
||||
__in ULONG MessageFlags,
|
||||
__in LPGUID MessageGuid,
|
||||
__in USHORT MessageNumber,
|
||||
__in ...
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
va_list va;
|
||||
|
||||
va_start(va, MessageNumber);
|
||||
|
||||
#pragma prefast(suppress:__WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean");
|
||||
status = WmiTraceMessageVa(LoggerHandle,
|
||||
MessageFlags,
|
||||
MessageGuid,
|
||||
MessageNumber,
|
||||
va);
|
||||
va_end(va);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Subcomponents for the In-Flight Recorder follow.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ULONG
|
||||
FxIFRGetSize(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PCUNICODE_STRING RegistryPath
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Checks to see if the service has overriden the default number of pages that
|
||||
are in the IFR.
|
||||
|
||||
Arguments:
|
||||
RegistryPath - path to the service
|
||||
|
||||
Return Value:
|
||||
The size of the IFR to create in bytes (not pages!)
|
||||
|
||||
--*/
|
||||
{
|
||||
FxAutoRegKey service, parameters;
|
||||
NTSTATUS status;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
ULONG numPages;
|
||||
|
||||
//
|
||||
// This is the value used in case of any error while retrieving 'LogPages'
|
||||
// from the registry.
|
||||
//
|
||||
numPages = FxIFRMinLogPages;
|
||||
|
||||
//
|
||||
// External representation of the IFR is the "LogPages", so use that term when
|
||||
// overriding the size via the registry.
|
||||
//
|
||||
DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf");
|
||||
DECLARE_CONST_UNICODE_STRING(valueName, L"LogPages");
|
||||
|
||||
InitializeObjectAttributes(&oa,
|
||||
(PUNICODE_STRING)RegistryPath,
|
||||
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
status = ZwOpenKey(&service.m_Key, KEY_READ, &oa);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto defaultValues;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&oa,
|
||||
(PUNICODE_STRING)¶metersPath,
|
||||
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
||||
service.m_Key,
|
||||
NULL);
|
||||
|
||||
status = ZwOpenKey(¶meters.m_Key, KEY_READ, &oa);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto defaultValues;
|
||||
}
|
||||
|
||||
status = FxRegKey::_QueryULong(parameters.m_Key, &valueName, &numPages);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto defaultValues;
|
||||
}
|
||||
|
||||
if (numPages == 0) {
|
||||
numPages = FxIFRMinLogPages;
|
||||
}
|
||||
|
||||
defaultValues:
|
||||
//
|
||||
// Use FxIFRAvgLogPages if user specifies greater than FxIFRMaxLogPages and if
|
||||
// Verifier flag is on and so is Verbose flag.
|
||||
//
|
||||
if (numPages > FxIFRMaxLogPages) {
|
||||
if (FxDriverGlobals->FxVerifierOn && FxDriverGlobals->FxVerboseOn) {
|
||||
numPages = FxIFRAvgLogPages;
|
||||
}
|
||||
else {
|
||||
numPages = FxIFRMinLogPages;
|
||||
}
|
||||
}
|
||||
|
||||
return numPages * PAGE_SIZE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxIFRStart(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PCUNICODE_STRING RegistryPath,
|
||||
__in MdDriverObject DriverObject
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine initialize the In-Flight Recorder (IFR).
|
||||
|
||||
The default log size is set by WDF_IFR_LOG_SIZE and currently
|
||||
is 4096 (one x86 page).
|
||||
This routine should be called very early in driver initialization
|
||||
to allow the capture of all significant events.
|
||||
|
||||
--*/
|
||||
{
|
||||
PWDF_IFR_HEADER pHeader;
|
||||
ULONG size;
|
||||
|
||||
UNREFERENCED_PARAMETER( DriverObject );
|
||||
|
||||
WDFCASSERT(FxIFRRecordSignature == WDF_IFR_RECORD_SIGNATURE);
|
||||
|
||||
//
|
||||
// Return early if IFR is disabled.
|
||||
//
|
||||
if (FxLibraryGlobals.IfrDisabled) {
|
||||
ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (FxDriverGlobals == NULL || FxDriverGlobals->WdfLogHeader != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = FxIFRGetSize(FxDriverGlobals, RegistryPath);
|
||||
|
||||
pHeader = (PWDF_IFR_HEADER) ExAllocatePoolWithTag(NonPagedPool,
|
||||
size,
|
||||
WDF_IFR_LOG_TAG );
|
||||
if (pHeader == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
RtlZeroMemory(pHeader, size);
|
||||
|
||||
//
|
||||
// Initialize the header.
|
||||
// Base will be where the IFR records are placed.
|
||||
// WPP_ThisDir_CTLGUID_FrameworksTraceGuid
|
||||
//
|
||||
RtlCopyMemory(&pHeader->Guid, (PVOID) &WdfTraceGuid, sizeof(GUID));
|
||||
|
||||
pHeader->Base = (PUCHAR) &pHeader[1];
|
||||
pHeader->Size = size - sizeof(WDF_IFR_HEADER);
|
||||
|
||||
pHeader->Offset.u.s.Current = 0;
|
||||
pHeader->Offset.u.s.Previous = 0;
|
||||
RtlStringCchCopyA(pHeader->DriverName, WDF_IFR_HEADER_NAME_LEN, FxDriverGlobals->Public.DriverName);
|
||||
|
||||
FxDriverGlobals->WdfLogHeader = pHeader;
|
||||
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER,
|
||||
"FxIFR logging started" );
|
||||
|
||||
if (size > FxIFRMinLogSize) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER,
|
||||
"FxIFR has been started with a size override: size 0x%x bytes, "
|
||||
"# Pages %d. An extended IFR size may not be written to a minidump!",
|
||||
size, size/PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxIFRStop(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine stops the In-Flight Recorder (IFR).
|
||||
|
||||
It should be called as late in the driver teardown as possible
|
||||
to allow for the capture of all significant events.
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Return early if IFR is disabled.
|
||||
//
|
||||
if (FxLibraryGlobals.IfrDisabled) {
|
||||
ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (FxDriverGlobals == NULL || FxDriverGlobals->WdfLogHeader == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Free the Log buffer.
|
||||
//
|
||||
ExFreePoolWithTag( FxDriverGlobals->WdfLogHeader, WDF_IFR_LOG_TAG );
|
||||
FxDriverGlobals->WdfLogHeader = NULL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxIFR(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in UCHAR MessageLevel,
|
||||
__in ULONG MessageFlags,
|
||||
__in LPGUID MessageGuid,
|
||||
__in USHORT MessageNumber,
|
||||
__in ...
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is the main In-Flight Recorder (IFR) routine.
|
||||
|
||||
It captures a WPP message to the IFR log.
|
||||
The IFR is always running, e.g. not WPP logger is necessary
|
||||
to start logging.
|
||||
|
||||
Arguments:
|
||||
|
||||
MessageLevel - The WPP message level for this event
|
||||
MessageFlags - The WPP message flags for this event (see trace GUID)
|
||||
MessageGuid - The tracewpp generated guid for module emitting this event.
|
||||
MessageNumber - The tracewpp generated message number within
|
||||
the emitting module.
|
||||
... - Variable arguments associates with the emitted message.
|
||||
|
||||
Returns:
|
||||
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
size_t size;
|
||||
PWDF_IFR_RECORD record;
|
||||
PWDF_IFR_HEADER header;
|
||||
|
||||
UNREFERENCED_PARAMETER( MessageLevel );
|
||||
UNREFERENCED_PARAMETER( MessageFlags );
|
||||
|
||||
//
|
||||
// Return early if IFR is disabled.
|
||||
//
|
||||
if (FxLibraryGlobals.IfrDisabled) {
|
||||
ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if ( FxDriverGlobals->WdfLogHeader == NULL) {
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine the number bytes to follow header
|
||||
//
|
||||
size = 0; // For Count of Bytes
|
||||
|
||||
//
|
||||
// Determine how much log space is needed for this
|
||||
// trace record's data.
|
||||
//
|
||||
{
|
||||
va_list ap;
|
||||
size_t argLen;
|
||||
|
||||
va_start(ap, MessageNumber);
|
||||
#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean");
|
||||
while ((va_arg(ap, PVOID)) != NULL) {
|
||||
|
||||
argLen = va_arg(ap, size_t);
|
||||
|
||||
if (argLen > 0) {
|
||||
|
||||
if (argLen > FxIFRMaxMessageSize) {
|
||||
goto drop_message;
|
||||
}
|
||||
size += (USHORT) argLen;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
//
|
||||
// NOTE: The final size must be 32-bit (ULONG) aligned.
|
||||
// This is necessary for IA64 to prevent Alignment Faults.
|
||||
//
|
||||
size += (size % sizeof(ULONG)) ? sizeof(ULONG) - (size % sizeof(ULONG)) : 0;
|
||||
|
||||
if (size > FxIFRMaxMessageSize) {
|
||||
goto drop_message;
|
||||
}
|
||||
}
|
||||
|
||||
size += sizeof(WDF_IFR_RECORD);
|
||||
|
||||
//
|
||||
// Allocate log space of the calculated size
|
||||
//
|
||||
{
|
||||
WDF_IFR_OFFSET offsetRet;
|
||||
WDF_IFR_OFFSET offsetCur;
|
||||
WDF_IFR_OFFSET offsetNew;
|
||||
USHORT usSize = (USHORT) size; // for a prefast artifact.
|
||||
|
||||
header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader;
|
||||
|
||||
FxVerifyLogHeader(FxDriverGlobals, header);
|
||||
|
||||
offsetRet.u.AsLONG = header->Offset.u.AsLONG;
|
||||
offsetNew.u.AsLONG = offsetRet.u.s.Current;
|
||||
|
||||
do {
|
||||
offsetCur.u.AsLONG = offsetRet.u.AsLONG;
|
||||
|
||||
if (&header->Base[header->Size] < &header->Base[offsetCur.u.s.Current+size]) {
|
||||
|
||||
offsetNew.u.s.Current = 0;
|
||||
offsetNew.u.s.Previous = offsetRet.u.s.Previous;
|
||||
|
||||
offsetRet.u.AsLONG =
|
||||
InterlockedCompareExchange( &header->Offset.u.AsLONG,
|
||||
offsetNew.u.AsLONG,
|
||||
offsetCur.u.AsLONG );
|
||||
|
||||
if (offsetCur.u.AsLONG != offsetRet.u.AsLONG) {
|
||||
continue;
|
||||
} else {
|
||||
offsetNew.u.s.Current = offsetCur.u.s.Current + usSize;
|
||||
offsetNew.u.s.Previous = offsetRet.u.s.Current;
|
||||
}
|
||||
} else {
|
||||
|
||||
offsetNew.u.s.Current = offsetCur.u.s.Current + usSize;
|
||||
offsetNew.u.s.Previous = offsetCur.u.s.Current;
|
||||
}
|
||||
|
||||
offsetRet.u.AsLONG =
|
||||
InterlockedCompareExchange( &header->Offset.u.AsLONG,
|
||||
offsetNew.u.AsLONG,
|
||||
offsetCur.u.AsLONG );
|
||||
|
||||
} while (offsetCur.u.AsLONG != offsetRet.u.AsLONG);
|
||||
|
||||
record = (PWDF_IFR_RECORD) &header->Base[offsetRet.u.s.Current];
|
||||
|
||||
// RtlZeroMemory( record, sizeof(WDF_IFR_RECORD) );
|
||||
|
||||
//
|
||||
// Build record (fill all fields!)
|
||||
//
|
||||
record->Signature = FxIFRRecordSignature;
|
||||
record->Length = (USHORT) size;
|
||||
record->PrevOffset = (USHORT) offsetRet.u.s.Previous;
|
||||
record->MessageNumber = MessageNumber;
|
||||
record->Sequence = InterlockedIncrement( &header->Sequence );
|
||||
record->MessageGuid = *MessageGuid;
|
||||
}
|
||||
|
||||
//
|
||||
// Move variable part of data into log.
|
||||
//
|
||||
{
|
||||
va_list ap;
|
||||
size_t argLen;
|
||||
PVOID source;
|
||||
PUCHAR argsData;
|
||||
|
||||
argsData = (UCHAR*) &record[1];
|
||||
|
||||
va_start(ap, MessageNumber);
|
||||
|
||||
while ((source = va_arg(ap, PVOID)) != NULL) {
|
||||
|
||||
argLen = va_arg(ap, size_t);
|
||||
|
||||
if (argLen > 0) {
|
||||
|
||||
RtlCopyMemory( argsData, source, argLen );
|
||||
argsData += argLen;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
FxVerifyLogHeader(FxDriverGlobals, header);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
{
|
||||
//
|
||||
// Increment sequence number to indicate dropped message
|
||||
//
|
||||
drop_message:
|
||||
header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader;
|
||||
InterlockedIncrement( &header->Sequence );
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxCommonBuffer.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
WDF CommonBuffer Object
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only.
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxDmaPCH.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxCommonBuffer.tmh"
|
||||
}
|
||||
|
||||
FxCommonBuffer::FxCommonBuffer(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in FxDmaEnabler * pDmaEnabler
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_COMMON_BUFFER, sizeof(FxCommonBuffer), FxDriverGlobals)
|
||||
{
|
||||
m_DmaEnabler = pDmaEnabler;
|
||||
m_BufferRawVA = NULL; // allocated buffer base (unaligned)
|
||||
m_BufferAlignedVA = NULL; // aligned buffer base
|
||||
m_BufferAlignedLA.QuadPart = NULL; // aligned physical buffer base
|
||||
m_BufferRawLA.QuadPart = NULL; // allocated buffer phy base (unaligned)
|
||||
m_Length = 0;
|
||||
m_RawLength = 0;
|
||||
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
|
||||
//
|
||||
// By default use the alignment of the dma enabler.
|
||||
//
|
||||
m_Alignment = m_DmaEnabler->GetAlignment();
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxCommonBuffer::Dispose()
|
||||
{
|
||||
FreeCommonBuffer();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxCommonBuffer::AllocateCommonBuffer(
|
||||
__in size_t Length
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals();
|
||||
ULONGLONG offset;
|
||||
ULONG result;
|
||||
|
||||
//
|
||||
// Must be running at PASIVE_LEVEL
|
||||
//
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
m_Length = Length;
|
||||
|
||||
//
|
||||
// If required, add alignment to the length.
|
||||
// If alignment is <= page-1, we actually don't need to do it b/c
|
||||
// AllocateCommonBuffer allocates at least a page of memory, regardless
|
||||
// of the requested Length. If driver version is < v1.11, we still add the
|
||||
// alignment to the length for compatibility.
|
||||
//
|
||||
if (m_Alignment > PAGE_SIZE-1 ||
|
||||
pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) {
|
||||
|
||||
status = RtlSizeTAdd(Length, m_Alignment, &m_RawLength);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"WDFDMAENABLER %p AllocateCommonBuffer: overflow when adding Length "
|
||||
"%I64d + Alignment %I64d", GetObjectHandle(), Length, m_Alignment);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_RawLength = Length;
|
||||
}
|
||||
|
||||
m_DmaEnabler->AllocateCommonBuffer(m_RawLength,
|
||||
&m_BufferRawVA,
|
||||
&m_BufferRawLA);
|
||||
if (m_BufferRawVA) {
|
||||
|
||||
m_BufferAlignedVA = FX_ALIGN_VIRTUAL_ADDRESS(m_BufferRawVA, m_Alignment);
|
||||
m_BufferAlignedLA.QuadPart = FX_ALIGN_LOGICAL_ADDRESS(m_BufferRawLA, m_Alignment);
|
||||
|
||||
if (m_Alignment > PAGE_SIZE-1) {
|
||||
//
|
||||
// If the alignment mask is over a page-size then the aligned virtual
|
||||
// and aligned logical could be pointing to different locations
|
||||
// in memory. So ajdust the VA to match the LA address by adding
|
||||
// the offset of alignedLA and RawLA to VA. By doing this we
|
||||
// only guarantee alignment of LA when the page alignment exceeds PAGE_SIZE.
|
||||
//
|
||||
status = RtlULongLongSub(m_BufferAlignedLA.QuadPart,
|
||||
m_BufferRawLA.QuadPart,
|
||||
&offset);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"WDFDMAENABLER %p AllocateCommonBuffer: overflow when subtracting "
|
||||
"RawLA %I64x from AlignedLA %I64x",
|
||||
GetObjectHandle(), m_BufferRawLA.QuadPart, m_BufferAlignedLA.QuadPart);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = RtlULongLongToULong(offset, &result);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"WDFDMAENABLER %p AllocateCommonBuffer: overflow when "
|
||||
"converting from ULongLong %I64d to ULong",
|
||||
GetObjectHandle(), offset);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return status;
|
||||
}
|
||||
|
||||
m_BufferAlignedVA = WDF_PTR_ADD_OFFSET(m_BufferRawVA, result);
|
||||
}
|
||||
else {
|
||||
ASSERT(m_BufferAlignedVA == m_BufferRawVA);
|
||||
ASSERT(m_BufferAlignedLA.QuadPart == m_BufferRawLA.QuadPart);
|
||||
}
|
||||
} else {
|
||||
m_Length = 0;
|
||||
m_RawLength = 0;
|
||||
m_BufferAlignedVA = NULL;
|
||||
m_BufferAlignedLA.QuadPart = NULL;
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxCommonBuffer::FreeCommonBuffer(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Free this CommonBuffer per DmaEnabler
|
||||
//
|
||||
if (m_BufferRawVA != NULL) {
|
||||
m_DmaEnabler->FreeCommonBuffer((ULONG) m_RawLength,
|
||||
m_BufferRawVA,
|
||||
m_BufferRawLA);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxCommonBufferAPI.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Base for WDF CommonBuffer APIs
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only.
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxDmaPCH.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxCommonBufferAPI.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfCommonBufferCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDMAENABLER DmaEnabler,
|
||||
__in
|
||||
__drv_when(Length == 0, __drv_reportError(Length cannot be zero))
|
||||
size_t Length,
|
||||
__in_opt
|
||||
WDF_OBJECT_ATTRIBUTES * Attributes,
|
||||
__out
|
||||
WDFCOMMONBUFFER * CommonBufferHandle
|
||||
)
|
||||
{
|
||||
FxCommonBuffer * pComBuf;
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
NTSTATUS status;
|
||||
WDFOBJECT handle;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
//
|
||||
// Get validate DmaEnabler handle
|
||||
//
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DmaEnabler,
|
||||
FX_TYPE_DMA_ENABLER,
|
||||
(PVOID *) &pDmaEnabler,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, CommonBufferHandle);
|
||||
|
||||
*CommonBufferHandle = NULL;
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Basic parameter validation
|
||||
//
|
||||
if (Length == 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Length is 0, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals,
|
||||
Attributes,
|
||||
FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a new CommonBuffer object
|
||||
//
|
||||
pComBuf = new(pFxDriverGlobals, Attributes)
|
||||
FxCommonBuffer(pFxDriverGlobals, pDmaEnabler);
|
||||
|
||||
if (pComBuf == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Could not allocate memory for a WDFCOMMONBUFFER, "
|
||||
"%!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Assign this FxCommonBuffer to its parent FxDmaEnabler object.
|
||||
//
|
||||
status = pComBuf->Commit(Attributes, (WDFOBJECT*)&handle, pDmaEnabler);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Ok: now allocate a CommonBuffer via this DmaEnabler
|
||||
//
|
||||
status = pComBuf->AllocateCommonBuffer( Length );
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Only return a valid handle on success.
|
||||
//
|
||||
*CommonBufferHandle = (WDFCOMMONBUFFER) handle;
|
||||
}
|
||||
else {
|
||||
pComBuf->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfCommonBufferCreateWithConfig)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDMAENABLER DmaEnabler,
|
||||
__in
|
||||
__drv_when(Length == 0, __drv_reportError(Length cannot be zero))
|
||||
size_t Length,
|
||||
__in
|
||||
PWDF_COMMON_BUFFER_CONFIG Config,
|
||||
__in_opt
|
||||
WDF_OBJECT_ATTRIBUTES * Attributes,
|
||||
__out
|
||||
WDFCOMMONBUFFER * CommonBufferHandle
|
||||
)
|
||||
{
|
||||
FxCommonBuffer * pComBuf;
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
NTSTATUS status;
|
||||
WDFOBJECT handle;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
//
|
||||
// Get validate DmaEnabler handle
|
||||
//
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DmaEnabler,
|
||||
FX_TYPE_DMA_ENABLER,
|
||||
(PVOID *) &pDmaEnabler,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// Basic parameter validation
|
||||
//
|
||||
FxPointerNotNull(pFxDriverGlobals, Config);
|
||||
|
||||
if (Config->Size != sizeof(WDF_COMMON_BUFFER_CONFIG)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"WDF_COMMON_BUFFER_CONFIG Size 0x%x, expected 0x%x, %!STATUS!",
|
||||
Config->Size, sizeof(WDF_COMMON_BUFFER_CONFIG), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, CommonBufferHandle);
|
||||
|
||||
*CommonBufferHandle = NULL;
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Length == 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Length is 0, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals,
|
||||
Attributes,
|
||||
FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
pComBuf = new(pFxDriverGlobals, Attributes)
|
||||
FxCommonBuffer(pFxDriverGlobals, pDmaEnabler);
|
||||
|
||||
if (pComBuf == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Could not allocate memory for a WDFCOMMONBUFFER, "
|
||||
"%!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Assign this FxCommonBuffer to its parent FxDmaEnabler object.
|
||||
//
|
||||
status = pComBuf->Commit(Attributes, (WDFOBJECT*)&handle, pDmaEnabler);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Set the alignment value before calling AllocateCommonBuffer.
|
||||
//
|
||||
pComBuf->SetAlignment(Config->AlignmentRequirement);
|
||||
status = pComBuf->AllocateCommonBuffer( Length );
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Only return a valid handle on success.
|
||||
//
|
||||
*CommonBufferHandle = (WDFCOMMONBUFFER) handle;
|
||||
}
|
||||
else {
|
||||
pComBuf->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PVOID
|
||||
WDFEXPORT(WdfCommonBufferGetAlignedVirtualAddress)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOMMONBUFFER CommonBuffer
|
||||
)
|
||||
{
|
||||
FxCommonBuffer * pComBuf;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
CommonBuffer,
|
||||
FX_TYPE_COMMON_BUFFER,
|
||||
(PVOID *) &pComBuf);
|
||||
|
||||
return pComBuf->GetAlignedVirtualAddress();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PHYSICAL_ADDRESS
|
||||
WDFEXPORT(WdfCommonBufferGetAlignedLogicalAddress)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOMMONBUFFER CommonBuffer
|
||||
)
|
||||
{
|
||||
FxCommonBuffer * pComBuf;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
CommonBuffer,
|
||||
FX_TYPE_COMMON_BUFFER,
|
||||
(PVOID *) &pComBuf);
|
||||
|
||||
return pComBuf->GetAlignedLogicalAddress();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
size_t
|
||||
WDFEXPORT(WdfCommonBufferGetLength)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOMMONBUFFER CommonBuffer
|
||||
)
|
||||
{
|
||||
FxCommonBuffer * pComBuf;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
CommonBuffer,
|
||||
FX_TYPE_COMMON_BUFFER,
|
||||
(PVOID *) &pComBuf);
|
||||
|
||||
return pComBuf->GetLength();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,516 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDmaEnablerAPI.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Base for WDF DMA Enabler object APIs
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only.
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxDmaPCH.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDmaEnablerAPI.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDmaEnablerCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
WDF_DMA_ENABLER_CONFIG * Config,
|
||||
__in_opt
|
||||
WDF_OBJECT_ATTRIBUTES * Attributes,
|
||||
__out
|
||||
WDFDMAENABLER * DmaEnablerHandle
|
||||
)
|
||||
{
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
FxDeviceBase * pDevice;
|
||||
NTSTATUS status;
|
||||
WDFDMAENABLER handle;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxObject * pParent;
|
||||
WDF_DMA_ENABLER_CONFIG dmaConfig;
|
||||
|
||||
//
|
||||
// Validate the Device handle
|
||||
//
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE_BASE,
|
||||
(PVOID *) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, DmaEnablerHandle);
|
||||
FxPointerNotNull(pFxDriverGlobals, Config);
|
||||
|
||||
*DmaEnablerHandle = NULL;
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Attributes != NULL && Attributes->ParentObject != NULL) {
|
||||
FxObjectHandleGetPtr(pFxDriverGlobals,
|
||||
Attributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent);
|
||||
|
||||
if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
|
||||
FxDeviceBase * pSearchDevice;
|
||||
|
||||
//
|
||||
// If a parent object is passed-in it must be descendent of device.
|
||||
// DmaEnabler stores device and uses it during dispose
|
||||
// (to remove it from dmaenabler list maintained at device level),
|
||||
// so DmaEnabler cannot outlive device.
|
||||
//
|
||||
|
||||
pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL);
|
||||
|
||||
if (pSearchDevice == NULL) {
|
||||
status = STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Attributes->ParentObject 0x%p must have WDFDEVICE as an "
|
||||
"eventual ancestor, %!STATUS!",
|
||||
Attributes->ParentObject, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
else if (pSearchDevice != pDevice) {
|
||||
status = STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but "
|
||||
"not the same WDFDEVICE 0x%p passed to WdfDmaEnablerCreate, "
|
||||
"%!STATUS!",
|
||||
Attributes->ParentObject, pSearchDevice->GetHandle(),
|
||||
Device, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// For < 1.11 drivers we only allow pDevice to be the parent
|
||||
// since that is what we were blindly setting the parent to.
|
||||
//
|
||||
// Using the passed-in parent for such drivers could cause
|
||||
// side-effects such as earlier deletion of DmaEnabler object. So
|
||||
// we don't do that.
|
||||
//
|
||||
// We cause this verifier breakpoint to warn downlevel drivers
|
||||
// that the parent they passed in gets ignored.
|
||||
//
|
||||
if (pParent != pDevice) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDMA,
|
||||
"For drivers bound to version <= 1.9 "
|
||||
"WdfDmaEnablerCreate uses WDFDEVICE as the "
|
||||
"parent object for the dma enabler object. "
|
||||
"Attributes->ParentObject 0x%p, which is different from "
|
||||
"WDFDEVICE 0x%p, gets ignored. Please note that DmaEnabler "
|
||||
"would be disposed only when device is disposed.",
|
||||
Attributes->ParentObject, Device);
|
||||
|
||||
if (pFxDriverGlobals->IsDownlevelVerificationEnabled()) {
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
}
|
||||
|
||||
pParent = pDevice;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pParent = pDevice;
|
||||
}
|
||||
|
||||
{
|
||||
ULONG expectedSize = pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) ?
|
||||
sizeof(WDF_DMA_ENABLER_CONFIG) :
|
||||
sizeof(WDF_DMA_ENABLER_CONFIG_V1_9);
|
||||
|
||||
if (Config->Size != expectedSize) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"WDF_DMA_ENABLER_CONFIG Size 0x%x, expected 0x%x, %!STATUS!",
|
||||
Config->Size, expectedSize, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Normalize DMA config structure if necessary.
|
||||
//
|
||||
if (Config->Size < sizeof(WDF_DMA_ENABLER_CONFIG)) {
|
||||
//
|
||||
// Init new fields to default values.
|
||||
//
|
||||
WDF_DMA_ENABLER_CONFIG_INIT(&dmaConfig,
|
||||
Config->Profile,
|
||||
Config->MaximumLength);
|
||||
//
|
||||
// Copy over existing fields and readjust the struct size.
|
||||
//
|
||||
RtlCopyMemory(&dmaConfig, Config, Config->Size);
|
||||
dmaConfig.Size = sizeof(dmaConfig);
|
||||
|
||||
//
|
||||
// Use new config structure from now on.
|
||||
//
|
||||
Config = &dmaConfig;
|
||||
}
|
||||
}
|
||||
|
||||
switch (Config->Profile) {
|
||||
case WdfDmaProfilePacket:
|
||||
case WdfDmaProfileScatterGather:
|
||||
case WdfDmaProfilePacket64:
|
||||
case WdfDmaProfileScatterGather64:
|
||||
case WdfDmaProfileScatterGather64Duplex:
|
||||
case WdfDmaProfileScatterGatherDuplex:
|
||||
case WdfDmaProfileSystem:
|
||||
case WdfDmaProfileSystemDuplex:
|
||||
break;
|
||||
default:
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"DMA Profile value %d is unknown, %!STATUS!",
|
||||
Config->Profile, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Config->MaximumLength == 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Config MaximumLength of zero is invalid, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Ok: create a new DmaEnabler
|
||||
//
|
||||
pDmaEnabler = new(pFxDriverGlobals, Attributes)
|
||||
FxDmaEnabler( pFxDriverGlobals );
|
||||
|
||||
if (pDmaEnabler == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Could not allocate memory for a WDFDMAENABLER, "
|
||||
"%!STATUS!", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Assign this FxDmaEnabler to its parent FxDevice object.
|
||||
//
|
||||
status = pDmaEnabler->Commit(Attributes, (WDFOBJECT*)&handle, pParent);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Ok: start this DmaEnabler.
|
||||
//
|
||||
status = pDmaEnabler->Initialize( Config, pDevice );
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Only return a valid handle on success.
|
||||
//
|
||||
*DmaEnablerHandle = handle;
|
||||
}
|
||||
else {
|
||||
pDmaEnabler->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
size_t
|
||||
WDFEXPORT(WdfDmaEnablerGetMaximumLength)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDMAENABLER DmaEnabler
|
||||
)
|
||||
{
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
DmaEnabler,
|
||||
FX_TYPE_DMA_ENABLER,
|
||||
(PVOID *) &pDmaEnabler);
|
||||
|
||||
return pDmaEnabler->GetMaximumLength();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
size_t
|
||||
WDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDMAENABLER DmaEnabler
|
||||
)
|
||||
{
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
DmaEnabler,
|
||||
FX_TYPE_DMA_ENABLER,
|
||||
(PVOID *) &pDmaEnabler);
|
||||
|
||||
return pDmaEnabler->GetMaxSGElements();
|
||||
}
|
||||
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDMAENABLER DmaEnabler,
|
||||
__in
|
||||
__drv_when(MaximumElements == 0, __drv_reportError(MaximumElements cannot be zero))
|
||||
size_t MaximumElements
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DmaEnabler,
|
||||
FX_TYPE_DMA_ENABLER,
|
||||
(PVOID *) &pDmaEnabler,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MaximumElements == 0) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Cannot set MaximumElements of zero on WDFDMAENABLER %p",
|
||||
DmaEnabler);
|
||||
return;
|
||||
}
|
||||
|
||||
pDmaEnabler->SetMaxSGElements(MaximumElements);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
size_t
|
||||
WDFEXPORT(WdfDmaEnablerGetFragmentLength)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDMAENABLER DmaEnabler,
|
||||
__in
|
||||
WDF_DMA_DIRECTION DmaDirection
|
||||
)
|
||||
{
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
size_t length;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DmaEnabler,
|
||||
FX_TYPE_DMA_ENABLER,
|
||||
(PVOID *) &pDmaEnabler,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
switch (DmaDirection) {
|
||||
|
||||
case WdfDmaDirectionReadFromDevice:
|
||||
length = pDmaEnabler->GetReadDmaDescription()->MaximumFragmentLength;
|
||||
break;
|
||||
|
||||
case WdfDmaDirectionWriteToDevice:
|
||||
length = pDmaEnabler->GetWriteDmaDescription()->MaximumFragmentLength;
|
||||
break;
|
||||
|
||||
default:
|
||||
length = 0;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Invalid value for Dma direction %d, %p",
|
||||
DmaDirection, DmaEnabler);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PDMA_ADAPTER
|
||||
WDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDMAENABLER DmaEnabler,
|
||||
__in
|
||||
WDF_DMA_DIRECTION DmaDirection
|
||||
)
|
||||
{
|
||||
PDMA_ADAPTER adapter;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DmaEnabler,
|
||||
FX_TYPE_DMA_ENABLER,
|
||||
(PVOID *) &pDmaEnabler,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
switch (DmaDirection) {
|
||||
|
||||
case WdfDmaDirectionReadFromDevice:
|
||||
adapter = pDmaEnabler->GetReadDmaDescription()->AdapterObject;
|
||||
break;
|
||||
|
||||
case WdfDmaDirectionWriteToDevice:
|
||||
adapter = pDmaEnabler->GetWriteDmaDescription()->AdapterObject;
|
||||
break;
|
||||
|
||||
default:
|
||||
adapter = NULL;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"Invalid value for Dma direction %d, %p",
|
||||
DmaDirection, DmaEnabler);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
break;
|
||||
}
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDmaEnablerConfigureSystemProfile)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDMAENABLER DmaEnabler,
|
||||
__in
|
||||
PWDF_DMA_SYSTEM_PROFILE_CONFIG ProfileConfig,
|
||||
__in
|
||||
WDF_DMA_DIRECTION ConfigDirection
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDmaEnabler * pDmaEnabler;
|
||||
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
DmaEnabler,
|
||||
FX_TYPE_DMA_ENABLER,
|
||||
(PVOID *) &pDmaEnabler,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// Verify the DMA config
|
||||
//
|
||||
|
||||
if (ProfileConfig == NULL)
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"ProfileConfig must be non-null, %!STATUS!",
|
||||
status);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (ProfileConfig->Size != sizeof(WDF_DMA_SYSTEM_PROFILE_CONFIG))
|
||||
{
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"WDF_DMA_SYSTEM_PROFILE_CONFIG Size 0x%x, expected 0x%x, %!STATUS!",
|
||||
ProfileConfig->Size, sizeof(WDF_DMA_SYSTEM_PROFILE_CONFIG), status);
|
||||
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (ProfileConfig->DmaDescriptor == NULL)
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"ProfileConfig (%p) may not have NULL DmaDescriptor, %!STATUS!",
|
||||
ProfileConfig, status);
|
||||
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (ConfigDirection != WdfDmaDirectionReadFromDevice &&
|
||||
ConfigDirection != WdfDmaDirectionWriteToDevice) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
|
||||
"ConfigDirection 0x%x is an invalid value, %!STATUS!",
|
||||
ConfigDirection, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pDmaEnabler->ConfigureSystemAdapter(ProfileConfig,
|
||||
ConfigDirection);
|
||||
return status;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,7 @@
|
||||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
//
|
||||
extern "C" {
|
||||
#include <ntddk.h>
|
||||
}
|
||||
#include <Fx.hpp>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,760 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
Version.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module forms a loadable library from the WDF core libs
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ntverp.h>
|
||||
|
||||
extern "C" {
|
||||
#include <ntddk.h>
|
||||
#include <ntstrsafe.h>
|
||||
}
|
||||
|
||||
#define FX_DYNAMICS_GENERATE_TABLE 1
|
||||
|
||||
#include "fx.hpp"
|
||||
|
||||
#include <fxldr.h>
|
||||
#include "fxbugcheck.h"
|
||||
#include "wdfversionlog.h"
|
||||
|
||||
#define DRIVER_OBJECT_EXTENSION_IDENTIFIER DriverEntry
|
||||
#define DRIVER_PARAMETERS L"Parameters"
|
||||
#define REGISTRY_KMDF_MAJOR_VERSION L"MajorVersion"
|
||||
#define REGISTRY_KMDF_MINOR_VERSION L"MinorVersion"
|
||||
#define REGISTRY_KMDF_BUILD_NUMBER L"BuildNumber"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// These header files are referenced in order to make internal structures
|
||||
// available in public symbols. Various WDFKD debug commands use these
|
||||
// internal structures to provide information about WDF.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "FxIFR.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
//
|
||||
// This is the collection of all structure/types to be make public.
|
||||
// This union forces the structure type-info into the PDB file.
|
||||
//
|
||||
union {
|
||||
|
||||
WDF_IFR_HEADER * typeWDF_IFR_HEADER;
|
||||
WDF_IFR_RECORD * typeWDF_IFR_RECORD;
|
||||
WDF_IFR_OFFSET * typeWDF_IFR_OFFSET;
|
||||
WDF_BIND_INFO * typeWDF_BIND_INFO;
|
||||
WDF_OBJECT_CONTEXT_TYPE_INFO * typeWDF_OBJECT_CONTEXT_TYPE_INFO;
|
||||
WDF_POWER_ROUTINE_TIMED_OUT_DATA * typeWDF_POWER_ROUTINE_TIMED_OUT_DATA;
|
||||
WDF_BUGCHECK_CODES * typeWDF_BUGCHECK_CODES;
|
||||
WDF_REQUEST_FATAL_ERROR_CODES * typeWDF_REQUEST_FATAL_ERROR_CODES;
|
||||
FX_OBJECT_INFO * typeFX_OBJECT_INFO;
|
||||
FX_POOL_HEADER * typeFX_POOL_HEADER;
|
||||
FX_POOL * typeFX_POOL;
|
||||
FxObject * typeFxObject;
|
||||
FxContextHeader * typeFxContextHeader;
|
||||
FX_DUMP_DRIVER_INFO_ENTRY * typeFX_DUMP_DRIVER_INFO_ENTRY;
|
||||
FxTargetSubmitSyncParams * typeFxTargetSubmitSyncParams;
|
||||
|
||||
} uAllPublicTypes;
|
||||
|
||||
} // extern "C" end
|
||||
|
||||
//----------------------------------------- ------------------------------------
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include "FxDynamics.h"
|
||||
|
||||
#include "FxLibraryCommon.h"
|
||||
|
||||
#define KMDF_DEFAULT_NAME "Wdf" ## \
|
||||
LITERAL(__WDF_MAJOR_VERSION_STRING) ## \
|
||||
"000" //minor version
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// local prototype definitions
|
||||
//-----------------------------------------------------------------------------
|
||||
extern "C"
|
||||
DRIVER_UNLOAD DriverUnload;
|
||||
|
||||
extern "C"
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
|
||||
extern "C"
|
||||
__drv_dispatchType(IRP_MJ_CREATE)
|
||||
__drv_dispatchType(IRP_MJ_CLEANUP)
|
||||
__drv_dispatchType(IRP_MJ_CLOSE)
|
||||
DRIVER_DISPATCH FxLibraryDispatch;
|
||||
|
||||
RTL_OSVERSIONINFOW gOsVersion = { sizeof(RTL_OSVERSIONINFOW) };
|
||||
|
||||
ULONG WdfLdrDbgPrintOn = 0;
|
||||
|
||||
PCHAR WdfLdrType = KMDF_DEFAULT_NAME;
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
extern "C"
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDF_LIBRARY_COMMISSION(
|
||||
VOID
|
||||
);
|
||||
|
||||
extern "C"
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDF_LIBRARY_DECOMMISSION(
|
||||
VOID
|
||||
);
|
||||
|
||||
extern "C"
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDF_LIBRARY_REGISTER_CLIENT(
|
||||
__inout PWDF_BIND_INFO Info,
|
||||
__deref_out PWDF_DRIVER_GLOBALS * WdfDriverGlobals,
|
||||
__deref_inout PVOID * Context
|
||||
);
|
||||
|
||||
extern "C"
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDF_LIBRARY_UNREGISTER_CLIENT(
|
||||
__in PWDF_BIND_INFO Info,
|
||||
__in PWDF_DRIVER_GLOBALS WdfDriverGlobals
|
||||
);
|
||||
|
||||
extern "C"
|
||||
VOID
|
||||
FxLibraryDeleteDevice(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
FxLibraryCleanup(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
WdfWriteKmdfVersionToRegistry(
|
||||
__in PDRIVER_OBJECT DriverObject,
|
||||
__in PUNICODE_STRING RegistryPath
|
||||
);
|
||||
|
||||
VOID
|
||||
WdfDeleteKmdfVersionFromRegistry(
|
||||
__in PDRIVER_OBJECT DriverObject
|
||||
);
|
||||
|
||||
typedef struct _DRV_EXTENSION {
|
||||
UNICODE_STRING ParametersRegistryPath;
|
||||
} DRV_EXTENSION, *PDRV_EXTENSION;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Library registeration information
|
||||
//-----------------------------------------------------------------------------
|
||||
extern "C" {
|
||||
#pragma prefast(suppress:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "kernel component.");
|
||||
WDF_LIBRARY_INFO WdfLibraryInfo = {
|
||||
sizeof(WDF_LIBRARY_INFO),
|
||||
(PFNLIBRARYCOMMISSION) WDF_LIBRARY_COMMISSION,
|
||||
(PFNLIBRARYDECOMMISSION) WDF_LIBRARY_DECOMMISSION,
|
||||
(PFNLIBRARYREGISTERCLIENT) WDF_LIBRARY_REGISTER_CLIENT,
|
||||
(PFNLIBRARYUNREGISTERCLIENT) WDF_LIBRARY_UNREGISTER_CLIENT,
|
||||
{ __WDF_MAJOR_VERSION, __WDF_MINOR_VERSION, __WDF_BUILD_NUMBER }
|
||||
};
|
||||
|
||||
} // extern "C" end
|
||||
|
||||
extern "C"
|
||||
NTSTATUS
|
||||
FxLibraryDispatch (
|
||||
__in struct _DEVICE_OBJECT * DeviceObject,
|
||||
__in PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
ASSERT(FxLibraryGlobals.LibraryDeviceObject == DeviceObject);
|
||||
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction) {
|
||||
case IRP_MJ_CREATE:
|
||||
//
|
||||
// To limit our exposure for this device object, only allow kernel mode
|
||||
// creates.
|
||||
//
|
||||
if (Irp->RequestorMode == KernelMode) {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case IRP_MJ_CLEANUP:
|
||||
case IRP_MJ_CLOSE:
|
||||
//
|
||||
// Since we allowed a create to succeed, succeed the cleanup and close
|
||||
//
|
||||
status = STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = status;
|
||||
Irp->IoStatus.Information = 0x0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define KMDF_DEVICE_NAME L"\\Device\\KMDF"
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCreateDevice(
|
||||
__in PUNICODE_STRING DeviceName
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG i;
|
||||
|
||||
i = 0;
|
||||
|
||||
//
|
||||
// Repeatedly try to create a named device object until we run out of buffer
|
||||
// space or we succeed.
|
||||
//
|
||||
do {
|
||||
status = RtlUnicodeStringPrintf(DeviceName, L"%s%d", KMDF_DEVICE_NAME, i++);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a device with no device extension
|
||||
//
|
||||
status = IoCreateDevice(
|
||||
FxLibraryGlobals.DriverObject,
|
||||
0,
|
||||
DeviceName,
|
||||
FILE_DEVICE_UNKNOWN,
|
||||
0,
|
||||
FALSE,
|
||||
&FxLibraryGlobals.LibraryDeviceObject
|
||||
);
|
||||
} while (STATUS_OBJECT_NAME_COLLISION == status);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Clear the initializing bit now because the loader will attempt to
|
||||
// open the device before we return from DriverEntry
|
||||
//
|
||||
ASSERT(FxLibraryGlobals.LibraryDeviceObject != NULL);
|
||||
FxLibraryGlobals.LibraryDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
VOID
|
||||
FxLibraryDeleteDevice(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
FxLibraryCleanup();
|
||||
}
|
||||
|
||||
VOID
|
||||
FxLibraryCleanup(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (FxLibraryGlobals.LibraryDeviceObject != NULL) {
|
||||
IoDeleteDevice(FxLibraryGlobals.LibraryDeviceObject);
|
||||
FxLibraryGlobals.LibraryDeviceObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
NTSTATUS
|
||||
DriverEntry(
|
||||
__in PDRIVER_OBJECT DriverObject,
|
||||
__in PUNICODE_STRING RegistryPath
|
||||
)
|
||||
{
|
||||
UNICODE_STRING name;
|
||||
UNICODE_STRING string;
|
||||
NTSTATUS status;
|
||||
|
||||
//
|
||||
// This creates a local buffer which is big enough to hold a copy of the
|
||||
// constant string assigned to it. It does not point to the constant
|
||||
// string. As such, it is a writeable buffer.
|
||||
//
|
||||
// NOTE: KMDF_DEVICE_NAME L"XXXX" creates a concatenated string of
|
||||
// KMDF_DEVICE_NAME + L"XXXX". This is done to give us room for
|
||||
// appending a number up to 4 digits long after KMDF_DEVICE_NAME if
|
||||
// you want a null terminated string, 5 digits long if the string is
|
||||
// not null terminated (as is the case for a UNICODE_STRING)
|
||||
//
|
||||
WCHAR buffer[] = KMDF_DEVICE_NAME L"XXXX";
|
||||
|
||||
//
|
||||
// Initialize global to make NonPagedPool be treated as NxPool on Win8
|
||||
// and NonPagedPool on down-level
|
||||
//
|
||||
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||
|
||||
RtlInitUnicodeString(&string, WDF_REGISTRY_DBGPRINT_ON);
|
||||
|
||||
//
|
||||
// Determine if debug prints are on.
|
||||
//
|
||||
(void) WdfLdrDiagnosticsValueByNameAsULONG(&string, &WdfLdrDbgPrintOn);
|
||||
|
||||
__Print(("DriverEntry\n"));
|
||||
|
||||
DriverObject->DriverUnload = DriverUnload;
|
||||
|
||||
FxLibraryGlobals.DriverObject = DriverObject;
|
||||
|
||||
DriverObject->MajorFunction[IRP_MJ_CREATE] = FxLibraryDispatch;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FxLibraryDispatch;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FxLibraryDispatch;
|
||||
|
||||
RtlZeroMemory(&name, sizeof(name));
|
||||
name.Buffer = buffer;
|
||||
name.Length = 0x0;
|
||||
name.MaximumLength = sizeof(buffer);
|
||||
|
||||
//
|
||||
// We use the string when we declare the buffer to get the right sized
|
||||
// buffer. Now we want to make sure there are no contents before we
|
||||
// use it to create a device object.
|
||||
//
|
||||
RtlZeroMemory(buffer, sizeof(buffer));
|
||||
|
||||
status = FxLibraryCreateDevice(&name);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("ERROR: FxLibraryCreateDevice failed with Status 0x%x\n", status));
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Register this library with WdfLdr
|
||||
//
|
||||
// NOTE: Once WdfRegisterLibrary returns NT_SUCCESS() we must return
|
||||
// NT_SUCCESS from DriverEntry!
|
||||
//
|
||||
status = WdfRegisterLibrary( &WdfLibraryInfo, RegistryPath, &name );
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("ERROR: WdfRegisterLibrary failed with Status 0x%x\n", status));
|
||||
FxLibraryCleanup();
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Write KMDF version to registry
|
||||
//
|
||||
WdfWriteKmdfVersionToRegistry(DriverObject, RegistryPath);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
extern "C"
|
||||
VOID
|
||||
DriverUnload(
|
||||
__in PDRIVER_OBJECT DriverObject
|
||||
)
|
||||
{
|
||||
__Print(("DriverUnload\n"));
|
||||
|
||||
//
|
||||
// Delete KMDF version from registry before destroying the Driver Object
|
||||
//
|
||||
WdfDeleteKmdfVersionFromRegistry(DriverObject);
|
||||
|
||||
//
|
||||
// Make sure everything is deleted. Since the driver is considered a legacy
|
||||
// driver, it can be unloaded while there are still outstanding device objects.
|
||||
//
|
||||
FxLibraryCleanup();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
extern "C"
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDF_LIBRARY_COMMISSION(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return FxLibraryCommonCommission();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
extern "C"
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDF_LIBRARY_DECOMMISSION(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return FxLibraryCommonDecommission();
|
||||
}
|
||||
|
||||
#define EVTLOG_MESSAGE_SIZE 70
|
||||
#define RAW_DATA_SIZE 4
|
||||
|
||||
extern "C"
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDF_LIBRARY_REGISTER_CLIENT(
|
||||
__in PWDF_BIND_INFO Info,
|
||||
__deref_out PWDF_DRIVER_GLOBALS * WdfDriverGlobals,
|
||||
__deref_inout PVOID * Context
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_INVALID_PARAMETER;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
WCHAR insertString[EVTLOG_MESSAGE_SIZE];
|
||||
ULONG rawData[RAW_DATA_SIZE];
|
||||
PCLIENT_INFO clientInfo = NULL;
|
||||
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n"));
|
||||
|
||||
clientInfo = (PCLIENT_INFO)*Context;
|
||||
*Context = NULL;
|
||||
|
||||
ASSERT(Info->Version.Major == WdfLibraryInfo.Version.Major);
|
||||
|
||||
//
|
||||
// NOTE: If the currently loaded library < drivers minor version fail the load
|
||||
// instead of binding to a lower minor version. The reason for that if there
|
||||
// is a newer API or new contract change made the driver shouldn't be using older
|
||||
// API than it was compiled with.
|
||||
//
|
||||
|
||||
if (Info->Version.Minor > WdfLibraryInfo.Version.Minor) {
|
||||
status = RtlStringCchPrintfW(insertString,
|
||||
RTL_NUMBER_OF(insertString),
|
||||
L"Driver Version: %d.%d Kmdf Lib. Version: %d.%d",
|
||||
Info->Version.Major,
|
||||
Info->Version.Minor,
|
||||
WdfLibraryInfo.Version.Major,
|
||||
WdfLibraryInfo.Version.Minor);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("ERROR: RtlStringCchPrintfW failed with Status 0x%x\n", status));
|
||||
return status;
|
||||
}
|
||||
rawData[0] = Info->Version.Major;
|
||||
rawData[1] = Info->Version.Minor;
|
||||
rawData[2] = WdfLibraryInfo.Version.Major;
|
||||
rawData[3] = WdfLibraryInfo.Version.Minor;
|
||||
|
||||
LibraryLogEvent(FxLibraryGlobals.DriverObject,
|
||||
WDFVER_MINOR_VERSION_NOT_SUPPORTED,
|
||||
STATUS_OBJECT_TYPE_MISMATCH,
|
||||
insertString,
|
||||
rawData,
|
||||
sizeof(rawData) );
|
||||
//
|
||||
// this looks like the best status to return
|
||||
//
|
||||
return STATUS_OBJECT_TYPE_MISMATCH;
|
||||
|
||||
}
|
||||
|
||||
status = FxLibraryCommonRegisterClient(Info,
|
||||
WdfDriverGlobals,
|
||||
clientInfo);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// The context will be a pointer to FX_DRIVER_GLOBALS
|
||||
//
|
||||
*Context = GetFxDriverGlobals(*WdfDriverGlobals);
|
||||
|
||||
//
|
||||
// Set the WDF_BIND_INFO structure pointer in FxDriverGlobals
|
||||
//
|
||||
pFxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals);
|
||||
pFxDriverGlobals->WdfBindInfo = Info;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
extern "C"
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDF_LIBRARY_UNREGISTER_CLIENT(
|
||||
__in PWDF_BIND_INFO Info,
|
||||
__in PWDF_DRIVER_GLOBALS WdfDriverGlobals
|
||||
)
|
||||
{
|
||||
return FxLibraryCommonUnregisterClient(Info, WdfDriverGlobals);
|
||||
}
|
||||
|
||||
VOID
|
||||
WdfWriteKmdfVersionToRegistry(
|
||||
__in PDRIVER_OBJECT DriverObject,
|
||||
__in PUNICODE_STRING RegistryPath
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
HANDLE driverKey;
|
||||
HANDLE parametersKey;
|
||||
UNICODE_STRING valueName;
|
||||
UNICODE_STRING parametersPath;
|
||||
PDRV_EXTENSION driverExtension;
|
||||
|
||||
driverKey = NULL;
|
||||
parametersKey = NULL;
|
||||
driverExtension = NULL;
|
||||
|
||||
RtlInitUnicodeString(¶metersPath, DRIVER_PARAMETERS);
|
||||
|
||||
InitializeObjectAttributes(&objectAttributes,
|
||||
RegistryPath,
|
||||
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
status = ZwOpenKey(&driverKey, KEY_CREATE_SUB_KEY, &objectAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("WdfWriteKmdfVersionToRegistry: Failed to open HKLM\\%S\n",
|
||||
RegistryPath->Buffer));
|
||||
goto out;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&objectAttributes,
|
||||
¶metersPath,
|
||||
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
||||
driverKey,
|
||||
NULL);
|
||||
|
||||
//
|
||||
// Open or create key and get a handle
|
||||
//
|
||||
status = ZwCreateKey(¶metersKey,
|
||||
KEY_SET_VALUE,
|
||||
&objectAttributes,
|
||||
0,
|
||||
(PUNICODE_STRING) NULL,
|
||||
REG_OPTION_VOLATILE,
|
||||
NULL);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("WdfWriteKmdfVersionToRegistry: Failed to open HKLM\\%S\\%S\n",
|
||||
RegistryPath->Buffer, parametersPath.Buffer));
|
||||
goto out;
|
||||
}
|
||||
|
||||
//
|
||||
// Set Major Version
|
||||
//
|
||||
RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MAJOR_VERSION);
|
||||
|
||||
status = ZwSetValueKey(parametersKey,
|
||||
&valueName,
|
||||
0,
|
||||
REG_DWORD,
|
||||
&WdfLibraryInfo.Version.Major,
|
||||
sizeof(WdfLibraryInfo.Version.Major));
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("WdfWriteKmdfVersionToRegistry: Failed to set Major Version\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
//
|
||||
// Set Minor Version
|
||||
//
|
||||
RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MINOR_VERSION);
|
||||
|
||||
status = ZwSetValueKey(parametersKey,
|
||||
&valueName,
|
||||
0,
|
||||
REG_DWORD,
|
||||
&WdfLibraryInfo.Version.Minor,
|
||||
sizeof(WdfLibraryInfo.Version.Minor));
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("WdfWriteKmdfVersionToRegistry: Failed to set Minor Version\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Set Build Number
|
||||
//
|
||||
RtlInitUnicodeString(&valueName, REGISTRY_KMDF_BUILD_NUMBER);
|
||||
|
||||
status = ZwSetValueKey(parametersKey,
|
||||
&valueName,
|
||||
0,
|
||||
REG_DWORD,
|
||||
&WdfLibraryInfo.Version.Build,
|
||||
sizeof(WdfLibraryInfo.Version.Build));
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("WdfWriteKmdfVersionToRegistry: Failed to set Build Number\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a Driver Extension to store the registry path, where we write the
|
||||
// version of the wdf01000.sys that's loaded in memory
|
||||
//
|
||||
status = IoAllocateDriverObjectExtension(DriverObject,
|
||||
(PVOID) DRIVER_OBJECT_EXTENSION_IDENTIFIER,
|
||||
sizeof(DRV_EXTENSION),
|
||||
(PVOID *)&driverExtension);
|
||||
|
||||
if (!NT_SUCCESS(status) || driverExtension == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
driverExtension->ParametersRegistryPath.Buffer = (PWCHAR) ExAllocatePoolWithTag(
|
||||
PagedPool,
|
||||
RegistryPath->MaximumLength,
|
||||
FX_TAG);
|
||||
if (driverExtension->ParametersRegistryPath.Buffer == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
driverExtension->ParametersRegistryPath.MaximumLength = RegistryPath->MaximumLength;
|
||||
RtlCopyUnicodeString(&(driverExtension->ParametersRegistryPath), RegistryPath);
|
||||
|
||||
out:
|
||||
if (driverKey != NULL) {
|
||||
ZwClose(driverKey);
|
||||
}
|
||||
|
||||
if (parametersKey != NULL) {
|
||||
ZwClose(parametersKey);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
WdfDeleteKmdfVersionFromRegistry(
|
||||
__in PDRIVER_OBJECT DriverObject
|
||||
)
|
||||
{
|
||||
PUNICODE_STRING registryPath;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
HANDLE driverKey;
|
||||
HANDLE parametersKey;
|
||||
UNICODE_STRING valueName;
|
||||
NTSTATUS status;
|
||||
UNICODE_STRING parametersPath;
|
||||
PDRV_EXTENSION driverExtension;
|
||||
|
||||
RtlInitUnicodeString(¶metersPath, DRIVER_PARAMETERS);
|
||||
|
||||
driverKey = NULL;
|
||||
parametersKey = NULL;
|
||||
|
||||
driverExtension = (PDRV_EXTENSION)IoGetDriverObjectExtension(DriverObject,
|
||||
DRIVER_OBJECT_EXTENSION_IDENTIFIER);
|
||||
|
||||
if (driverExtension == NULL || driverExtension->ParametersRegistryPath.Buffer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
registryPath = &driverExtension->ParametersRegistryPath;
|
||||
|
||||
InitializeObjectAttributes(&objectAttributes,
|
||||
registryPath,
|
||||
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
status = ZwOpenKey(&driverKey, KEY_SET_VALUE, &objectAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&objectAttributes,
|
||||
¶metersPath,
|
||||
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
||||
driverKey,
|
||||
NULL);
|
||||
//
|
||||
// Open the key for deletion
|
||||
//
|
||||
status = ZwOpenKey(¶metersKey,
|
||||
DELETE,
|
||||
&objectAttributes);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MAJOR_VERSION);
|
||||
ZwDeleteValueKey(parametersKey, &valueName);
|
||||
|
||||
RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MINOR_VERSION);
|
||||
ZwDeleteValueKey(parametersKey, &valueName);
|
||||
|
||||
RtlInitUnicodeString(&valueName, REGISTRY_KMDF_BUILD_NUMBER);
|
||||
ZwDeleteValueKey(parametersKey, &valueName);
|
||||
|
||||
ZwDeleteKey(parametersKey);
|
||||
|
||||
out:
|
||||
if (driverExtension->ParametersRegistryPath.Buffer != NULL) {
|
||||
ExFreePool(driverExtension->ParametersRegistryPath.Buffer);
|
||||
}
|
||||
|
||||
if (driverKey != NULL) {
|
||||
ZwClose(driverKey);
|
||||
}
|
||||
|
||||
if (parametersKey != NULL) {
|
||||
ZwClose(parametersKey);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxObjectInfoKm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This file contains object info split from globals.cpp
|
||||
|
||||
This is because objects incorporated in KMDF and UMDF will differ
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxobjectpch.hpp"
|
||||
|
||||
#include "FxMemoryBufferPreallocated.hpp"
|
||||
#include "FxUserObject.hpp"
|
||||
#include "FxUsbDevice.hpp"
|
||||
#include "FxUsbPipe.hpp"
|
||||
#include "FxUsbInterface.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
//
|
||||
// Assumes sorted (by type) order!
|
||||
//
|
||||
FX_OBJECT_INFO FxObjectsInfo[] = {
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxObject, FX_TYPE_OBJECT),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDriver, FX_TYPE_DRIVER, WDFDRIVER),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDevice, FX_TYPE_DEVICE, WDFDEVICE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoQueue, FX_TYPE_QUEUE, WDFQUEUE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWmiProvider, FX_TYPE_WMI_PROVIDER, WDFWMIPROVIDER),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRegKey, FX_TYPE_REG_KEY, WDFKEY),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxString, FX_TYPE_STRING, WDFSTRING),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRequest, FX_TYPE_REQUEST, WDFREQUEST),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxLookasideList, FX_TYPE_LOOKASIDE, WDFLOOKASIDE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMemoryObject, IFX_TYPE_MEMORY, WDFMEMORY),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxIrpQueue, FX_TYPE_IRPQUEUE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUserObject, FX_TYPE_USEROBJECT, WDFOBJECT),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxCollection, FX_TYPE_COLLECTION, WDFCOLLECTION),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxVerifierLock, FX_TYPE_VERIFIERLOCK),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxSystemThread, FX_TYPE_SYSTEMTHREAD),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMpDevice, FX_TYPE_MP_DEVICE, WDFDEVICE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDpc, FX_TYPE_DPC, WDFDPC),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxResourceIo, FX_TYPE_RESOURCE_IO),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxResourceCm, FX_TYPE_RESOURCE_CM),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxFileObject, FX_TYPE_FILEOBJECT, WDFFILEOBJECT),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxRelatedDevice, FX_TYPE_RELATED_DEVICE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMemoryBufferPreallocated, FX_TYPE_MEMORY_PREALLOCATED, WDFMEMORY),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWaitLock, FX_TYPE_WAIT_LOCK, WDFWAITLOCK),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxSpinLock, FX_TYPE_SPIN_LOCK, WDFSPINLOCK),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWorkItem, FX_TYPE_WORKITEM, WDFWORKITEM),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxInterrupt, FX_TYPE_INTERRUPT, WDFINTERRUPT),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxTimer, FX_TYPE_TIMER, WDFTIMER),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxChildList, FX_TYPE_CHILD_LIST, WDFCHILDLIST),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxSystemWorkItem, FX_TYPE_SYSTEMWORKITEM),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRequestMemory, FX_TYPE_REQUEST_MEMORY, WDFMEMORY),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxDisposeList, FX_TYPE_DISPOSELIST),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWmiInstanceExternal, FX_TYPE_WMI_INSTANCE, WDFWMIINSTANCE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoResList, FX_TYPE_IO_RES_LIST, WDFIORESLIST),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxCmResList, FX_TYPE_CM_RES_LIST, WDFCMRESLIST),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoResReqList, FX_TYPE_IO_RES_REQ_LIST, WDFIORESREQLIST),
|
||||
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgIo, FX_TYPE_PACKAGE_IO),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgFdo, FX_TYPE_PACKAGE_FDO),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgPdo, FX_TYPE_PACKAGE_PDO),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxWmiIrpHandler, FX_TYPE_WMI_IRP_HANDLER),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgGeneral, FX_TYPE_PACKAGE_GENERAL),
|
||||
FX_INTERNAL_OBJECT_INFO_ENTRY(FxDefaultIrpHandler, FX_TYPE_DEFAULT_IRP_HANDLER),
|
||||
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoTarget, FX_TYPE_IO_TARGET, WDFIOTARGET),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbDevice, FX_TYPE_IO_TARGET_USB_DEVICE, WDFUSBDEVICE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbPipe, FX_TYPE_IO_TARGET_USB_PIPE, WDFUSBPIPE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbInterface, FX_TYPE_USB_INTERFACE, WDFUSBINTERFACE),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoTargetSelf, FX_TYPE_IO_TARGET_SELF, WDFIOTARGET),
|
||||
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDmaEnabler, FX_TYPE_DMA_ENABLER, WDFDMAENABLER ),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDmaTransactionBase, FX_TYPE_DMA_TRANSACTION, WDFDMATRANSACTION ),
|
||||
FX_EXTERNAL_OBJECT_INFO_ENTRY(FxCommonBuffer, FX_TYPE_COMMON_BUFFER, WDFCOMMONBUFFER ),
|
||||
};
|
||||
|
||||
ULONG FxObjectsInfoCount = sizeof(FxObjectsInfo)/sizeof(FX_OBJECT_INFO);
|
||||
|
||||
} //extern "C"
|
||||
@@ -0,0 +1,29 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
fxcorepch.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains header definitions and include files needed by all
|
||||
modules in FxToSharedInterface\FxObject
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __FX_CORE_PCH_H__
|
||||
#define __FX_CORE_PCH_H__
|
||||
|
||||
#include "objectpriv.hpp"
|
||||
#include <fx.hpp>
|
||||
|
||||
#endif // __FX_CORE_PCH_H__
|
||||
@@ -0,0 +1,33 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
corepriv.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Private header file for FxToSharedInterface\FxObject directory
|
||||
It is then included in objectpch.hpp
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
extern "C" {
|
||||
#include <ntddk.h>
|
||||
#include "wdf.h"
|
||||
}
|
||||
|
||||
#define WDF_REGISTRY_BASE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wdf"
|
||||
|
||||
@@ -0,0 +1,439 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxWmiApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the C interface to the WMI package
|
||||
for the driver frameworks.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxwmipch.hpp"
|
||||
|
||||
//
|
||||
// Extern "C" the tmh file and all external APIs
|
||||
//
|
||||
extern "C" {
|
||||
#include "FxWmiAPI.tmh"
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfWmiProviderCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES ProviderAttributes,
|
||||
__out
|
||||
WDFWMIPROVIDER* WmiProvider
|
||||
)
|
||||
{
|
||||
FxDevice* pDevice;
|
||||
FxPowerPolicyOwnerSettings* ownerSettings;
|
||||
FxWmiProvider* pProvider;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), WmiProviderConfig);
|
||||
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), WmiProvider);
|
||||
|
||||
//
|
||||
// If the Device is a power policy owner then do not allow client drivers
|
||||
// to register for GUID_POWER_DEVICE_ENABLE or GUID_POWER_DEVICE_WAKE_ENABLE
|
||||
// if the framework has already register a provider for those guids.
|
||||
//
|
||||
if (pDevice->m_PkgPnp->IsPowerPolicyOwner()) {
|
||||
ownerSettings = pDevice->m_PkgPnp->m_PowerPolicyMachine.m_Owner;
|
||||
|
||||
if ((FxIsEqualGuid(&WmiProviderConfig->Guid,
|
||||
&GUID_POWER_DEVICE_ENABLE) &&
|
||||
ownerSettings->m_IdleSettings.WmiInstance != NULL) ||
|
||||
|
||||
(FxIsEqualGuid(&WmiProviderConfig->Guid,
|
||||
&GUID_POWER_DEVICE_WAKE_ENABLE) &&
|
||||
ownerSettings->m_WakeSettings.WmiInstance != NULL)) {
|
||||
|
||||
DoTraceLevelMessage(GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_ERROR,
|
||||
TRACINGDEVICE, "WMI Guid already registered by "
|
||||
"framework");
|
||||
return STATUS_WMI_GUID_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return FxWmiProvider::_Create(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
ProviderAttributes,
|
||||
WmiProviderConfig,
|
||||
WmiProvider,
|
||||
&pProvider);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfWmiInstanceCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PWDF_WMI_INSTANCE_CONFIG InstanceConfig,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES InstanceAttributes,
|
||||
__out_opt
|
||||
WDFWMIINSTANCE* Instance
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxWmiProvider* pProvider;
|
||||
FxWmiInstanceExternal* pInstance;
|
||||
WDFWMIINSTANCE hInstance;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
pInstance = NULL;
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, InstanceConfig);
|
||||
|
||||
if (InstanceConfig->Size != sizeof(WDF_WMI_INSTANCE_CONFIG)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Expected InstanceConfig Size %d, got %d, %!STATUS!",
|
||||
InstanceConfig->Size, sizeof(*InstanceConfig),
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (InstanceConfig->Provider == NULL &&
|
||||
InstanceConfig->ProviderConfig == NULL) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"InstanceConfig %p Provider and ProviderConfig are both NULL, only "
|
||||
"one can be, %!STATUS!", InstanceConfig, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
else if (InstanceConfig->Provider != NULL &&
|
||||
InstanceConfig->ProviderConfig != NULL) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"InstanceConfig %p Provider %p and ProviderConfig %p are both not "
|
||||
"NULL, only one can be, %!STATUS!", InstanceConfig,
|
||||
InstanceConfig->Provider, InstanceConfig->ProviderConfig, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (InstanceConfig->Provider != NULL) {
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
InstanceConfig->Provider,
|
||||
FX_TYPE_WMI_PROVIDER,
|
||||
(PVOID*) &pProvider,
|
||||
&pFxDriverGlobals);
|
||||
}
|
||||
else {
|
||||
FxDevice* pDevice;
|
||||
FxPowerPolicyOwnerSettings* ownerSettings;
|
||||
WDFWMIPROVIDER hProvider;
|
||||
|
||||
hProvider = NULL;
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
//
|
||||
// If the Device is a power policy owner then do not allow client drivers
|
||||
// to register for GUID_POWER_DEVICE_ENABLE or GUID_POWER_DEVICE_WAKE_ENABLE
|
||||
// if the framework has already register a provider for those guids.
|
||||
//
|
||||
if (pDevice->m_PkgPnp->IsPowerPolicyOwner()) {
|
||||
ownerSettings = pDevice->m_PkgPnp->m_PowerPolicyMachine.m_Owner;
|
||||
|
||||
if ((FxIsEqualGuid(&InstanceConfig->ProviderConfig->Guid,
|
||||
&GUID_POWER_DEVICE_ENABLE) &&
|
||||
ownerSettings->m_IdleSettings.WmiInstance != NULL) ||
|
||||
|
||||
(FxIsEqualGuid(&InstanceConfig->ProviderConfig->Guid,
|
||||
&GUID_POWER_DEVICE_WAKE_ENABLE) &&
|
||||
ownerSettings->m_WakeSettings.WmiInstance != NULL)) {
|
||||
|
||||
status = STATUS_WMI_GUID_DISCONNECTED;
|
||||
DoTraceLevelMessage(GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_ERROR,
|
||||
TRACINGDEVICE, "WMI Guid already registered by "
|
||||
"framework");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = FxWmiProvider::_Create(pFxDriverGlobals,
|
||||
Device,
|
||||
NULL,
|
||||
InstanceConfig->ProviderConfig,
|
||||
&hProvider,
|
||||
&pProvider);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Use the object's globals and not the caller's
|
||||
//
|
||||
pFxDriverGlobals = pProvider->GetDriverGlobals();
|
||||
}
|
||||
|
||||
status = FxWmiInstanceExternal::_Create(pFxDriverGlobals,
|
||||
pProvider,
|
||||
InstanceConfig,
|
||||
InstanceAttributes,
|
||||
&hInstance,
|
||||
&pInstance);
|
||||
|
||||
if (NT_SUCCESS(status) && InstanceConfig->Register) {
|
||||
status = pProvider->AddInstance(pInstance);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
if (Instance != NULL) {
|
||||
*Instance = hInstance;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Something went wrong, cleanup
|
||||
//
|
||||
if (pInstance != NULL) {
|
||||
//
|
||||
// This will remove the instance from the provider's list as well.
|
||||
//
|
||||
pInstance->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
//
|
||||
// Only remove the provider if we created it in this function
|
||||
//
|
||||
if (InstanceConfig->ProviderConfig != NULL) {
|
||||
pProvider->DeleteFromFailedCreate();
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
WDFAPI
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDEVICE
|
||||
WDFEXPORT(WdfWmiProviderGetDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWMIPROVIDER WmiProvider
|
||||
)
|
||||
{
|
||||
FxWmiProvider *pProvider;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WmiProvider,
|
||||
FX_TYPE_WMI_PROVIDER,
|
||||
(PVOID*) &pProvider);
|
||||
|
||||
return pProvider->GetDevice()->GetHandle();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
WDFEXPORT(WdfWmiProviderIsEnabled)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWMIPROVIDER WmiProvider,
|
||||
__in
|
||||
WDF_WMI_PROVIDER_CONTROL ProviderControl
|
||||
)
|
||||
{
|
||||
FxWmiProvider *pProvider;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WmiProvider,
|
||||
FX_TYPE_WMI_PROVIDER,
|
||||
(PVOID*) &pProvider);
|
||||
|
||||
return pProvider->IsEnabled(ProviderControl);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
ULONGLONG
|
||||
WDFEXPORT(WdfWmiProviderGetTracingHandle)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWMIPROVIDER WmiProvider
|
||||
)
|
||||
{
|
||||
FxWmiProvider *pProvider;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WmiProvider,
|
||||
FX_TYPE_WMI_PROVIDER,
|
||||
(PVOID*) &pProvider);
|
||||
|
||||
return pProvider->GetTracingHandle();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfWmiInstanceRegister)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWMIINSTANCE WmiInstance
|
||||
)
|
||||
{
|
||||
FxWmiInstanceExternal* pInstance;
|
||||
FxWmiProvider* pProvider;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WmiInstance,
|
||||
FX_TYPE_WMI_INSTANCE,
|
||||
(PVOID*) &pInstance);
|
||||
|
||||
pProvider = pInstance->GetProvider();
|
||||
|
||||
return pProvider->AddInstance(pInstance);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfWmiInstanceDeregister)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWMIINSTANCE WmiInstance
|
||||
)
|
||||
{
|
||||
FxWmiInstanceExternal* pInstance;
|
||||
FxWmiProvider* pProvider;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WmiInstance,
|
||||
FX_TYPE_WMI_INSTANCE,
|
||||
(PVOID*) &pInstance);
|
||||
|
||||
pProvider = pInstance->GetProvider();
|
||||
pProvider->RemoveInstance(pInstance);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDEVICE
|
||||
WDFEXPORT(WdfWmiInstanceGetDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWMIINSTANCE WmiInstance
|
||||
)
|
||||
{
|
||||
FxWmiInstanceExternal* pInstance;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WmiInstance,
|
||||
FX_TYPE_WMI_INSTANCE,
|
||||
(PVOID*) &pInstance);
|
||||
|
||||
return pInstance->GetDevice()->GetHandle();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFWMIPROVIDER
|
||||
WDFEXPORT(WdfWmiInstanceGetProvider)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWMIINSTANCE WmiInstance
|
||||
)
|
||||
{
|
||||
FxWmiInstanceExternal *pInstance;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WmiInstance,
|
||||
FX_TYPE_WMI_INSTANCE,
|
||||
(PVOID*) &pInstance);
|
||||
|
||||
return pInstance->GetProvider()->GetHandle();
|
||||
}
|
||||
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(APC_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfWmiInstanceFireEvent)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWMIINSTANCE WmiInstance,
|
||||
__in_opt
|
||||
ULONG EventDataSize,
|
||||
__in_bcount_opt(EventDataSize)
|
||||
PVOID EventData
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Fires an event based on the instance handle.
|
||||
|
||||
Arguments:
|
||||
WmiInstance - instance which the event is associated with
|
||||
EventDataSize - size of EventData in bytes
|
||||
EventData - buffer associated with the event
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
FxWmiInstanceExternal* pInstance;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WmiInstance,
|
||||
FX_TYPE_WMI_INSTANCE,
|
||||
(PVOID*) &pInstance);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pInstance->GetDriverGlobals(), APC_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return pInstance->FireEvent(EventData, EventDataSize);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,684 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxWmiInstance.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the FxWmiInstance object and its derivations
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxwmipch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxWmiInstance.tmh"
|
||||
}
|
||||
|
||||
FxWmiInstance::FxWmiInstance(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in USHORT ObjectSize,
|
||||
__in FxWmiProvider* Provider
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_WMI_INSTANCE, ObjectSize, FxDriverGlobals)
|
||||
{
|
||||
InitializeListHead(&m_ListEntry);
|
||||
m_Provider = Provider;
|
||||
m_Provider->ADDREF(this);
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
}
|
||||
|
||||
FxWmiInstance::~FxWmiInstance()
|
||||
{
|
||||
ASSERT(IsListEmpty(&m_ListEntry));
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstance::Dispose(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
m_Provider->RemoveInstance(this);
|
||||
m_Provider->RELEASE(this);
|
||||
|
||||
//
|
||||
// Object is being deleted, remove this object from the provider's list
|
||||
// of instances. If we don't do this, the provider will have a list which
|
||||
// contains entries which have been freed.
|
||||
//
|
||||
return __super::Dispose();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiInstance::FireEvent(
|
||||
__in_bcount_opt(EventBufferSize) PVOID EventBuffer,
|
||||
__inout ULONG EventBufferSize
|
||||
)
|
||||
{
|
||||
ULONG sizeNeeded;
|
||||
PWNODE_SINGLE_INSTANCE pNode;
|
||||
NTSTATUS status;
|
||||
|
||||
if (EventBuffer == NULL) {
|
||||
EventBufferSize = 0;
|
||||
}
|
||||
|
||||
sizeNeeded = sizeof(WNODE_SINGLE_INSTANCE) + EventBufferSize;
|
||||
|
||||
//
|
||||
// IoWMIWriteEvent will free the memory by calling ExFreePool. This means
|
||||
// we cannot use a framework allocate function.
|
||||
//
|
||||
pNode = (PWNODE_SINGLE_INSTANCE)
|
||||
ExAllocatePoolWithTag(NonPagedPool, sizeNeeded, GetDriverGlobals()->Tag);
|
||||
|
||||
if (pNode != NULL) {
|
||||
RtlCopyMemory(&pNode->WnodeHeader.Guid,
|
||||
m_Provider->GetGUID(),
|
||||
sizeof(GUID));
|
||||
|
||||
pNode->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(
|
||||
GetDevice()->GetDeviceObject());
|
||||
pNode->WnodeHeader.BufferSize = sizeNeeded;
|
||||
pNode->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
|
||||
WNODE_FLAG_EVENT_ITEM |
|
||||
WNODE_FLAG_STATIC_INSTANCE_NAMES;
|
||||
KeQuerySystemTime(&pNode->WnodeHeader.TimeStamp);
|
||||
|
||||
pNode->InstanceIndex = m_Provider->GetInstanceIndex(this);
|
||||
pNode->SizeDataBlock = EventBufferSize;
|
||||
pNode->DataBlockOffset = sizeof(WNODE_SINGLE_INSTANCE);
|
||||
|
||||
if (EventBuffer != NULL) {
|
||||
RtlCopyMemory(&pNode->VariableData, EventBuffer, EventBufferSize);
|
||||
}
|
||||
|
||||
//
|
||||
// Upon success, IoWMIWriteEvent will free pNode.
|
||||
//
|
||||
status = IoWMIWriteEvent(pNode);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
ExFreePool(pNode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFWMIINSTANCE %p insufficient resources to fire event,%!STATUS!",
|
||||
GetHandle(), status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
FxWmiInstanceExternal::FxWmiInstanceExternal(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PWDF_WMI_INSTANCE_CONFIG Config,
|
||||
__in FxWmiProvider* Provider
|
||||
) :
|
||||
FxWmiInstance(FxDriverGlobals, sizeof(FxWmiInstanceExternal), Provider),
|
||||
m_QueryInstanceCallback(FxDriverGlobals),
|
||||
m_SetInstanceCallback(FxDriverGlobals),
|
||||
m_SetItemCallback(FxDriverGlobals),
|
||||
m_ExecuteMethodCallback(FxDriverGlobals)
|
||||
{
|
||||
m_ContextLength = 0;
|
||||
m_UseContextForQuery = Config->UseContextForQuery;
|
||||
|
||||
if (m_UseContextForQuery == FALSE) {
|
||||
m_QueryInstanceCallback.m_Method = Config->EvtWmiInstanceQueryInstance;
|
||||
}
|
||||
m_SetInstanceCallback.m_Method = Config->EvtWmiInstanceSetInstance;
|
||||
m_SetItemCallback.m_Method = Config->EvtWmiInstanceSetItem;
|
||||
|
||||
m_ExecuteMethodCallback.m_Method = Config->EvtWmiInstanceExecuteMethod;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiInstanceExternal::_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in FxWmiProvider* Provider,
|
||||
__in PWDF_WMI_INSTANCE_CONFIG WmiInstanceConfig,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES InstanceAttributes,
|
||||
__out WDFWMIINSTANCE* WmiInstance,
|
||||
__out FxWmiInstanceExternal** Instance
|
||||
)
|
||||
{
|
||||
FxWmiInstanceExternal* pInstance;
|
||||
WDFWMIINSTANCE hInstance;
|
||||
NTSTATUS status;
|
||||
size_t contextSize;
|
||||
|
||||
contextSize = 0;
|
||||
*Instance = 0;
|
||||
|
||||
*WmiInstance = NULL;
|
||||
|
||||
//
|
||||
// For event only providers, you cannot specify any callbacks or context
|
||||
// usage.
|
||||
//
|
||||
if (Provider->IsEventOnly() &&
|
||||
(WmiInstanceConfig->UseContextForQuery ||
|
||||
WmiInstanceConfig->EvtWmiInstanceQueryInstance != NULL ||
|
||||
WmiInstanceConfig->EvtWmiInstanceSetInstance != NULL ||
|
||||
WmiInstanceConfig->EvtWmiInstanceSetItem != NULL ||
|
||||
WmiInstanceConfig->EvtWmiInstanceExecuteMethod != NULL)) {
|
||||
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFWMIPROVIDER %p is event only and UseContextForQuery (%d) is TRUE,"
|
||||
" or a callback (query instance %p, set instance %p, set item %p, "
|
||||
"executue method %p) is not NULL, %!STATUS!",
|
||||
Provider->GetHandle(), WmiInstanceConfig->UseContextForQuery,
|
||||
WmiInstanceConfig->EvtWmiInstanceQueryInstance,
|
||||
WmiInstanceConfig->EvtWmiInstanceSetInstance,
|
||||
WmiInstanceConfig->EvtWmiInstanceSetItem,
|
||||
WmiInstanceConfig->EvtWmiInstanceExecuteMethod, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(FxDriverGlobals,
|
||||
InstanceAttributes,
|
||||
FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (WmiInstanceConfig->UseContextForQuery) {
|
||||
//
|
||||
// UseContextForQuery only supported for read only instances.
|
||||
// ExecuteMethod has undefined side affects, so we allow it.
|
||||
//
|
||||
if (WmiInstanceConfig->EvtWmiInstanceSetInstance != NULL ||
|
||||
WmiInstanceConfig->EvtWmiInstanceSetItem != NULL) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"UseContextForQuery set, i.e. a read only instance, but "
|
||||
"EvtWmiInstanceSetInstance %p or EvtWmiInstanceSetItem %p is "
|
||||
"set, %!STATUS!",
|
||||
WmiInstanceConfig->EvtWmiInstanceSetInstance,
|
||||
WmiInstanceConfig->EvtWmiInstanceSetItem, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// We must have a context to use for the query
|
||||
//
|
||||
if (InstanceAttributes == NULL ||
|
||||
InstanceAttributes->ContextTypeInfo == NULL) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"UseContextForQuery set, but InstanceAttributes %p is null or "
|
||||
"there is no associated type, %!STATUS!",
|
||||
InstanceAttributes, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
contextSize = InstanceAttributes->ContextTypeInfo->ContextSize;
|
||||
|
||||
if (InstanceAttributes->ContextSizeOverride != 0) {
|
||||
status = RtlSizeTAdd(contextSize,
|
||||
InstanceAttributes->ContextSizeOverride,
|
||||
&contextSize);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Overlfow adding contextSize %I64d with size override %I64d, "
|
||||
"%!STATUS!", contextSize,
|
||||
InstanceAttributes->ContextSizeOverride, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (contextSize > ULONG_MAX) {
|
||||
//
|
||||
// Since we are casting to a ULONG below, detect loss of data here
|
||||
// (only really applicable on 64 bit machines where sizeof(size_t) !=
|
||||
// sizeof(ULONG)
|
||||
//
|
||||
status = STATUS_INTEGER_OVERFLOW;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"context size %I64d can be %d large, %!STATUS!",
|
||||
contextSize, ULONG_MAX, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure the context is the minimum the buffer size.
|
||||
//
|
||||
if (contextSize < Provider->GetMinInstanceBufferSize()) {
|
||||
status = STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"context size %I64d is less then the WDFWMIPROVIDER %p min size "
|
||||
"of %d, %!STATUS!",
|
||||
contextSize, Provider->GetHandle(),
|
||||
Provider->GetMinInstanceBufferSize(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
pInstance = new(FxDriverGlobals, InstanceAttributes)
|
||||
FxWmiInstanceExternal(FxDriverGlobals, WmiInstanceConfig, Provider);
|
||||
|
||||
if (pInstance == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"could not allocate memory for WDFWMIINSTANCE, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (contextSize > 0) {
|
||||
pInstance->SetContextForQueryLength((ULONG) contextSize);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = pInstance->Commit(
|
||||
InstanceAttributes, (PWDFOBJECT) &hInstance, Provider);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Assign the handle back to the caller.
|
||||
//
|
||||
*WmiInstance = hInstance;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// On failure, DeleteFromFailedCreate will delete the object and
|
||||
// the Dispose callback will remove the instance from the provider's
|
||||
// list.
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*Instance = pInstance;
|
||||
}
|
||||
else {
|
||||
pInstance->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstanceExternal::IsQueryInstanceSupported(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// If we have a function pointer to call or we are using the context
|
||||
// as the buffer, query instance is supported.
|
||||
//
|
||||
// Also, if neither of the first 2 are true, we need to support query
|
||||
// instance if the device has an execute method callback b/c WMI will
|
||||
// send a query instance to this instance which much succeed for the
|
||||
// execute method irp to be sent.
|
||||
//
|
||||
return (m_UseContextForQuery ||
|
||||
m_QueryInstanceCallback.m_Method != NULL ||
|
||||
m_ExecuteMethodCallback.m_Method != NULL) ? TRUE
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_sameIRQL
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxWmiInstanceExternal::QueryInstance(
|
||||
__inout ULONG OutBufferSize,
|
||||
__out_bcount(OutBufferSize) PVOID OutBuffer,
|
||||
__out PULONG BufferUsed
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
if (m_UseContextForQuery) {
|
||||
//
|
||||
// No matter what, we are reporting the length of the context. If the
|
||||
// buffer is too small, it is used to report the desired buffer length.
|
||||
// Otherwise, it is the amount of data we copied to the query buffer.
|
||||
//
|
||||
*BufferUsed = m_ContextLength;
|
||||
|
||||
if (OutBufferSize < m_ContextLength) {
|
||||
status = STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFWMIINSTANCE %p query instance using context for query, "
|
||||
"query buffer length %d, context length %d, %!STATUS!",
|
||||
GetHandle(), OutBufferSize, m_ContextLength, status);
|
||||
}
|
||||
else {
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
RtlCopyMemory(OutBuffer,
|
||||
&GetContextHeader()->Context[0],
|
||||
m_ContextLength);
|
||||
}
|
||||
}
|
||||
else if (m_QueryInstanceCallback.m_Method != NULL) {
|
||||
BYTE dummy;
|
||||
|
||||
if (OutBufferSize == 0) {
|
||||
ASSERT(m_Provider->GetMinInstanceBufferSize() == 0);
|
||||
OutBuffer = (PVOID) &dummy;
|
||||
OutBufferSize = sizeof(dummy);
|
||||
}
|
||||
|
||||
status = m_QueryInstanceCallback.Invoke(
|
||||
GetDevice()->GetHandle(),
|
||||
GetHandle(),
|
||||
OutBufferSize,
|
||||
OutBuffer,
|
||||
BufferUsed
|
||||
);
|
||||
|
||||
if (status == STATUS_PENDING) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WDFWMIINSTANCE %p was queried and returned %!STATUS!, which is "
|
||||
"not an allowed return value", GetHandle(), status);
|
||||
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
*BufferUsed = 0;
|
||||
}
|
||||
else if (NT_SUCCESS(status)) {
|
||||
if (*BufferUsed > OutBufferSize) {
|
||||
//
|
||||
// Caller error, they returned more bytes in *BufferUsed then
|
||||
// was passed in via OutBufferSize, yet returned NT_SUCCESS
|
||||
//
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WDFWMIINSTANCE %p was queried with buffer size %d, "
|
||||
" but returned %d bytes and %!STATUS!, should return "
|
||||
"!NT_SUCCESS in this case",
|
||||
GetHandle(), OutBufferSize, *BufferUsed, status);
|
||||
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
*BufferUsed = 0;
|
||||
}
|
||||
else if (OutBuffer == &dummy && *BufferUsed > 0) {
|
||||
//
|
||||
// Convert success back to an error where we can report the
|
||||
// required size back to the caller.
|
||||
//
|
||||
status = STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
else if (status == STATUS_BUFFER_TOO_SMALL) {
|
||||
if (m_Provider->GetMinInstanceBufferSize()) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WDFWMIINSTANCE %p returned %!STATUS!, but it specified "
|
||||
"a minimum instance size %d in its WDFWMIPROVIDER %p",
|
||||
GetHandle(), status, m_Provider->GetMinInstanceBufferSize(),
|
||||
m_Provider->GetHandle());
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"This is a break in the contract. Minimum instance size "
|
||||
"should only be used for fixed sized instances");
|
||||
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ASSERT(m_ExecuteMethodCallback.m_Method != NULL);
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WDFWMIINSTANCE %p was queried with no query callback and supports "
|
||||
"execute method (%p), zero bytes returned", GetHandle(),
|
||||
m_ExecuteMethodCallback.m_Method);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
*BufferUsed = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstanceExternal::IsSetInstanceSupported(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_SetInstanceCallback.m_Method != NULL ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_sameIRQL
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxWmiInstanceExternal::SetInstance(
|
||||
__in ULONG InBufferSize,
|
||||
__in_bcount(InBufferSize) PVOID InBuffer
|
||||
)
|
||||
{
|
||||
return m_SetInstanceCallback.Invoke(
|
||||
GetDevice()->GetHandle(),
|
||||
GetHandle(),
|
||||
InBufferSize,
|
||||
InBuffer
|
||||
);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstanceExternal::IsSetItemSupported(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_SetItemCallback.m_Method != NULL ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_sameIRQL
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxWmiInstanceExternal::SetItem(
|
||||
__in ULONG DataItemId,
|
||||
__in ULONG InBufferSize,
|
||||
__in_bcount(InBufferSize) PVOID InBuffer
|
||||
)
|
||||
{
|
||||
return m_SetItemCallback.Invoke(
|
||||
GetDevice()->GetHandle(),
|
||||
GetHandle(),
|
||||
DataItemId,
|
||||
InBufferSize,
|
||||
InBuffer
|
||||
);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstanceExternal::IsExecuteMethodSupported(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_ExecuteMethodCallback.m_Method != NULL ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_sameIRQL
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxWmiInstanceExternal::ExecuteMethod(
|
||||
__in ULONG MethodId,
|
||||
__in ULONG InBufferSize,
|
||||
__inout ULONG OutBufferSize,
|
||||
__drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize))
|
||||
__drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize))
|
||||
PVOID Buffer,
|
||||
__out PULONG BufferUsed
|
||||
)
|
||||
{
|
||||
return m_ExecuteMethodCallback.Invoke(
|
||||
GetDevice()->GetHandle(),
|
||||
GetHandle(),
|
||||
MethodId,
|
||||
InBufferSize,
|
||||
OutBufferSize,
|
||||
Buffer,
|
||||
BufferUsed
|
||||
);
|
||||
}
|
||||
|
||||
FxWmiInstanceInternal::FxWmiInstanceInternal(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in FxWmiInstanceInternalCallbacks* Callbacks,
|
||||
__in FxWmiProvider* Provider
|
||||
) : FxWmiInstance(FxDriverGlobals, sizeof(FxWmiInstanceInternal), Provider)
|
||||
{
|
||||
m_QueryInstance = Callbacks->QueryInstance;
|
||||
m_SetInstance = Callbacks->SetInstance;
|
||||
m_SetItem = Callbacks->SetItem;
|
||||
m_ExecuteMethod = Callbacks->ExecuteMethod;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstanceInternal::IsQueryInstanceSupported(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_QueryInstance != NULL ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_sameIRQL
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxWmiInstanceInternal::QueryInstance(
|
||||
__inout ULONG OutBufferSize,
|
||||
__out_bcount(OutBufferSize) PVOID OutBuffer,
|
||||
__out PULONG BufferUsed
|
||||
)
|
||||
{
|
||||
return m_QueryInstance(GetDevice(),
|
||||
this,
|
||||
OutBufferSize,
|
||||
OutBuffer,
|
||||
BufferUsed);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstanceInternal::IsSetInstanceSupported(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_SetInstance != NULL ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_sameIRQL
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxWmiInstanceInternal::SetInstance(
|
||||
__in ULONG InBufferSize,
|
||||
__in_bcount(InBufferSize) PVOID InBuffer
|
||||
)
|
||||
{
|
||||
return m_SetInstance(GetDevice(),
|
||||
this,
|
||||
InBufferSize,
|
||||
InBuffer);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstanceInternal::IsSetItemSupported(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_SetItem != NULL ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_sameIRQL
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxWmiInstanceInternal::SetItem(
|
||||
__in ULONG DataItemId,
|
||||
__in ULONG InBufferSize,
|
||||
__in_bcount(InBufferSize) PVOID InBuffer
|
||||
)
|
||||
{
|
||||
return m_SetItem(GetDevice(),
|
||||
this,
|
||||
DataItemId,
|
||||
InBufferSize,
|
||||
InBuffer);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiInstanceInternal::IsExecuteMethodSupported(
|
||||
VOID
|
||||
)
|
||||
|
||||
{
|
||||
return m_ExecuteMethod != NULL ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_sameIRQL
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxWmiInstanceInternal::ExecuteMethod(
|
||||
__in ULONG MethodId,
|
||||
__in ULONG InBufferSize,
|
||||
__inout ULONG OutBufferSize,
|
||||
__drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize))
|
||||
__drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize))
|
||||
PVOID Buffer,
|
||||
__out PULONG BufferUsed
|
||||
)
|
||||
{
|
||||
return m_ExecuteMethod(GetDevice(),
|
||||
this,
|
||||
MethodId,
|
||||
InBufferSize,
|
||||
OutBufferSize,
|
||||
Buffer,
|
||||
BufferUsed);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
fxwmipch.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains header definitions and include files needed by all
|
||||
modules in this directory.
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __FX_WMI_PCH_HPP__
|
||||
#define __FX_WMI_PCH_HPP__
|
||||
|
||||
extern "C" {
|
||||
#include <ntddk.h>
|
||||
}
|
||||
|
||||
#include <fx.hpp>
|
||||
|
||||
#endif // __FX_WMI_PCH_HPP__
|
||||
@@ -0,0 +1,563 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxWmiProvider.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the FxWmiProvider object
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxwmipch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxWmiProvider.tmh"
|
||||
}
|
||||
|
||||
FxWmiProvider::FxWmiProvider(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PWDF_WMI_PROVIDER_CONFIG Config,
|
||||
__in FxDevice* Device
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_WMI_PROVIDER,
|
||||
sizeof(FxWmiProvider),
|
||||
FxDriverGlobals),
|
||||
m_FunctionControl(FxDriverGlobals)
|
||||
{
|
||||
InitializeListHead(&m_ListEntry);
|
||||
InitializeListHead(&m_InstanceListHead);
|
||||
m_NumInstances = 0;
|
||||
|
||||
m_Parent = Device->m_PkgWmi;
|
||||
|
||||
m_EventControlEnabled = FALSE;
|
||||
m_DataBlockControlEnabled = FALSE;
|
||||
m_RemoveGuid = FALSE;
|
||||
|
||||
m_TracingHandle = 0;
|
||||
|
||||
m_Flags = Config->Flags;
|
||||
m_MinInstanceBufferSize = Config->MinInstanceBufferSize;
|
||||
RtlCopyMemory(&m_Guid, &Config->Guid, sizeof(GUID));
|
||||
|
||||
if (Config->EvtWmiProviderFunctionControl != NULL) {
|
||||
m_FunctionControl.m_Method = Config->EvtWmiProviderFunctionControl;
|
||||
}
|
||||
|
||||
//
|
||||
// Driver cannot call WdfObjectDelete on this handle
|
||||
//
|
||||
MarkNoDeleteDDI();
|
||||
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
}
|
||||
|
||||
FxWmiProvider::~FxWmiProvider()
|
||||
{
|
||||
ASSERT(IsListEmpty(&m_ListEntry));
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWmiProvider::Dispose(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Object is being deleted, remove this object from the irp handler's list
|
||||
// of providers. If we don't do this, the irp handler will have a list
|
||||
// which contains entries which have been freed.
|
||||
//
|
||||
m_Parent->RemoveProvider(this);
|
||||
|
||||
return __super::Dispose();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiProvider::_Create(
|
||||
__in PFX_DRIVER_GLOBALS CallersGlobals,
|
||||
__in WDFDEVICE Device,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES ProviderAttributes,
|
||||
__in PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig,
|
||||
__out WDFWMIPROVIDER* WmiProvider,
|
||||
__out FxWmiProvider** Provider
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice* pDevice;
|
||||
FxWmiProvider* pProvider;
|
||||
NTSTATUS status;
|
||||
WDFOBJECT hProvider;
|
||||
GUID zeroGuid;
|
||||
BOOLEAN update;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(CallersGlobals,
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
*Provider = NULL;
|
||||
update = FALSE;
|
||||
|
||||
*WmiProvider = NULL;
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals,
|
||||
ProviderAttributes,
|
||||
FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (WmiProviderConfig->Size != sizeof(WDF_WMI_PROVIDER_CONFIG)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WmiProviderConfig Size 0x%x, expected size 0x%x, %!STATUS!",
|
||||
WmiProviderConfig->Size, sizeof(WDF_WMI_PROVIDER_CONFIG),
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((WmiProviderConfig->Flags & ~WdfWmiProviderValidFlags) != 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Invalid flag(s) set, Flags 0x%x, valid mask 0x%x, %!STATUS!",
|
||||
WmiProviderConfig->Flags, WdfWmiProviderValidFlags,
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((WmiProviderConfig->Flags & WdfWmiProviderTracing) &&
|
||||
(WmiProviderConfig->Flags & ~WdfWmiProviderTracing)) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WdfWmiProviderTracing must be the only flag set, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Function control makes sense if it is expensive. Otherwise you will
|
||||
// not be called back on it.
|
||||
//
|
||||
// The opposite, marking yourself as expensive but providing no callback is
|
||||
// OK b/c the provider marks the enabled state and the driver can retrieve
|
||||
// it at runtime.
|
||||
//
|
||||
// Function control also applies to tracing GUIDs since the tracing subsystem
|
||||
// will call enable/disable events to start/stop tracing.
|
||||
//
|
||||
if (WmiProviderConfig->EvtWmiProviderFunctionControl != NULL &&
|
||||
((WmiProviderConfig->Flags & (WdfWmiProviderTracing | WdfWmiProviderExpensive)) == 0)) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"EvtWmiProviderFunctionControl can only be set if Flags 0x%x has "
|
||||
"WdfWmiProviderTracing (%d) or WdfWmiProviderExpensive (%d) bit "
|
||||
"values set, %!STATUS!",
|
||||
WmiProviderConfig->Flags, WdfWmiProviderTracing,
|
||||
WdfWmiProviderExpensive, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
RtlZeroMemory(&zeroGuid, sizeof(zeroGuid));
|
||||
|
||||
if (RtlCompareMemory(&WmiProviderConfig->Guid,
|
||||
&zeroGuid,
|
||||
sizeof(GUID)) == sizeof(GUID)) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"WmiProvider Guid filed is all zeros, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
pProvider = NULL;
|
||||
|
||||
pProvider = new(pFxDriverGlobals, ProviderAttributes)
|
||||
FxWmiProvider(pFxDriverGlobals, WmiProviderConfig, pDevice);
|
||||
|
||||
if (pProvider == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Could not allocate memory for a WDFWMIPROVIDER, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pDevice->m_PkgWmi->AddProvider(pProvider, &update);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = pProvider->Commit(ProviderAttributes, &hProvider, pDevice);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pDevice->m_PkgWmi->RemoveProvider(pProvider);
|
||||
}
|
||||
else {
|
||||
//
|
||||
// NT_SUCCES(status) case
|
||||
//
|
||||
*WmiProvider = (WDFWMIPROVIDER) hProvider;
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*Provider = pProvider;
|
||||
|
||||
if (update) {
|
||||
pDevice->m_PkgWmi->UpdateGuids();
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// AddProvider incremented update count on success however since we
|
||||
// are not going to update registration due to this failure, decrement
|
||||
// the count.
|
||||
//
|
||||
if (update) {
|
||||
pDevice->m_PkgWmi->DecrementUpdateCount();
|
||||
}
|
||||
|
||||
pProvider->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiProvider::AddInstanceLocked(
|
||||
__in FxWmiInstance* Instance,
|
||||
__in BOOLEAN NoErrorIfPresent,
|
||||
__out PBOOLEAN Update,
|
||||
__in AddInstanceAction Action
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
*Update = FALSE;
|
||||
|
||||
if (!IsListEmpty(&Instance->m_ListEntry)) {
|
||||
if (NoErrorIfPresent) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Entry is already on a list, bad caller!
|
||||
//
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFWMIINSTANCE %p already added, %!STATUS!",
|
||||
Instance->GetHandle(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check to see if we are in the process of
|
||||
//
|
||||
switch (m_Parent->m_RegisteredState) {
|
||||
case FxWmiIrpHandler::WmiUnregistered:
|
||||
//
|
||||
// The GUID will be reported when we do the initial registration
|
||||
//
|
||||
break;
|
||||
|
||||
case FxWmiIrpHandler::WmiDeregistered:
|
||||
//
|
||||
// Either the GUID will be reported when we do the re-registration or
|
||||
// we will clean it up when we goto the cleanup state.
|
||||
//
|
||||
break;
|
||||
|
||||
case FxWmiIrpHandler::WmiRegistered:
|
||||
//
|
||||
// Since we already registered we need to tell WMI the change in the
|
||||
// number of instances on this provider.
|
||||
//
|
||||
*Update = TRUE;
|
||||
break;
|
||||
|
||||
case FxWmiIrpHandler::WmiCleanedUp:
|
||||
//
|
||||
// Device is going away, registration is not allowed for the device
|
||||
// anymore.
|
||||
//
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGDEVICE,
|
||||
"WMI is being cleanedup, WDFWMIINSTANCE %p add failing, %!STATUS!",
|
||||
Instance->GetHandle(), status);
|
||||
|
||||
return status;
|
||||
|
||||
default:
|
||||
ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Action == AddInstanceToTail) {
|
||||
InsertTailList(&m_InstanceListHead, &Instance->m_ListEntry);
|
||||
}
|
||||
else {
|
||||
InsertHeadList(&m_InstanceListHead, &Instance->m_ListEntry);
|
||||
}
|
||||
|
||||
//
|
||||
// Since the count is increasing to at least one, we are not going to
|
||||
// need to report this GUID as missing. We could check the
|
||||
// m_Parent->m_RegisteredState and only set it when we are registered, but
|
||||
// it does us no harm to always clear this value regardless of state.
|
||||
//
|
||||
m_RemoveGuid = FALSE;
|
||||
|
||||
m_NumInstances++;
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiProvider::AddInstance(
|
||||
__in FxWmiInstance* Instance,
|
||||
__in BOOLEAN NoErrorIfPresent
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
KIRQL irql;
|
||||
BOOLEAN update;
|
||||
|
||||
if (m_Flags & WdfWmiProviderTracing) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFWMIINSTANCE %p cannot be added to tracing WDFWMIPROVIDER %p, "
|
||||
"%!STATUS!", Instance->GetHandle(), GetHandle(), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
m_Parent->Lock(&irql);
|
||||
status = AddInstanceLocked(Instance, NoErrorIfPresent, &update);
|
||||
|
||||
if (update) {
|
||||
update = m_Parent->DeferUpdateLocked(irql);
|
||||
}
|
||||
m_Parent->Unlock(irql);
|
||||
|
||||
if (update) {
|
||||
m_Parent->UpdateGuids();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxWmiProvider::RemoveInstance(
|
||||
__in FxWmiInstance* Instance
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
BOOLEAN update;
|
||||
|
||||
update = FALSE;
|
||||
|
||||
m_Parent->Lock(&irql);
|
||||
|
||||
if (!IsListEmpty(&Instance->m_ListEntry)) {
|
||||
//
|
||||
// Instance is in the list of instances on this provider. Remove it.
|
||||
//
|
||||
RemoveEntryList(&Instance->m_ListEntry);
|
||||
InitializeListHead(&Instance->m_ListEntry);
|
||||
m_NumInstances--;
|
||||
|
||||
if (m_Parent->m_RegisteredState == FxWmiIrpHandler::WmiRegistered) {
|
||||
update = TRUE;
|
||||
|
||||
//
|
||||
// When the count goes to zero, inform WMI that the GUID should be
|
||||
// removed when we get requeried. We only need to do this once we have
|
||||
// been registered. In all other states, we ignore this value.
|
||||
//
|
||||
if (m_NumInstances == 0 &&
|
||||
(m_Flags & WdfWmiProviderExpensive) == 0) {
|
||||
m_RemoveGuid = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// The instance was explicitly removed and now the instance is trying
|
||||
// to remove itself during dispose. Nothing to do.
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
|
||||
if (update) {
|
||||
update = m_Parent->DeferUpdateLocked(irql);
|
||||
}
|
||||
|
||||
m_Parent->Unlock(irql);
|
||||
|
||||
if (update) {
|
||||
m_Parent->UpdateGuids();
|
||||
}
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxWmiProvider::GetInstanceIndex(
|
||||
__in FxWmiInstance* Instance
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY ple;
|
||||
ULONG index;
|
||||
KIRQL irql;
|
||||
|
||||
m_Parent->Lock(&irql);
|
||||
for (index = 0, ple = m_InstanceListHead.Flink;
|
||||
index < m_NumInstances;
|
||||
index++, ple = ple->Flink) {
|
||||
if (CONTAINING_RECORD(ple, FxWmiInstance, m_ListEntry) == Instance) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_Parent->Unlock(irql);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxWmiInstance*
|
||||
FxWmiProvider::GetInstanceReferenced(
|
||||
__in ULONG Index,
|
||||
__in PVOID Tag
|
||||
)
|
||||
{
|
||||
FxWmiInstance* pInstance;
|
||||
KIRQL irql;
|
||||
|
||||
m_Parent->Lock(&irql);
|
||||
pInstance = GetInstanceReferencedLocked(Index, Tag);
|
||||
m_Parent->Unlock(irql);
|
||||
|
||||
return pInstance;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxWmiInstance*
|
||||
FxWmiProvider::GetInstanceReferencedLocked(
|
||||
__in ULONG Index,
|
||||
__in PVOID Tag
|
||||
)
|
||||
{
|
||||
FxWmiInstance* pFound;
|
||||
PLIST_ENTRY ple;
|
||||
ULONG i;
|
||||
|
||||
pFound = NULL;
|
||||
|
||||
for (i = 0, ple = m_InstanceListHead.Flink;
|
||||
i < m_NumInstances;
|
||||
ple = ple->Flink, i++) {
|
||||
|
||||
if (i == Index) {
|
||||
pFound = CONTAINING_RECORD(ple, FxWmiInstance, m_ListEntry);
|
||||
pFound->ADDREF(Tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pFound;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiProvider::FunctionControl(
|
||||
__in WDF_WMI_PROVIDER_CONTROL Control,
|
||||
__in BOOLEAN Enable
|
||||
)
|
||||
{
|
||||
return m_FunctionControl.Invoke(m_Parent->GetDevice()->GetHandle(),
|
||||
GetHandle(),
|
||||
Control,
|
||||
Enable);
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxWmiProvider::GetRegistrationFlagsLocked(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ULONG flags;
|
||||
|
||||
if (m_Flags & WdfWmiProviderTracing) {
|
||||
flags = WMIREG_FLAG_TRACED_GUID | WMIREG_FLAG_TRACE_CONTROL_GUID;
|
||||
|
||||
//
|
||||
// Once tracing GUID is registered, we do not allow it to be unregistered
|
||||
//
|
||||
ASSERT(m_RemoveGuid == FALSE);
|
||||
}
|
||||
else {
|
||||
flags = WMIREG_FLAG_INSTANCE_PDO;
|
||||
|
||||
if (m_Flags & WdfWmiProviderExpensive) {
|
||||
flags |= WMIREG_FLAG_EXPENSIVE;
|
||||
}
|
||||
|
||||
if (m_Flags & WdfWmiProviderEventOnly) {
|
||||
flags |= WMIREG_FLAG_EVENT_ONLY_GUID;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_RemoveGuid) {
|
||||
//
|
||||
// We have gone down to zero instances of this provider, report it as
|
||||
// gone to WMI.
|
||||
//
|
||||
ASSERT(m_NumInstances == 0);
|
||||
flags |= WMIREG_FLAG_REMOVE_GUID;
|
||||
|
||||
//
|
||||
// Once reported as removed, we do not have not have to report ourselves
|
||||
// as removed again.
|
||||
//
|
||||
m_RemoveGuid = FALSE;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,717 @@
|
||||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <ntddk.h>
|
||||
}
|
||||
|
||||
//
|
||||
// This will cause inclusion of VfWdfFunctions table implementation from header
|
||||
//
|
||||
#define VF_FX_DYNAMICS_GENERATE_TABLE 1
|
||||
|
||||
//
|
||||
// Compute the length based on the max. service name length and the rest of the
|
||||
// error string as seen in ReportDdiFunctionCountMismatch
|
||||
//
|
||||
#define EVTLOG_DDI_COUNT_ERROR_MAX_LEN (53 + MAX_PATH)
|
||||
|
||||
#include "fx.hpp"
|
||||
#include "fxldr.h"
|
||||
#include "FxLibraryCommon.h"
|
||||
#include "FxTelemetry.hpp"
|
||||
#include "WdfVersionLog.h"
|
||||
#include "minwindef.h"
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
// Global triage Info for dbgeng and 0x9F work
|
||||
//
|
||||
static WDFOBJECT_TRIAGE_INFO _WdfObjectTriageInfo = {0};
|
||||
static WDFCONTEXT_TRIAGE_INFO _WdfContextTriageInfo = {0};
|
||||
static WDFCONTEXTTYPE_TRIAGE_INFO _WdfContextTypeTriageInfo = {0};
|
||||
static WDFQUEUE_TRIAGE_INFO _WdfQueueTriageInfo = {0};
|
||||
static WDFIRPQUEUE_TRIAGE_INFO _WdfIrpQueueTriageInfo = {0};
|
||||
static WDFREQUEST_TRIAGE_INFO _WdfRequestTriageInfo = {0};
|
||||
static WDFDEVICE_TRIAGE_INFO _WdfDeviceTriageInfo = {0};
|
||||
static WDFIRP_TRIAGE_INFO _WdfIrpTriageInfo = {0};
|
||||
static WDFFWDPROGRESS_TRIAGE_INFO _WdfFwdProgressTriageInfo = {0};
|
||||
|
||||
WDF_TRIAGE_INFO g_WdfTriageInfo = {
|
||||
//
|
||||
// KMDF Version.
|
||||
//
|
||||
__WDF_MAJOR_VERSION,
|
||||
__WDF_MINOR_VERSION,
|
||||
|
||||
//
|
||||
// Table Version.
|
||||
//
|
||||
WDF_01_TRIAGE_INFO_MAJOR_VERSION,
|
||||
WDF_01_TRIAGE_INFO_MINOR_VERSION,
|
||||
|
||||
//
|
||||
// Reserved ptr (set to NULL).
|
||||
//
|
||||
NULL,
|
||||
|
||||
//
|
||||
// WDF objects triage info.
|
||||
//
|
||||
&_WdfObjectTriageInfo,
|
||||
&_WdfContextTriageInfo,
|
||||
&_WdfContextTypeTriageInfo,
|
||||
&_WdfQueueTriageInfo,
|
||||
&_WdfFwdProgressTriageInfo,
|
||||
&_WdfIrpQueueTriageInfo,
|
||||
&_WdfRequestTriageInfo,
|
||||
&_WdfDeviceTriageInfo,
|
||||
&_WdfIrpTriageInfo,
|
||||
};
|
||||
} // extern "C"
|
||||
|
||||
VOID
|
||||
GetTriageInfo(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
// Object
|
||||
_WdfObjectTriageInfo.RawObjectSize = sizeof(FxObject);
|
||||
_WdfObjectTriageInfo.ObjectType = FIELD_OFFSET(FxObject, m_Type);
|
||||
_WdfObjectTriageInfo.TotalObjectSize = FIELD_OFFSET(FxObject, m_ObjectSize);
|
||||
_WdfObjectTriageInfo.ChildListHead = FIELD_OFFSET(FxObject, m_ChildListHead);
|
||||
_WdfObjectTriageInfo.ChildEntry = FIELD_OFFSET(FxObject, m_ChildEntry);
|
||||
_WdfObjectTriageInfo.Globals = FIELD_OFFSET(FxObject, m_Globals);
|
||||
_WdfObjectTriageInfo.ParentObject = FIELD_OFFSET(FxObject, m_ParentObject);
|
||||
|
||||
// Context Triage Info
|
||||
_WdfContextTriageInfo.HeaderSize = sizeof(FxContextHeader);
|
||||
_WdfContextTriageInfo.NextHeader = FIELD_OFFSET(FxContextHeader, NextHeader);
|
||||
_WdfContextTriageInfo.Object = FIELD_OFFSET(FxContextHeader, Object);
|
||||
_WdfContextTriageInfo.TypeInfoPtr = FIELD_OFFSET(FxContextHeader, ContextTypeInfo);
|
||||
_WdfContextTriageInfo.Context = FIELD_OFFSET(FxContextHeader, Context);
|
||||
|
||||
// Context type Triage info
|
||||
_WdfContextTypeTriageInfo.TypeInfoSize = sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO);
|
||||
_WdfContextTypeTriageInfo.ContextSize = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextSize);
|
||||
_WdfContextTypeTriageInfo.ContextName = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextName);
|
||||
|
||||
// WdfRequest Queue
|
||||
_WdfQueueTriageInfo.QueueSize = sizeof(FxIoQueue);
|
||||
_WdfQueueTriageInfo.IrpQueue1 = FIELD_OFFSET(FxIoQueue, m_Queue);
|
||||
_WdfQueueTriageInfo.IrpQueue2 = FIELD_OFFSET(FxIoQueue, m_DriverCancelable);
|
||||
_WdfQueueTriageInfo.RequestList1 = FIELD_OFFSET(FxIoQueue, m_Cancelled);
|
||||
_WdfQueueTriageInfo.RequestList2 = FIELD_OFFSET(FxIoQueue, m_CanceledOnQueueList);
|
||||
_WdfQueueTriageInfo.FwdProgressContext = FIELD_OFFSET(FxIoQueue, m_FwdProgContext);
|
||||
_WdfQueueTriageInfo.PkgIo = FIELD_OFFSET(FxIoQueue, m_PkgIo);
|
||||
|
||||
// Forward Progress
|
||||
_WdfFwdProgressTriageInfo.ReservedRequestList =
|
||||
FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestList);
|
||||
_WdfFwdProgressTriageInfo.ReservedRequestInUseList =
|
||||
FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestInUseList);
|
||||
_WdfFwdProgressTriageInfo.PendedIrpList =
|
||||
FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_PendedIrpList);
|
||||
|
||||
// Irp Queue
|
||||
_WdfIrpQueueTriageInfo.IrpQueueSize = sizeof(FxIrpQueue);
|
||||
_WdfIrpQueueTriageInfo.IrpListHeader = FIELD_OFFSET(FxIrpQueue, m_Queue);
|
||||
_WdfIrpQueueTriageInfo.IrpListEntry = FIELD_OFFSET(IRP, Tail.Overlay.ListEntry);
|
||||
_WdfIrpQueueTriageInfo.IrpContext = FIELD_OFFSET(IRP,
|
||||
Tail.Overlay.DriverContext[FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY]);
|
||||
|
||||
// WdfRequest
|
||||
_WdfRequestTriageInfo.RequestSize = sizeof(FxRequest);
|
||||
_WdfRequestTriageInfo.CsqContext = FIELD_OFFSET(FxRequest, m_CsqContext);
|
||||
_WdfRequestTriageInfo.FxIrp = FIELD_OFFSET(FxRequest, m_Irp);
|
||||
_WdfRequestTriageInfo.ListEntryQueueOwned =
|
||||
FIELD_OFFSET(FxRequest, m_OwnerListEntry);
|
||||
_WdfRequestTriageInfo.ListEntryQueueOwned2 =
|
||||
FIELD_OFFSET(FxRequest, m_OwnerListEntry2);
|
||||
_WdfRequestTriageInfo.RequestListEntry =
|
||||
FIELD_OFFSET(FxRequest, m_ListEntry);
|
||||
_WdfRequestTriageInfo.FwdProgressList =
|
||||
FIELD_OFFSET(FxRequest, m_ForwardProgressList);
|
||||
|
||||
// WdfDevice
|
||||
_WdfDeviceTriageInfo.DeviceInitSize = sizeof(WDFDEVICE_INIT);
|
||||
_WdfDeviceTriageInfo.DeviceDriver = FIELD_OFFSET(FxDevice, m_Driver);
|
||||
|
||||
// FxIrp
|
||||
_WdfIrpTriageInfo.FxIrpSize = sizeof(FxIrp);
|
||||
_WdfIrpTriageInfo.IrpPtr = FIELD_OFFSET(FxIrp, m_Irp);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
IsClientInfoValid(
|
||||
_In_ PCLIENT_INFO ClientInfo
|
||||
)
|
||||
{
|
||||
if (ClientInfo == NULL ||
|
||||
ClientInfo->Size != sizeof(CLIENT_INFO) ||
|
||||
ClientInfo->RegistryPath == NULL ||
|
||||
ClientInfo->RegistryPath->Length == 0 ||
|
||||
ClientInfo->RegistryPath->Buffer == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
ReportDdiFunctionCountMismatch(
|
||||
_In_ PCUNICODE_STRING ServiceName,
|
||||
_In_ ULONG ActualFunctionCount,
|
||||
_In_ ULONG ExpectedFunctionCount
|
||||
)
|
||||
{
|
||||
WCHAR insertString[EVTLOG_DDI_COUNT_ERROR_MAX_LEN] = { 0 };
|
||||
NTSTATUS status;
|
||||
|
||||
//
|
||||
// NOTE: Any single call to DbgPrintEx will only transmit 512 bytes of
|
||||
// information.
|
||||
//
|
||||
DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL,
|
||||
"\n\n************************* \n"
|
||||
"* DDI function table mismatch detected in KMDF driver. The \n"
|
||||
"* driver will not load until it is re-compiled using a \n"
|
||||
"* newer version of the Windows Driver Kit (WDK). \n"
|
||||
);
|
||||
|
||||
DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL,
|
||||
"* Service name : %wZ\n"
|
||||
"* Actual function table count : %d \n"
|
||||
"* Expected function table count: %d \n"
|
||||
"*************************** \n\n",
|
||||
ServiceName,
|
||||
ActualFunctionCount,
|
||||
ExpectedFunctionCount
|
||||
);
|
||||
|
||||
//
|
||||
// Report a warning level ETW event to the system event log. "Wdf01000" is
|
||||
// the listed event provider.
|
||||
//
|
||||
status = RtlStringCchPrintfW(insertString,
|
||||
RTL_NUMBER_OF(insertString),
|
||||
L"Service:%wZ Count:Actual %d Expected %d",
|
||||
ServiceName,
|
||||
ActualFunctionCount,
|
||||
ExpectedFunctionCount);
|
||||
if (NT_SUCCESS(status)) {
|
||||
LibraryLogEvent(FxLibraryGlobals.DriverObject,
|
||||
WDFVER_CLIENT_INVALID_DDI_COUNT,
|
||||
STATUS_INVALID_PARAMETER,
|
||||
insertString,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
//
|
||||
// Report a telemetry event that can be used to proactively fix drivers
|
||||
//
|
||||
TraceLoggingWrite(g_TelemetryProvider,
|
||||
"KmdfClientFunctionCountMismatch",
|
||||
WDF_TELEMETRY_EVT_KEYWORDS,
|
||||
TraceLoggingUnicodeString(ServiceName, "ServiceName"),
|
||||
TraceLoggingUInt32(ActualFunctionCount, "FunctionCount"),
|
||||
TraceLoggingUInt32(ExpectedFunctionCount, "ExpectedCount"));
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCommonCommission(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
DECLARE_CONST_UNICODE_STRING(usName, L"RtlGetVersion");
|
||||
PFN_RTL_GET_VERSION pRtlGetVersion = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
__Print((LITERAL(WDF_LIBRARY_COMMISSION) "\n"));
|
||||
|
||||
//
|
||||
// Commission this version's DLL globals.
|
||||
//
|
||||
status = FxLibraryGlobalsCommission();
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
__Print(("FxLibraryGlobalsCommission failed %X\n", status));
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// register telemetry provider.
|
||||
//
|
||||
RegisterTelemetryProvider();
|
||||
|
||||
//
|
||||
// Initialize internal WPP tracing.
|
||||
//
|
||||
status = FxTraceInitialize();
|
||||
if (NT_SUCCESS(status)) {
|
||||
FxLibraryGlobals.InternalTracingInitialized = TRUE;
|
||||
}
|
||||
else {
|
||||
__Print(("Failed to initialize tracing for WDF\n"));
|
||||
|
||||
//
|
||||
// Failure to initialize is not critical enough to fail driver load.
|
||||
//
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Attempt to load RtlGetVersion (works for > w2k).
|
||||
//
|
||||
pRtlGetVersion = (PFN_RTL_GET_VERSION) MmGetSystemRoutineAddress(
|
||||
(PUNICODE_STRING) &usName
|
||||
);
|
||||
|
||||
//
|
||||
// Now attempt to get this OS's version.
|
||||
//
|
||||
if (pRtlGetVersion != NULL) {
|
||||
pRtlGetVersion(&gOsVersion);
|
||||
}
|
||||
|
||||
__Print(("OsVersion(%d.%d)\n",
|
||||
gOsVersion.dwMajorVersion,
|
||||
gOsVersion.dwMinorVersion ));
|
||||
|
||||
//
|
||||
// Init triage info for 9f bugcheck analysis.
|
||||
//
|
||||
GetTriageInfo();
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCommonDecommission(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
__Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": enter\n"));
|
||||
|
||||
//
|
||||
// Uninitialize WPP tracing.
|
||||
//
|
||||
if (FxLibraryGlobals.InternalTracingInitialized) {
|
||||
TraceUninitialize();
|
||||
FxLibraryGlobals.InternalTracingInitialized = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Unregister telemetry provider.
|
||||
//
|
||||
UnregisterTelemetryProvider();
|
||||
|
||||
EventUnregisterMicrosoft_Windows_DriverFrameworks_KernelMode_Performance();
|
||||
|
||||
//
|
||||
// Decommission this version's DLL globals.
|
||||
//
|
||||
FxLibraryGlobalsDecommission();
|
||||
|
||||
//
|
||||
// Note: This is the absolute last action from WDF library (dynamic or static).
|
||||
// The image is likely to be deleted after returning.
|
||||
//
|
||||
__Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": exit\n"));
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCommonRegisterClient(
|
||||
__inout PWDF_BIND_INFO Info,
|
||||
__deref_out PWDF_DRIVER_GLOBALS *WdfDriverGlobals,
|
||||
__in_opt PCLIENT_INFO ClientInfo
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
UNICODE_STRING serviceName = { 0 };
|
||||
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n"));
|
||||
|
||||
if (Info == NULL || WdfDriverGlobals == NULL || Info->FuncTable == NULL) {
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
|
||||
": NULL parameter -- %s\n",
|
||||
(Info == NULL) ? "PWDF_BIND_INFO" :
|
||||
(WdfDriverGlobals == NULL) ? "PWDF_DRIVER_GLOBALS *" :
|
||||
(Info->FuncTable == NULL) ? "PWDF_BIND_INFO->FuncTable" :
|
||||
"unknown" ));
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ASSERT(Info->FuncCount);
|
||||
|
||||
|
||||
*WdfDriverGlobals = NULL;
|
||||
|
||||
//
|
||||
// WdfVersion.Count is initialized in FxDynamics.h and is never changed.
|
||||
// Prefast is unable to make that determination.
|
||||
//
|
||||
__assume(WdfVersion.FuncCount == sizeof(WDFFUNCTIONS)/sizeof(PVOID));
|
||||
|
||||
if (Info->FuncCount > WdfVersion.FuncCount) {
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
|
||||
": version mismatch detected in function table count: client"
|
||||
"has 0x%x, library has 0x%x\n",
|
||||
Info->FuncCount, WdfVersion.FuncCount));
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_15) {
|
||||
//
|
||||
// Make sure table count matches exactly with previously
|
||||
// released framework version table sizes.
|
||||
//
|
||||
switch (Info->FuncCount) {
|
||||
|
||||
case WdfFunctionTableNumEntries_V1_15:
|
||||
case WdfFunctionTableNumEntries_V1_13:
|
||||
case WdfFunctionTableNumEntries_V1_11:
|
||||
case WdfFunctionTableNumEntries_V1_9:
|
||||
// case WdfFunctionTableNumEntries_V1_7: // both 1.7 and 1.5 have 387 functions
|
||||
case WdfFunctionTableNumEntries_V1_5:
|
||||
case WdfFunctionTableNumEntries_V1_1:
|
||||
case WdfFunctionTableNumEntries_V1_0:
|
||||
break;
|
||||
|
||||
default:
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
|
||||
": Function table count 0x%x doesn't match any previously "
|
||||
"released framework version table size\n",
|
||||
Info->FuncCount));
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Client version is same as framework version. Make
|
||||
// sure table count is exact.
|
||||
if (Info->FuncCount != WdfFunctionTableNumEntries) {
|
||||
RtlZeroMemory(&serviceName, sizeof(UNICODE_STRING));
|
||||
|
||||
if (IsClientInfoValid(ClientInfo)) {
|
||||
GetNameFromPath(ClientInfo->RegistryPath, &serviceName);
|
||||
}
|
||||
else {
|
||||
RtlInitUnicodeString(&serviceName, L"Unknown");
|
||||
}
|
||||
|
||||
//
|
||||
// Report a DbgPrint message, telemetry event and an ETW event that
|
||||
// will serve as diagnostic aid.
|
||||
//
|
||||
ReportDdiFunctionCountMismatch((PCUNICODE_STRING)&serviceName,
|
||||
Info->FuncCount,
|
||||
WdfFunctionTableNumEntries);
|
||||
|
||||
//
|
||||
// If loader diagnostics are enabled and KD is connected, break-in
|
||||
//
|
||||
if (WdfLdrDbgPrintOn && KD_DEBUGGER_ENABLED &&
|
||||
!KD_DEBUGGER_NOT_PRESENT) {
|
||||
DbgBreakPoint();
|
||||
}
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate an new FxDriverGlobals area for this driver.
|
||||
//
|
||||
*WdfDriverGlobals = FxAllocateDriverGlobals();
|
||||
|
||||
if (*WdfDriverGlobals) {
|
||||
BOOLEAN isFunctinTableHookingOn = FALSE;
|
||||
BOOLEAN isPerformanceAnalysisOn = FALSE;
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals = NULL;
|
||||
|
||||
//
|
||||
// Check the registry to see if Enhanced verifier is on for this driver.
|
||||
// if registry read fails, options value remains unchanged.
|
||||
// store enhanced verifier options in driver globals
|
||||
//
|
||||
fxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals);
|
||||
GetEnhancedVerifierOptions(ClientInfo, &fxDriverGlobals->FxEnhancedVerifierOptions);
|
||||
isFunctinTableHookingOn = IsFxVerifierFunctionTableHooking(fxDriverGlobals);
|
||||
isPerformanceAnalysisOn = IsFxPerformanceAnalysis(fxDriverGlobals);
|
||||
|
||||
//
|
||||
// Set-up the function table. Enhanced verifier and Performance analysis is off by default.
|
||||
//
|
||||
if (isFunctinTableHookingOn == FALSE && isPerformanceAnalysisOn == FALSE) {
|
||||
|
||||
//
|
||||
// Starting in 1.15 we reference a copy of the DDI table in WDF01000,
|
||||
// prior to that we copy the entire table to local memory.
|
||||
//
|
||||
if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_13) {
|
||||
RtlCopyMemory( Info->FuncTable,
|
||||
&WdfVersion.Functions,
|
||||
Info->FuncCount * sizeof(PVOID) );
|
||||
}
|
||||
else {
|
||||
//
|
||||
// FuncTable arrives with a ptr to &WdfFunctions, so we update
|
||||
// what WdfFunctions points to.
|
||||
//
|
||||
*((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &WdfVersion.Functions;
|
||||
}
|
||||
}
|
||||
else {
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
|
||||
": Enhanced Verification is ON \n"));
|
||||
|
||||
LockVerifierSection(fxDriverGlobals, ClientInfo->RegistryPath);
|
||||
|
||||
if (Microsoft_Windows_DriverFrameworks_KernelMode_PerformanceHandle == NULL) {
|
||||
EventRegisterMicrosoft_Windows_DriverFrameworks_KernelMode_Performance();
|
||||
}
|
||||
|
||||
//
|
||||
// Enhanced verification is on. Return verifier function table
|
||||
//
|
||||
// Starting in 1.15 we reference a copy of the DDI table in WDF01000,
|
||||
// prior to that we copy the entire table to local memory.
|
||||
//
|
||||
if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_13) {
|
||||
RtlCopyMemory( Info->FuncTable,
|
||||
&VfWdfVersion.Functions,
|
||||
Info->FuncCount * sizeof(PVOID) );
|
||||
}
|
||||
else {
|
||||
//
|
||||
// FuncTable arrives with a ptr to &WdfFunctions, so we update
|
||||
// what WdfFunctions points to.
|
||||
//
|
||||
*((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &VfWdfVersion.Functions;
|
||||
}
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
|
||||
": WdfFunctions %p\n", Info->FuncTable));
|
||||
}
|
||||
|
||||
Done:
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
|
||||
": exit: status %X\n", status));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLibraryCommonUnregisterClient(
|
||||
__in PWDF_BIND_INFO Info,
|
||||
__in PWDF_DRIVER_GLOBALS WdfDriverGlobals
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
__Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT) ": enter\n"));
|
||||
|
||||
ASSERT(Info);
|
||||
ASSERT(WdfDriverGlobals);
|
||||
|
||||
if (Info != NULL && WdfDriverGlobals != NULL) {
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(WdfDriverGlobals);
|
||||
|
||||
//
|
||||
// Destroy this FxDriver instance, if its still indicated.
|
||||
//
|
||||
if (pFxDriverGlobals->Driver != NULL) {
|
||||
//
|
||||
// Association support, we are a root with no parent
|
||||
//
|
||||
pFxDriverGlobals->Driver->DeleteObject();
|
||||
|
||||
FxDestroy(pFxDriverGlobals);
|
||||
}
|
||||
|
||||
//
|
||||
// Stop IFR logging
|
||||
//
|
||||
FxIFRStop(pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// unlock enhanced-verifier image sections
|
||||
//
|
||||
if (IsFxVerifierFunctionTableHooking(pFxDriverGlobals)) {
|
||||
UnlockVerifierSection(pFxDriverGlobals);
|
||||
}
|
||||
|
||||
//
|
||||
// This will free the client's FxDriverGlobals area
|
||||
//
|
||||
FxFreeDriverGlobals(WdfDriverGlobals);
|
||||
}
|
||||
else {
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
__Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT)
|
||||
": exit: status %X\n", status));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
GetEnhancedVerifierOptions(
|
||||
__in PCLIENT_INFO ClientInfo,
|
||||
__out PULONG Options
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG value;
|
||||
FxAutoRegKey hKey, hWdf;
|
||||
DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf");
|
||||
DECLARE_CONST_UNICODE_STRING(valueName, WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME);
|
||||
|
||||
*Options = 0;
|
||||
if (!IsClientInfoValid(ClientInfo) ||
|
||||
Options == NULL) {
|
||||
|
||||
__Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT)
|
||||
": Invalid ClientInfo received from wdfldr \n"));
|
||||
return;
|
||||
}
|
||||
|
||||
status = FxRegKey::_OpenKey(NULL,
|
||||
ClientInfo->RegistryPath,
|
||||
&hWdf.m_Key,
|
||||
KEY_READ);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = FxRegKey::_OpenKey(hWdf.m_Key,
|
||||
¶metersPath,
|
||||
&hKey.m_Key,
|
||||
KEY_READ);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = FxRegKey::_QueryULong(
|
||||
hKey.m_Key, &valueName, &value);
|
||||
|
||||
//
|
||||
// Examine key values and set Options only on success.
|
||||
//
|
||||
if (NT_SUCCESS(status)) {
|
||||
if (value) {
|
||||
*Options = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
LibraryLogEvent(
|
||||
__in PDRIVER_OBJECT DriverObject,
|
||||
__in NTSTATUS ErrorCode,
|
||||
__in NTSTATUS FinalStatus,
|
||||
__in PWSTR ErrorInsertionString,
|
||||
__in_bcount(RawDataLen) PVOID RawDataBuf,
|
||||
__in USHORT RawDataLen
|
||||
)
|
||||
/*++
|
||||
|
||||
|
||||
Routine Description:
|
||||
|
||||
Logs an error to the system event log.
|
||||
|
||||
Arguments:
|
||||
|
||||
DriverObject - Pointer to driver object reporting the error.
|
||||
|
||||
ErrorCode - Indicates the type of error, system or driver-defined.
|
||||
|
||||
ErrorInsertionString - Null-terminated Unicode string inserted into error
|
||||
description, as defined by error code.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||||
size_t errorLogEntrySize; // [including null]
|
||||
size_t errorInsertionStringByteSize = 0;
|
||||
|
||||
if (ErrorInsertionString) {
|
||||
errorInsertionStringByteSize = wcslen(ErrorInsertionString) * sizeof(WCHAR);
|
||||
errorInsertionStringByteSize += sizeof(UNICODE_NULL);
|
||||
}
|
||||
|
||||
errorLogEntrySize = sizeof(IO_ERROR_LOG_PACKET) + RawDataLen + errorInsertionStringByteSize;
|
||||
|
||||
//
|
||||
// Log an error.
|
||||
//
|
||||
//
|
||||
// prefast complains about comparison of constant with constant here
|
||||
//
|
||||
#pragma prefast(suppress:__WARNING_CONST_CONST_COMP, "If ErrorInsertionString is not null then this is not a constant")
|
||||
if (errorLogEntrySize <= ERROR_LOG_MAXIMUM_SIZE) {
|
||||
|
||||
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DriverObject,
|
||||
(UCHAR)errorLogEntrySize);
|
||||
|
||||
if (errorLogEntry != NULL) {
|
||||
|
||||
RtlZeroMemory(errorLogEntry, errorLogEntrySize);
|
||||
|
||||
errorLogEntry->ErrorCode = ErrorCode;
|
||||
errorLogEntry->FinalStatus = FinalStatus;
|
||||
errorLogEntry->NumberOfStrings = (ErrorInsertionString) ? 1 : 0;
|
||||
errorLogEntry->DumpDataSize = RawDataLen;
|
||||
errorLogEntry->StringOffset = (FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)) + errorLogEntry->DumpDataSize;
|
||||
|
||||
//
|
||||
// Insertion strings follow dumpdata and since there is no dumpdata we place the
|
||||
// insertion string at the start offset of the dumpdata.
|
||||
//
|
||||
if (RawDataBuf) {
|
||||
RtlCopyMemory(errorLogEntry->DumpData,
|
||||
RawDataBuf,
|
||||
RawDataLen);
|
||||
}
|
||||
|
||||
if (ErrorInsertionString) {
|
||||
RtlCopyMemory(((PCHAR)errorLogEntry->DumpData) + RawDataLen,
|
||||
ErrorInsertionString,
|
||||
errorInsertionStringByteSize);
|
||||
}
|
||||
|
||||
IoWriteErrorLogEntry(errorLogEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxQueryInterface.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the device interface object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxQueryInterface.tmh"
|
||||
}
|
||||
|
||||
FxQueryInterface::FxQueryInterface(
|
||||
__in FxDevice* Device,
|
||||
__in PWDF_QUERY_INTERFACE_CONFIG Config
|
||||
) :
|
||||
m_Device(Device),
|
||||
m_Interface(NULL)
|
||||
{
|
||||
m_Entry.Next = NULL;
|
||||
|
||||
m_EmbeddedInterface = FALSE;
|
||||
|
||||
if (Config != NULL) {
|
||||
m_SendQueryToParentStack = Config->SendQueryToParentStack;
|
||||
m_ImportInterface = Config->ImportInterface;
|
||||
m_ProcessRequest.m_Method = Config->EvtDeviceProcessQueryInterfaceRequest;
|
||||
RtlCopyMemory(&m_InterfaceType, Config->InterfaceType, sizeof(GUID));
|
||||
}
|
||||
}
|
||||
|
||||
FxQueryInterface::~FxQueryInterface()
|
||||
{
|
||||
//
|
||||
// Should not in any list
|
||||
//
|
||||
ASSERT(m_Entry.Next == NULL);
|
||||
|
||||
if (m_Interface != NULL && m_EmbeddedInterface == FALSE) {
|
||||
FxPoolFree(m_Interface);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxQueryInterface::_FormatIrp(
|
||||
__in PIRP Irp,
|
||||
__in const GUID* InterfaceGuid,
|
||||
__out PINTERFACE Interface,
|
||||
__in USHORT InterfaceSize,
|
||||
__in USHORT InterfaceVersion,
|
||||
__in_opt PVOID InterfaceSpecificData
|
||||
)
|
||||
{
|
||||
PIO_STACK_LOCATION stack;
|
||||
|
||||
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
stack = IoGetNextIrpStackLocation(Irp);
|
||||
|
||||
stack->MajorFunction = IRP_MJ_PNP;
|
||||
stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||||
|
||||
stack->Parameters.QueryInterface.Interface = Interface;
|
||||
stack->Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData;
|
||||
stack->Parameters.QueryInterface.Size = InterfaceSize;
|
||||
stack->Parameters.QueryInterface.Version = InterfaceVersion;
|
||||
stack->Parameters.QueryInterface.InterfaceType = InterfaceGuid;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxQueryInterface::_QueryForInterface(
|
||||
__in PDEVICE_OBJECT TopOfStack,
|
||||
__in const GUID* InterfaceType,
|
||||
__out PINTERFACE Interface,
|
||||
__in USHORT Size,
|
||||
__in USHORT Version,
|
||||
__in_opt PVOID InterfaceSpecificData
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Send an IRP_MJPNP/IRP_MN_QUERY_INTERFACE irp to a device object and its
|
||||
attached stack.
|
||||
|
||||
Arguments:
|
||||
TargetDevice - device to send the query to.
|
||||
|
||||
InterfaceType - The type of interface to query for
|
||||
|
||||
Interface - The interface to fill out
|
||||
|
||||
Size - Size of Interface in bytes
|
||||
|
||||
Version - Version of the interface to be queried
|
||||
|
||||
InterfaceSpecificData - Addtional interface data to be queried
|
||||
|
||||
|
||||
Return Value:
|
||||
NTSTATUS as indicated by the handler of the QI with in the device stack,
|
||||
STATUS_NOT_SUPPORTED if the QI is not handled.
|
||||
|
||||
--*/
|
||||
{
|
||||
PIRP pIrp;
|
||||
NTSTATUS status;
|
||||
|
||||
pIrp = IoAllocateIrp(TopOfStack->StackSize, FALSE);
|
||||
|
||||
if (pIrp != NULL) {
|
||||
FxAutoIrp irp(pIrp);
|
||||
|
||||
_FormatIrp(
|
||||
pIrp,
|
||||
InterfaceType,
|
||||
Interface,
|
||||
Size,
|
||||
Version,
|
||||
InterfaceSpecificData
|
||||
);
|
||||
|
||||
status = irp.SendIrpSynchronously(TopOfStack);
|
||||
}
|
||||
else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxQueryInterface::SetEmbedded(
|
||||
__in PWDF_QUERY_INTERFACE_CONFIG Config,
|
||||
__in PINTERFACE Interface
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Marks the structure as embedded and sets the configuration. This is used
|
||||
for FxQueryInterface structs which are embedded in other structures because
|
||||
at contruction time the Config is not available yet.
|
||||
|
||||
By marking as embedded, FxPkgPnp will not free the structure when it deletes
|
||||
the query interface chain.
|
||||
|
||||
Arguments:
|
||||
Config - how the interface behaves
|
||||
|
||||
Interface - the interface that is exported
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
m_EmbeddedInterface = TRUE;
|
||||
m_Interface = Interface;
|
||||
|
||||
m_SendQueryToParentStack = Config->SendQueryToParentStack;
|
||||
m_ImportInterface = Config->ImportInterface;
|
||||
m_ProcessRequest.m_Method = Config->EvtDeviceProcessQueryInterfaceRequest;
|
||||
RtlCopyMemory(&m_InterfaceType, Config->InterfaceType, sizeof(GUID));
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxQueryInterfaceAPI.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the device interface object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxQueryInterfaceAPI.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceAddQueryInterface)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PWDF_QUERY_INTERFACE_CONFIG InterfaceConfig
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxQueryInterface *pQueryInterface;
|
||||
FxDevice *pDevice;
|
||||
PINTERFACE pInterface;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice,
|
||||
&pFxDriverGlobals );
|
||||
|
||||
pQueryInterface = NULL;
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Device);
|
||||
FxPointerNotNull(pFxDriverGlobals, InterfaceConfig);
|
||||
FxPointerNotNull(pFxDriverGlobals, InterfaceConfig->InterfaceType);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
pInterface = InterfaceConfig->Interface;
|
||||
|
||||
if (InterfaceConfig->Size != sizeof(WDF_QUERY_INTERFACE_CONFIG)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p, WDF_QUERY_INTERFACE_CONFIG Size %d, expected %d, "
|
||||
"%!STATUS!", Device, InterfaceConfig->Size,
|
||||
sizeof(WDF_QUERY_INTERFACE_CONFIG), status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
//
|
||||
// A pass through interface is only associated with PDOs
|
||||
//
|
||||
if (InterfaceConfig->SendQueryToParentStack && pDevice->IsPdo() == FALSE) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"SendQueryToParentStack TRUE, but WDFDEVICE %p not a PDO, %!STATUS!",
|
||||
Device, status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
//
|
||||
// The only time we can have a NULL Interface is if the interface is
|
||||
// passthrough or it is an import interface (since on import interfaces
|
||||
// the callback must do the copying).
|
||||
//
|
||||
if (pInterface == NULL) {
|
||||
if (InterfaceConfig->SendQueryToParentStack || InterfaceConfig->ImportInterface) {
|
||||
//
|
||||
// A NULL interface is valid for this config
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
else {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p, SendQueryToParentStack is FALSE and "
|
||||
"InterfaceConfig->ImportInterface is FALSE, %!STATUS!",
|
||||
Device, status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If it is an import interface, we need a callback so that the driver can
|
||||
// modify the interface being returned.
|
||||
//
|
||||
if (InterfaceConfig->ImportInterface &&
|
||||
InterfaceConfig->EvtDeviceProcessQueryInterfaceRequest == NULL) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p, ImportInterface is TRUE and "
|
||||
"EvtDeviceProcessQueryInterfaceRequest is NULL, %!STATUS!",
|
||||
Device, status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (pInterface != NULL) {
|
||||
//
|
||||
// Make sure we are exposing the minimum size
|
||||
//
|
||||
if (pInterface->Size < sizeof(INTERFACE)) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p, Interface size %d < sizeof(INTERFACE) (%d), "
|
||||
"%!STATUS!", Device, pInterface->Size, sizeof(INTERFACE), status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Since the QI irp is only allowed to be sent at passive level and
|
||||
// the list of FxQueryInterface's is locked by a lock which does not
|
||||
// raise IRQL, we can allocate the structure out paged pool.
|
||||
//
|
||||
pQueryInterface = new (pFxDriverGlobals, PagedPool)
|
||||
FxQueryInterface(pDevice, InterfaceConfig);
|
||||
|
||||
if (pQueryInterface == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p, object creation failed, %!STATUS!", Device, status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (pInterface != NULL) {
|
||||
//
|
||||
// Try to allocate memory for the interface.
|
||||
//
|
||||
pQueryInterface->m_Interface = (PINTERFACE)
|
||||
FxPoolAllocate(pFxDriverGlobals, PagedPool, pInterface->Size);
|
||||
|
||||
if (pQueryInterface->m_Interface == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p, interface allocation failed, %!STATUS!",
|
||||
Device, status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
RtlCopyMemory(pQueryInterface->m_Interface,
|
||||
pInterface,
|
||||
pInterface->Size);
|
||||
|
||||
if (pInterface->InterfaceReference == NULL) {
|
||||
pQueryInterface->m_Interface->InterfaceReference =
|
||||
FxDevice::_InterfaceReferenceNoOp;
|
||||
}
|
||||
if (pInterface->InterfaceDereference == NULL) {
|
||||
pQueryInterface->m_Interface->InterfaceDereference =
|
||||
FxDevice::_InterfaceDereferenceNoOp;
|
||||
}
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
pDevice->m_PkgPnp->AddQueryInterface(pQueryInterface, TRUE);
|
||||
|
||||
Done:
|
||||
//
|
||||
// Delete the query interface structure if there is an error.
|
||||
//
|
||||
if (!NT_SUCCESS(status) && pQueryInterface != NULL) {
|
||||
delete pQueryInterface;
|
||||
pQueryInterface = NULL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,44 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRelatedDevice.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the FxRelatedDevice class which is used in usage
|
||||
notification propagation
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
FxRelatedDevice::FxRelatedDevice(
|
||||
__in PDEVICE_OBJECT DeviceObject,
|
||||
__in PFX_DRIVER_GLOBALS Globals
|
||||
) : FxObject(FX_TYPE_RELATED_DEVICE, 0, Globals),
|
||||
m_DeviceObject(DeviceObject),
|
||||
m_State(RelatedDeviceStateNeedsReportPresent)
|
||||
{
|
||||
m_TransactionedEntry.SetTransactionedObject(this);
|
||||
ObReferenceObject(m_DeviceObject);
|
||||
}
|
||||
|
||||
FxRelatedDevice::~FxRelatedDevice(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ObDereferenceObject(m_DeviceObject);
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDependentList.cpp
|
||||
|
||||
Abstract:
|
||||
This object derives from the transactioned list and provides a unique
|
||||
object check during the addition of an item.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRelatedDeviceList::Add(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__inout FxRelatedDevice* Entry
|
||||
)
|
||||
{
|
||||
return FxSpinLockTransactionedList::Add(FxDriverGlobals,
|
||||
&Entry->m_TransactionedEntry);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRelatedDeviceList::Remove(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PDEVICE_OBJECT Device
|
||||
)
|
||||
{
|
||||
SearchForAndRemove(FxDriverGlobals, (PVOID) Device);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxRelatedDevice*
|
||||
FxRelatedDeviceList::GetNextEntry(
|
||||
__in_opt FxRelatedDevice* Entry
|
||||
)
|
||||
{
|
||||
FxTransactionedEntry *pReturn, *pEntry;
|
||||
|
||||
if (Entry == NULL) {
|
||||
pEntry = NULL;
|
||||
}
|
||||
else {
|
||||
pEntry = &Entry->m_TransactionedEntry;
|
||||
}
|
||||
|
||||
pReturn = FxSpinLockTransactionedList::GetNextEntry(pEntry);
|
||||
|
||||
if (pReturn != NULL) {
|
||||
return CONTAINING_RECORD(pReturn, FxRelatedDevice, m_TransactionedEntry);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRelatedDeviceList::ProcessAdd(
|
||||
__in FxTransactionedEntry *NewEntry
|
||||
)
|
||||
{
|
||||
FxRelatedDevice* pNew, *pInList;
|
||||
FxTransactionedEntry *pEntry;
|
||||
PLIST_ENTRY ple;
|
||||
|
||||
pNew = CONTAINING_RECORD(NewEntry, FxRelatedDevice, m_TransactionedEntry);
|
||||
|
||||
pEntry = NULL;
|
||||
|
||||
//
|
||||
// Go over the transactions first because the device could be in the real
|
||||
// list with a transaction to remove it, so we catch first here instead
|
||||
// of adding complexity to the iteration of the already inserted list.
|
||||
//
|
||||
for (ple = m_TransactionHead.Flink;
|
||||
ple != &m_TransactionHead;
|
||||
ple = ple->Flink) {
|
||||
pEntry = FxTransactionedEntry::_FromEntry(ple);
|
||||
pInList = CONTAINING_RECORD(pEntry, FxRelatedDevice, m_TransactionedEntry);
|
||||
|
||||
if (pInList->m_DeviceObject == pNew->m_DeviceObject) {
|
||||
if (pEntry->GetTransactionAction() == FxTransactionActionAdd) {
|
||||
//
|
||||
// An additional add, failure
|
||||
//
|
||||
return STATUS_DUPLICATE_OBJECTID;
|
||||
}
|
||||
|
||||
|
||||
// Removal is OK b/c our add will be right behind it
|
||||
//
|
||||
ASSERT(pEntry->GetTransactionAction() == FxTransactionActionRemove);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
pEntry = NULL;
|
||||
while ((pEntry = __super::GetNextEntryLocked(pEntry)) != NULL) {
|
||||
pInList = CONTAINING_RECORD(pEntry, FxRelatedDevice, m_TransactionedEntry);
|
||||
|
||||
if (pInList->m_DeviceObject == pNew->m_DeviceObject) {
|
||||
return STATUS_DUPLICATE_OBJECTID;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxRelatedDeviceList::Compare(
|
||||
__in FxTransactionedEntry* Entry,
|
||||
__in PVOID Data
|
||||
)
|
||||
{
|
||||
FxRelatedDevice *pRelated;
|
||||
|
||||
pRelated = CONTAINING_RECORD(Entry, FxRelatedDevice, m_TransactionedEntry);
|
||||
|
||||
return pRelated->GetDevice() == (PDEVICE_OBJECT) Data ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRelatedDeviceList::EntryRemoved(
|
||||
__in FxTransactionedEntry* Entry
|
||||
)
|
||||
{
|
||||
FxRelatedDevice *pRelated;
|
||||
|
||||
pRelated = CONTAINING_RECORD(Entry, FxRelatedDevice, m_TransactionedEntry);
|
||||
|
||||
if (pRelated->m_State == RelatedDeviceStateReportedPresent) {
|
||||
m_NeedReportMissing++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
fxsupportpch.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains header definitions and include files needed by all
|
||||
modules in fx\support
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __FX_SUPPORT_PCH_HPP__
|
||||
#define __FX_SUPPORT_PCH_HPP__
|
||||
|
||||
extern "C" {
|
||||
#include <ntddk.h>
|
||||
}
|
||||
|
||||
#include <fx.hpp>
|
||||
|
||||
#endif // __FX_SUPPORT_PCH_HPP__
|
||||
@@ -0,0 +1,79 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
ProbeAndLock.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains C routines for probing and locking
|
||||
down memory buffers.
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
//
|
||||
// These routines must be implemented in a C file to avoid problems
|
||||
// with C++ exception handling errors.
|
||||
//
|
||||
|
||||
#include <ntddk.h>
|
||||
|
||||
NTSTATUS
|
||||
FxProbeAndLockForRead(
|
||||
__in PMDL Mdl,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
try {
|
||||
MmProbeAndLockPages(Mdl, AccessMode, IoReadAccess);
|
||||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
return GetExceptionCode();
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxProbeAndLockForWrite(
|
||||
__in PMDL Mdl,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
try {
|
||||
MmProbeAndLockPages(Mdl, AccessMode, IoWriteAccess);
|
||||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
return GetExceptionCode();
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxProbeAndLockWithAccess(
|
||||
__in PMDL Mdl,
|
||||
__in KPROCESSOR_MODE AccessMode,
|
||||
__in LOCK_OPERATION Operation
|
||||
)
|
||||
{
|
||||
try {
|
||||
MmProbeAndLockPages(Mdl, AccessMode, Operation);
|
||||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
return GetExceptionCode();
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
corepriv.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the main driver framework.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE))
|
||||
#define FX_IS_USER_MODE (TRUE)
|
||||
#define FX_IS_KERNEL_MODE (FALSE)
|
||||
#elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
|
||||
#define FX_IS_USER_MODE (FALSE)
|
||||
#define FX_IS_KERNEL_MODE (TRUE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
extern "C" {
|
||||
#include <ntddk.h>
|
||||
#include "wdf.h"
|
||||
}
|
||||
|
||||
#define WDF_REGISTRY_BASE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wdf"
|
||||
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "mx.h"
|
||||
}
|
||||
|
||||
#include "FxMin.hpp"
|
||||
|
||||
#include "wdfmemory.h"
|
||||
#include "wdfrequest.h"
|
||||
#include "wdfdevice.h"
|
||||
#include "wdfdevicepri.h"
|
||||
#include "wdfiotargetpri.h"
|
||||
#include "wdfwmi.h"
|
||||
#include "wdfChildList.h"
|
||||
#include "wdfpdo.h"
|
||||
#include "wdffdo.h"
|
||||
#include "wdfiotarget.h"
|
||||
#include "wdfcontrol.h"
|
||||
#include "wdfcx.h"
|
||||
#include "wdfio.h"
|
||||
#include "wdfqueryinterface.h"
|
||||
#include "wdftriage.h"
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
#include "FxIrpUm.hpp"
|
||||
#else
|
||||
#include "FxIrpKm.hpp"
|
||||
#endif
|
||||
|
||||
// <FxSystemWorkItem.hpp>
|
||||
typedef
|
||||
VOID
|
||||
(*PFN_WDF_SYSTEMWORKITEM) (
|
||||
IN PVOID Parameter
|
||||
);
|
||||
|
||||
#include "FxIrpQueue.hpp"
|
||||
|
||||
|
||||
// </FxSystemWorkItem.hpp>
|
||||
|
||||
|
||||
#include "FxProbeAndLock.h"
|
||||
#include "FxPackage.hpp"
|
||||
#include "FxCollection.hpp"
|
||||
#include "FxDeviceInitShared.hpp"
|
||||
|
||||
#include "IfxMemory.hpp"
|
||||
#include "FxCallback.hpp"
|
||||
#include "FxRequestContext.hpp"
|
||||
#include "FxRequestContextTypes.h"
|
||||
#include "FxRequestBase.hpp"
|
||||
#include "FxMemoryObject.hpp"
|
||||
#include "FxMemoryBuffer.hpp"
|
||||
|
||||
#include "FxMemoryBufferFromPool.hpp"
|
||||
|
||||
#include "FxMemoryBufferPreallocated.hpp"
|
||||
|
||||
#include "FxTransactionedList.hpp"
|
||||
|
||||
//
|
||||
// MERGE temp: We may not need these include files here,
|
||||
// temporarily including them to verify they compile in shared code
|
||||
//
|
||||
#include "FxRequestValidateFunctions.hpp"
|
||||
#include "FxRequestCallbacks.hpp"
|
||||
|
||||
// support
|
||||
#include "StringUtil.hpp"
|
||||
#include "FxAutoString.hpp"
|
||||
#include "FxString.hpp"
|
||||
#include "FxDeviceText.hpp"
|
||||
#include "FxCallback.hpp"
|
||||
#include "FxDisposeList.hpp"
|
||||
#include "FxSystemThread.hpp"
|
||||
|
||||
#include "FxIrpPreprocessInfo.hpp"
|
||||
#include "FxPnpCallbacks.hpp"
|
||||
|
||||
// device init
|
||||
#include "FxCxDeviceInit.hpp"
|
||||
#include "FxCxDeviceInfo.hpp"
|
||||
#include "FxDeviceInit.hpp"
|
||||
|
||||
#include "FxDeviceToMxInterface.hpp"
|
||||
|
||||
// request
|
||||
#include "FxRequestMemory.hpp"
|
||||
#include "FxRequest.hpp"
|
||||
#include "FxRequestBuffer.hpp"
|
||||
#include "FxSyncRequest.hpp"
|
||||
|
||||
// io target
|
||||
#include "FxIoTarget.hpp"
|
||||
#include "FxIoTargetSelf.hpp"
|
||||
|
||||
#include "FxSystemWorkItem.hpp"
|
||||
#include "FxCallbackMutexLock.hpp"
|
||||
#include "FxDriver.hpp"
|
||||
|
||||
#include "FxDeviceInterface.hpp"
|
||||
#include "FxQueryInterface.hpp"
|
||||
|
||||
#include "FxCallbackSpinLock.hpp"
|
||||
#include "FxDefaultIrpHandler.hpp"
|
||||
#include "FxWmiIrpHandler.hpp"
|
||||
|
||||
// packages
|
||||
#include "FxPkgIo.hpp"
|
||||
#include "FxPkgPnp.hpp"
|
||||
#include "FxPkgFdo.hpp"
|
||||
#include "FxPkgPdo.hpp"
|
||||
#include "FxPkgGeneral.hpp"
|
||||
#include "FxFileObject.hpp"
|
||||
#include "FxIoQueue.hpp"
|
||||
#include "FxDevice.hpp"
|
||||
#include "FxTelemetry.hpp"
|
||||
|
||||
#include "FxChildList.hpp"
|
||||
|
||||
#include "FxLookasideList.hpp"
|
||||
|
||||
/*#if FX_IS_KERNEL_MODE
|
||||
#include "wdfrequest.h"
|
||||
#endif*/
|
||||
|
||||
//
|
||||
// Versioning of structures for wdfdriver.h
|
||||
//
|
||||
typedef struct _WDF_DRIVER_CONFIG_V1_0 {
|
||||
//
|
||||
// Size of this structure in bytes
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Event callbacks
|
||||
//
|
||||
PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd;
|
||||
|
||||
PFN_WDF_DRIVER_UNLOAD EvtDriverUnload;
|
||||
|
||||
//
|
||||
// Combination of WDF_DRIVER_INIT_FLAGS values
|
||||
//
|
||||
ULONG DriverInitFlags;
|
||||
|
||||
} WDF_DRIVER_CONFIG_V1_0, *PWDF_DRIVER_CONFIG_V1_0;
|
||||
|
||||
//
|
||||
// Versioning of structures for wdfdriver.h
|
||||
//
|
||||
typedef struct _WDF_DRIVER_CONFIG_V1_1 {
|
||||
//
|
||||
// Size of this structure in bytes
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Event callbacks
|
||||
//
|
||||
PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd;
|
||||
|
||||
PFN_WDF_DRIVER_UNLOAD EvtDriverUnload;
|
||||
|
||||
//
|
||||
// Combination of WDF_DRIVER_INIT_FLAGS values
|
||||
//
|
||||
ULONG DriverInitFlags;
|
||||
|
||||
} WDF_DRIVER_CONFIG_V1_1, *PWDF_DRIVER_CONFIG_V1_1;
|
||||
|
||||
|
||||
typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9 {
|
||||
//
|
||||
// Size of this structure in bytes
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Indicates whether the device can wake itself up while the machine is in
|
||||
// S0.
|
||||
//
|
||||
WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps;
|
||||
|
||||
//
|
||||
// The low power state in which the device will be placed when it is idled
|
||||
// out while the machine is in S0.
|
||||
//
|
||||
DEVICE_POWER_STATE DxState;
|
||||
|
||||
//
|
||||
// Amount of time the device must be idle before idling out. Timeout is in
|
||||
// milliseconds.
|
||||
//
|
||||
ULONG IdleTimeout;
|
||||
|
||||
//
|
||||
// Inidcates whether a user can control the idle policy of the device.
|
||||
// By default, a user is allowed to change the policy.
|
||||
//
|
||||
WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings;
|
||||
|
||||
//
|
||||
// If WdfTrue, idling out while the machine is in S0 will be enabled.
|
||||
//
|
||||
// If WdfFalse, idling out will be disabled.
|
||||
//
|
||||
// If WdfUseDefault, the idling out will be enabled. If
|
||||
// UserControlOfIdleSettings is set to IdleAllowUserControl, the user's
|
||||
// settings will override the default.
|
||||
//
|
||||
WDF_TRI_STATE Enabled;
|
||||
|
||||
//
|
||||
// This field is applicable only when IdleCaps == IdleCannotWakeFromS0
|
||||
// If WdfTrue,device is powered up on System Wake even if device is idle
|
||||
// If WdfFalse, device is not powered up on system wake if it is idle
|
||||
// If WdfUseDefault, the behavior is same as WdfFalse
|
||||
//
|
||||
WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake;
|
||||
|
||||
} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9;
|
||||
|
||||
typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7 {
|
||||
//
|
||||
// Size of this structure in bytes
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Indicates whether the device can wake itself up while the machine is in
|
||||
// S0.
|
||||
//
|
||||
WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps;
|
||||
|
||||
//
|
||||
// The low power state in which the device will be placed when it is idled
|
||||
// out while the machine is in S0.
|
||||
//
|
||||
DEVICE_POWER_STATE DxState;
|
||||
|
||||
//
|
||||
// Amount of time the device must be idle before idling out. Timeout is in
|
||||
// milliseconds.
|
||||
//
|
||||
ULONG IdleTimeout;
|
||||
|
||||
//
|
||||
// Inidcates whether a user can control the idle policy of the device.
|
||||
// By default, a user is allowed to change the policy.
|
||||
//
|
||||
WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings;
|
||||
|
||||
//
|
||||
// If WdfTrue, idling out while the machine is in S0 will be enabled.
|
||||
//
|
||||
// If WdfFalse, idling out will be disabled.
|
||||
//
|
||||
// If WdfUseDefault, the idling out will be enabled. If
|
||||
// UserControlOfIdleSettings is set to IdleAllowUserControl, the user's
|
||||
// settings will override the default.
|
||||
//
|
||||
WDF_TRI_STATE Enabled;
|
||||
|
||||
} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7;
|
||||
|
||||
typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5 {
|
||||
//
|
||||
// Size of this structure in bytes
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// The low power state in which the device will be placed when it is armed
|
||||
// for wake from Sx.
|
||||
//
|
||||
DEVICE_POWER_STATE DxState;
|
||||
|
||||
//
|
||||
// Inidcates whether a user can control the idle policy of the device.
|
||||
// By default, a user is allowed to change the policy.
|
||||
//
|
||||
WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings;
|
||||
|
||||
//
|
||||
// If WdfTrue, arming the device for wake while the machine is in Sx is
|
||||
// enabled.
|
||||
//
|
||||
// If WdfFalse, arming the device for wake while the machine is in Sx is
|
||||
// disabled.
|
||||
//
|
||||
// If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings
|
||||
// is set to WakeAllowUserControl, the user's settings will override the
|
||||
// default.
|
||||
//
|
||||
WDF_TRI_STATE Enabled;
|
||||
|
||||
} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5;
|
||||
|
||||
//
|
||||
// Versioning of structures for wdftimer.h
|
||||
//
|
||||
typedef struct _WDF_TIMER_CONFIG_V1_7 {
|
||||
ULONG Size;
|
||||
|
||||
PFN_WDF_TIMER EvtTimerFunc;
|
||||
|
||||
LONG Period;
|
||||
|
||||
//
|
||||
// If this is TRUE, the Timer will automatically serialize
|
||||
// with the event callback handlers of its Parent Object.
|
||||
//
|
||||
// Parent Object's callback constraints should be compatible
|
||||
// with the Timer DPC (DISPATCH_LEVEL), or the request will fail.
|
||||
//
|
||||
BOOLEAN AutomaticSerialization;
|
||||
|
||||
} WDF_TIMER_CONFIG_V1_7, *PWDF_TIMER_CONFIG_V1_7;
|
||||
|
||||
typedef struct _WDF_TIMER_CONFIG_V1_11 {
|
||||
ULONG Size;
|
||||
|
||||
PFN_WDF_TIMER EvtTimerFunc;
|
||||
|
||||
ULONG Period;
|
||||
|
||||
//
|
||||
// If this is TRUE, the Timer will automatically serialize
|
||||
// with the event callback handlers of its Parent Object.
|
||||
//
|
||||
// Parent Object's callback constraints should be compatible
|
||||
// with the Timer DPC (DISPATCH_LEVEL), or the request will fail.
|
||||
//
|
||||
BOOLEAN AutomaticSerialization;
|
||||
|
||||
//
|
||||
// Optional tolerance for the timer in milliseconds.
|
||||
//
|
||||
ULONG TolerableDelay;
|
||||
|
||||
} WDF_TIMER_CONFIG_V1_11, *PWDF_TIMER_CONFIG_V1_11;
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxCxDeviceInit.cpp
|
||||
|
||||
Abstract:
|
||||
Internals for WDFCXDEVICE_INIT
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxCxDeviceInit.tmh"
|
||||
}
|
||||
|
||||
WDFCXDEVICE_INIT::WDFCXDEVICE_INIT()
|
||||
{
|
||||
InitializeListHead(&ListEntry);
|
||||
|
||||
ClientDriverGlobals = NULL;
|
||||
CxDriverGlobals = NULL;
|
||||
PreprocessInfo = NULL;
|
||||
IoInCallerContextCallback = NULL;
|
||||
RtlZeroMemory(&RequestAttributes, sizeof(RequestAttributes));
|
||||
RtlZeroMemory(&FileObject, sizeof(FileObject));
|
||||
FileObject.AutoForwardCleanupClose = WdfUseDefault;
|
||||
CxDeviceInfo = NULL;
|
||||
}
|
||||
|
||||
WDFCXDEVICE_INIT::~WDFCXDEVICE_INIT()
|
||||
{
|
||||
ASSERT(IsListEmpty(&ListEntry));
|
||||
|
||||
if (PreprocessInfo != NULL) {
|
||||
delete PreprocessInfo;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PWDFCXDEVICE_INIT
|
||||
WDFCXDEVICE_INIT::_AllocateCxDeviceInit(
|
||||
__in PWDFDEVICE_INIT DeviceInit
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
PWDFCXDEVICE_INIT init;
|
||||
|
||||
fxDriverGlobals = DeviceInit->DriverGlobals;
|
||||
|
||||
init = new(fxDriverGlobals) WDFCXDEVICE_INIT();
|
||||
if (init == NULL) {
|
||||
DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDRIVER 0x%p couldn't allocate WDFCXDEVICE_INIT",
|
||||
DeviceInit->Driver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DeviceInit->AddCxDeviceInit(init);
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,501 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxCxDeviceInitApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module exposes the "C" interface to the FxDevice object
|
||||
for the class extensions.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxCxDeviceInitApi.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
__inline
|
||||
static
|
||||
NTSTATUS
|
||||
FxValiateCx(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PFX_DRIVER_GLOBALS CxDriverGlobals
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
if (FxIsClassExtension(FxDriverGlobals, CxDriverGlobals) == FALSE) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"This function can only be called by a WDF "
|
||||
"extension driver, Driver 0x%p, %!STATUS!",
|
||||
CxDriverGlobals->Public.Driver, status);
|
||||
FxVerifierDbgBreakPoint(FxDriverGlobals);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFAPI
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PWDFCXDEVICE_INIT CxDeviceInit,
|
||||
__in
|
||||
PFN_WDFCXDEVICE_WDM_IRP_PREPROCESS EvtCxDeviceWdmIrpPreprocess,
|
||||
__in
|
||||
UCHAR MajorFunction,
|
||||
__drv_when(NumMinorFunctions > 0, __in_bcount(NumMinorFunctions))
|
||||
__drv_when(NumMinorFunctions == 0, __in_opt)
|
||||
PUCHAR MinorFunctions,
|
||||
__in
|
||||
ULONG NumMinorFunctions
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
PFX_DRIVER_GLOBALS cxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
|
||||
cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
|
||||
fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
|
||||
|
||||
//
|
||||
// Caller must be a class extension driver.
|
||||
//
|
||||
status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
FxPointerNotNull(fxDriverGlobals, EvtCxDeviceWdmIrpPreprocess);
|
||||
|
||||
if (NumMinorFunctions > 0) {
|
||||
FxPointerNotNull(fxDriverGlobals, MinorFunctions);
|
||||
}
|
||||
|
||||
//
|
||||
// ARRAY_SIZE(CxDeviceInit->PreprocessInfo->Dispatch) just returns a
|
||||
// constant size, it does not actually deref PreprocessInfo (which could
|
||||
// be NULL)
|
||||
//
|
||||
if (MajorFunction >= ARRAY_SIZE(CxDeviceInit->PreprocessInfo->Dispatch)) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"MajorFunction %x is invalid, %!STATUS!",
|
||||
(ULONG)MajorFunction, status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
//
|
||||
// CX must call this API multiple times if it wants to register preprocess callbacks for
|
||||
// multiple IRP major codes.
|
||||
//
|
||||
if (CxDeviceInit->PreprocessInfo == NULL) {
|
||||
CxDeviceInit->PreprocessInfo = new(fxDriverGlobals) FxIrpPreprocessInfo();
|
||||
if (CxDeviceInit->PreprocessInfo == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Couldn't create object PreprocessInfo, "
|
||||
"%!STATUS!", status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
CxDeviceInit->PreprocessInfo->ClassExtension = TRUE;
|
||||
}
|
||||
|
||||
ASSERT(CxDeviceInit->PreprocessInfo->ClassExtension);
|
||||
|
||||
if (NumMinorFunctions > 0) {
|
||||
if (CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions != 0) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Already assigned Minorfunctions, %!STATUS!",
|
||||
status);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions =
|
||||
(PUCHAR) FxPoolAllocate(fxDriverGlobals,
|
||||
NonPagedPool,
|
||||
sizeof(UCHAR) * NumMinorFunctions);
|
||||
|
||||
if (CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Couldn't create object MinorFunctions, "
|
||||
"%!STATUS!", status);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
RtlCopyMemory(
|
||||
&CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions[0],
|
||||
&MinorFunctions[0],
|
||||
NumMinorFunctions
|
||||
);
|
||||
|
||||
CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions =
|
||||
NumMinorFunctions;
|
||||
}
|
||||
|
||||
CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].EvtCxDevicePreprocess =
|
||||
EvtCxDeviceWdmIrpPreprocess;
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
Done:
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PWDFCXDEVICE_INIT CxDeviceInit,
|
||||
__in
|
||||
PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Registers an I/O pre-processing callback for the class extension device.
|
||||
|
||||
If registered, any I/O for the device is first presented to this
|
||||
callback function before being placed in any I/O Queue's.
|
||||
|
||||
The callback is invoked in the thread and/or DPC context of the
|
||||
original WDM caller as presented to the I/O package. No framework
|
||||
threading, locking, synchronization, or queuing occurs, and
|
||||
responsibility for synchronization is up to the device driver.
|
||||
|
||||
This API is intended to support METHOD_NEITHER IRP_MJ_DEVICE_CONTROL's
|
||||
which must access the user buffer in the original callers context. The
|
||||
driver would probe and lock the buffer pages from within this event
|
||||
handler using the functions supplied on the WDFREQUEST object, storing
|
||||
any required mapped buffers and/or pointers on the WDFREQUEST context
|
||||
whose size is set by the RequestContextSize of the WDF_DRIVER_CONFIG structure.
|
||||
|
||||
It is the responsibility of this routine to either complete the request, or
|
||||
pass it on to the I/O package through WdfDeviceEnqueueRequest(Device, Request).
|
||||
|
||||
Arguments:
|
||||
|
||||
CxDeviceInit - Class Extension Device initialization structure
|
||||
|
||||
EvtIoInCallerContext - Pointer to driver supplied callback function
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
PFX_DRIVER_GLOBALS cxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
|
||||
cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
|
||||
fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
|
||||
|
||||
//
|
||||
// Caller must be a class extension driver.
|
||||
//
|
||||
status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
FxPointerNotNull(fxDriverGlobals, EvtIoInCallerContext);
|
||||
|
||||
CxDeviceInit->IoInCallerContextCallback = EvtIoInCallerContext;
|
||||
|
||||
Done:
|
||||
return;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfCxDeviceInitSetRequestAttributes)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PWDFCXDEVICE_INIT CxDeviceInit,
|
||||
__in
|
||||
PWDF_OBJECT_ATTRIBUTES RequestAttributes
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
PFX_DRIVER_GLOBALS cxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
|
||||
cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
|
||||
fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
|
||||
|
||||
//
|
||||
// Caller must be a class extension driver.
|
||||
//
|
||||
status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
FxPointerNotNull(fxDriverGlobals, RequestAttributes);
|
||||
|
||||
//
|
||||
// Parent of all requests created from WDFDEVICE are parented by the WDFDEVICE.
|
||||
//
|
||||
status = FxValidateObjectAttributes(fxDriverGlobals,
|
||||
RequestAttributes,
|
||||
FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FxVerifierDbgBreakPoint(fxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(&CxDeviceInit->RequestAttributes,
|
||||
RequestAttributes,
|
||||
sizeof(WDF_OBJECT_ATTRIBUTES));
|
||||
|
||||
Done:
|
||||
return;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PWDFCXDEVICE_INIT CxDeviceInit,
|
||||
__in
|
||||
PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES FileObjectAttributes
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Registers file object callbacks for class extensions.
|
||||
|
||||
Defaults to WdfFileObjectNotRequired if no file obj config set.
|
||||
|
||||
Arguments:
|
||||
|
||||
Returns:
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
PFX_DRIVER_GLOBALS cxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
WDF_FILEOBJECT_CLASS normalizedFileClass;
|
||||
|
||||
cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
|
||||
fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
|
||||
|
||||
//
|
||||
// Caller must be a class extension driver.
|
||||
//
|
||||
status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
FxPointerNotNull(fxDriverGlobals, CxFileObjectConfig);
|
||||
|
||||
if (CxFileObjectConfig->Size != sizeof(WDFCX_FILEOBJECT_CONFIG)) {
|
||||
DoTraceLevelMessage(
|
||||
fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Invalid CxFileObjectConfig Size %d, expected %d",
|
||||
CxFileObjectConfig->Size, sizeof(WDFCX_FILEOBJECT_CONFIG));
|
||||
|
||||
FxVerifierDbgBreakPoint(fxDriverGlobals);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(
|
||||
fxDriverGlobals,
|
||||
FileObjectAttributes,
|
||||
FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED |
|
||||
FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED |
|
||||
FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FxVerifierDbgBreakPoint(fxDriverGlobals);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate AutoForwardCleanupClose.
|
||||
//
|
||||
switch (CxFileObjectConfig->AutoForwardCleanupClose) {
|
||||
case WdfTrue:
|
||||
case WdfFalse:
|
||||
case WdfUseDefault:
|
||||
break;
|
||||
|
||||
default:
|
||||
DoTraceLevelMessage(
|
||||
fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Invalid CxFileObjectConfig->AutoForwardCleanupClose value 0x%x, "
|
||||
"expected WDF_TRI_STATE value",
|
||||
CxFileObjectConfig->AutoForwardCleanupClose);
|
||||
|
||||
FxVerifierDbgBreakPoint(fxDriverGlobals);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
CxDeviceInit->FileObject.Set = TRUE;
|
||||
|
||||
CxDeviceInit->FileObject.AutoForwardCleanupClose =
|
||||
CxFileObjectConfig->AutoForwardCleanupClose;
|
||||
|
||||
//
|
||||
// Remove bit flags and validate file object class value.
|
||||
//
|
||||
normalizedFileClass = FxFileObjectClassNormalize(
|
||||
CxFileObjectConfig->FileObjectClass);
|
||||
|
||||
if (normalizedFileClass == WdfFileObjectInvalid ||
|
||||
normalizedFileClass > WdfFileObjectWdfCannotUseFsContexts) {
|
||||
DoTraceLevelMessage(
|
||||
fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Out of range CxFileObjectConfig->FileObjectClass %d",
|
||||
CxFileObjectConfig->FileObjectClass);
|
||||
FxVerifierDbgBreakPoint(fxDriverGlobals);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
//
|
||||
// The optional flag can only be combined with a subset of values.
|
||||
//
|
||||
if (FxIsFileObjectOptional(CxFileObjectConfig->FileObjectClass)) {
|
||||
switch(normalizedFileClass) {
|
||||
case WdfFileObjectWdfCanUseFsContext:
|
||||
case WdfFileObjectWdfCanUseFsContext2:
|
||||
case WdfFileObjectWdfCannotUseFsContexts:
|
||||
break;
|
||||
|
||||
default:
|
||||
DoTraceLevelMessage(
|
||||
fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Invalid CxFileObjectConfig->FileObjectClass %d",
|
||||
CxFileObjectConfig->FileObjectClass);
|
||||
FxVerifierDbgBreakPoint(fxDriverGlobals);
|
||||
goto Done;
|
||||
break; // just in case static verification tools complain.
|
||||
}
|
||||
}
|
||||
|
||||
CxDeviceInit->FileObject.Class = CxFileObjectConfig->FileObjectClass;
|
||||
|
||||
RtlCopyMemory(&CxDeviceInit->FileObject.Callbacks,
|
||||
CxFileObjectConfig,
|
||||
sizeof(CxDeviceInit->FileObject.Callbacks));
|
||||
|
||||
if (FileObjectAttributes != NULL) {
|
||||
RtlCopyMemory(&CxDeviceInit->FileObject.Attributes,
|
||||
FileObjectAttributes,
|
||||
sizeof(CxDeviceInit->FileObject.Attributes));
|
||||
}
|
||||
|
||||
Done:
|
||||
return;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
PWDFCXDEVICE_INIT
|
||||
WDFEXPORT(WdfCxDeviceInitAllocate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PWDFDEVICE_INIT DeviceInit
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS cxDriverGlobals;
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
PWDFCXDEVICE_INIT cxDeviceInit;
|
||||
NTSTATUS status;
|
||||
|
||||
cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
FxPointerNotNull(cxDriverGlobals, DeviceInit);
|
||||
fxDriverGlobals = DeviceInit->DriverGlobals;
|
||||
cxDeviceInit = NULL;
|
||||
|
||||
//
|
||||
// Caller must be a class extension driver.
|
||||
//
|
||||
status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(fxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
cxDeviceInit = WDFCXDEVICE_INIT::_AllocateCxDeviceInit(DeviceInit);
|
||||
if (NULL == cxDeviceInit) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
cxDeviceInit->ClientDriverGlobals = fxDriverGlobals;
|
||||
cxDeviceInit->CxDriverGlobals = cxDriverGlobals;
|
||||
|
||||
Done:
|
||||
return cxDeviceInit;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,417 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceBase.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the class implementation for the base device class.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceBase.tmh"
|
||||
}
|
||||
|
||||
FxDeviceBase::FxDeviceBase(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in FxDriver* Driver,
|
||||
__in WDFTYPE Type,
|
||||
__in USHORT Size
|
||||
) :
|
||||
FxNonPagedObject(Type, Size, FxDriverGlobals)
|
||||
{
|
||||
m_Driver = Driver;
|
||||
|
||||
m_CallbackLockPtr = NULL;
|
||||
m_CallbackLockObjectPtr = NULL;
|
||||
|
||||
m_DisposeList = NULL;
|
||||
|
||||
m_DmaPacketTransactionStatus = FxDmaPacketTransactionCompleted;
|
||||
|
||||
m_ExecutionLevel = WdfExecutionLevelInheritFromParent;
|
||||
m_SynchronizationScope = WdfSynchronizationScopeInheritFromParent;
|
||||
|
||||
MarkPassiveDispose(ObjectDoNotLock);
|
||||
SetDeviceBase(this);
|
||||
}
|
||||
|
||||
FxDeviceBase::~FxDeviceBase(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (m_DisposeList != NULL) {
|
||||
m_DisposeList->DeleteObject();
|
||||
m_DisposeList = NULL;
|
||||
}
|
||||
|
||||
if (m_CallbackLockPtr != NULL) {
|
||||
delete m_CallbackLockPtr;
|
||||
m_CallbackLockPtr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceBase::QueryInterface(
|
||||
__inout FxQueryInterfaceParams* Params
|
||||
)
|
||||
{
|
||||
switch (Params->Type) {
|
||||
case FX_TYPE_DEVICE_BASE:
|
||||
*Params->Object = this;
|
||||
break;
|
||||
|
||||
case FX_TYPE_IHASCALLBACKS:
|
||||
*Params->Object = (IFxHasCallbacks*) this;
|
||||
break;
|
||||
|
||||
default:
|
||||
return __super::QueryInterface(Params);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxDeviceBase::ConfigureConstraints(
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
WDF_EXECUTION_LEVEL driverLevel;
|
||||
WDF_SYNCHRONIZATION_SCOPE driverScope;
|
||||
|
||||
ASSERT(m_Driver != NULL);
|
||||
|
||||
//
|
||||
// If WDF_OBJECT_ATTRIBUTES is specified, these override any
|
||||
// default settings.
|
||||
//
|
||||
if (ObjectAttributes != NULL) {
|
||||
m_ExecutionLevel = ObjectAttributes->ExecutionLevel;
|
||||
m_SynchronizationScope = ObjectAttributes->SynchronizationScope;
|
||||
}
|
||||
|
||||
//
|
||||
// If no WDFDEVICE specific attributes are specified, we
|
||||
// get them from WDFDRIVER, which allows WDFDRIVER to
|
||||
// provide a default for all WDFDEVICE's created.
|
||||
//
|
||||
m_Driver->GetConstraints(&driverLevel, &driverScope);
|
||||
|
||||
if (m_ExecutionLevel == WdfExecutionLevelInheritFromParent) {
|
||||
m_ExecutionLevel = driverLevel;
|
||||
}
|
||||
|
||||
if (m_SynchronizationScope == WdfSynchronizationScopeInheritFromParent) {
|
||||
m_SynchronizationScope = driverScope;
|
||||
}
|
||||
|
||||
//
|
||||
// Configure The Execution Level Constraint
|
||||
//
|
||||
if (m_ExecutionLevel == WdfExecutionLevelPassive) {
|
||||
m_CallbackLockPtr = new(GetDriverGlobals())
|
||||
FxCallbackMutexLock(GetDriverGlobals());
|
||||
//
|
||||
// Currently, all event callbacks from FxDevice into the driver
|
||||
// are from PASSIVE_LEVEL threads, and there is no need to defer
|
||||
// to a system workitem like IoQueue. So we don't allocate and
|
||||
// setup an FxSystemWorkItem here.
|
||||
//
|
||||
// If the FxDevice starts raising events to the device driver
|
||||
// whose thread starts out above PASSIVE_LEVEL, then an FxSystemWorkItem
|
||||
// would need to be allocated when WdfExecutionLevelPassive is specified.
|
||||
//
|
||||
// (FDO and PDO variants of FxDevice may own their own event dispatch
|
||||
// and deferral logic separate from FxDevice.)
|
||||
//
|
||||
}
|
||||
else {
|
||||
m_CallbackLockPtr = new(GetDriverGlobals())
|
||||
FxCallbackSpinLock(GetDriverGlobals());
|
||||
}
|
||||
|
||||
//
|
||||
// Finish initializing the spin/mutex lock.
|
||||
//
|
||||
if (NULL == m_CallbackLockPtr) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT,
|
||||
"WDFDEVICE %p, could not allocate callback lock, %!STATUS!",
|
||||
GetHandle(), status);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
m_CallbackLockPtr->Initialize(this);
|
||||
m_CallbackLockObjectPtr = this;
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
Done:
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDeviceBase::GetConstraints(
|
||||
__out_opt WDF_EXECUTION_LEVEL* ExecutionLevel,
|
||||
__out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope
|
||||
)
|
||||
{
|
||||
if (ExecutionLevel != NULL) {
|
||||
*ExecutionLevel = m_ExecutionLevel;
|
||||
}
|
||||
|
||||
if (SynchronizationScope != NULL) {
|
||||
*SynchronizationScope = m_SynchronizationScope;
|
||||
}
|
||||
}
|
||||
|
||||
FxCallbackLock*
|
||||
FxDeviceBase::GetCallbackLockPtr(
|
||||
__out_opt FxObject** LockObject
|
||||
)
|
||||
{
|
||||
if (LockObject != NULL) {
|
||||
*LockObject = m_CallbackLockObjectPtr;
|
||||
}
|
||||
|
||||
return m_CallbackLockPtr;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FxDeviceBase::Init(
|
||||
__in MdDeviceObject DeviceObject,
|
||||
__in MdDeviceObject AttachedDevice,
|
||||
__in MdDeviceObject PhysicalDevice
|
||||
)
|
||||
{
|
||||
m_DeviceObject.SetObject(DeviceObject);
|
||||
m_AttachedDevice.SetObject(AttachedDevice);
|
||||
m_PhysicalDevice.SetObject(PhysicalDevice);
|
||||
}
|
||||
|
||||
FxDeviceBase*
|
||||
FxDeviceBase::_SearchForDevice(
|
||||
__in FxObject* Object,
|
||||
__out_opt IFxHasCallbacks** Callbacks
|
||||
)
|
||||
{
|
||||
FxObject* pParent, *pOrigParent;
|
||||
FxDeviceBase* pDeviceBase;
|
||||
FxQueryInterfaceParams cbParams = { (PVOID*) Callbacks, FX_TYPE_IHASCALLBACKS, 0 };
|
||||
PVOID pTag;
|
||||
|
||||
pDeviceBase = Object->GetDeviceBase();
|
||||
if (pDeviceBase == NULL) {
|
||||
DoTraceLevelMessage(
|
||||
Object->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT,
|
||||
"WDFHANDLE %p does not have a WDFDEVICE as an ancestor",
|
||||
Object->GetObjectHandle());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (Callbacks == NULL) {
|
||||
//
|
||||
// Caller is not interested in the callbacks interface, just return
|
||||
// now without searching for it.
|
||||
//
|
||||
return pDeviceBase;
|
||||
}
|
||||
|
||||
//
|
||||
// Init out parameter.
|
||||
//
|
||||
*Callbacks = NULL;
|
||||
|
||||
pOrigParent = Object;
|
||||
pTag = pOrigParent;
|
||||
|
||||
//
|
||||
// By adding a reference now, we simulate what GetParentObjectReferenced
|
||||
// does later, thus allowing simple logic on when/how to release the
|
||||
// reference on exit.
|
||||
//
|
||||
Object->ADDREF(pTag);
|
||||
|
||||
do {
|
||||
//
|
||||
// If successful, Callbacks will be != NULL
|
||||
//
|
||||
if (NT_SUCCESS(Object->QueryInterface(&cbParams))) {
|
||||
ASSERT(*Callbacks != NULL);
|
||||
//
|
||||
// Release the reference previously taken by the top of the function
|
||||
// or GetParentObjectReferenced in a previous pass in the loop.
|
||||
//
|
||||
Object->RELEASE(pTag);
|
||||
return pDeviceBase;
|
||||
}
|
||||
|
||||
pParent = Object->GetParentObjectReferenced(pTag);
|
||||
|
||||
//
|
||||
// Release the reference previously taken by the top of the function
|
||||
// or GetParentObjectReferenced in a previous pass in the loop.
|
||||
//
|
||||
Object->RELEASE(pTag);
|
||||
|
||||
Object = pParent;
|
||||
} while (Object != NULL);
|
||||
|
||||
ASSERT(Object == NULL);
|
||||
|
||||
//
|
||||
// Queue presented requests do not have parents (to increase performance).
|
||||
// Try to find the callback interface on this object's device base.
|
||||
//
|
||||
if (NT_SUCCESS(pDeviceBase->QueryInterface(&cbParams))) {
|
||||
ASSERT(*Callbacks != NULL);
|
||||
//
|
||||
// Success, we got a callback interface.
|
||||
//
|
||||
return pDeviceBase;
|
||||
}
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pOrigParent->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT,
|
||||
"WDFHANDLE %p does not have a callbacks interface in its object tree"
|
||||
"(WDFDEVICE %p)", pOrigParent->GetObjectHandle(),
|
||||
pDeviceBase->GetHandle());
|
||||
|
||||
return pDeviceBase;
|
||||
}
|
||||
|
||||
FxDeviceBase*
|
||||
FxDeviceBase::_SearchForDevice(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes
|
||||
)
|
||||
{
|
||||
FxObject* pParentObject;
|
||||
FxDeviceBase* pDeviceBase;
|
||||
|
||||
if (Attributes == NULL || Attributes->ParentObject == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtr(FxDriverGlobals,
|
||||
Attributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*) &pParentObject);
|
||||
|
||||
pDeviceBase = _SearchForDevice(pParentObject, NULL);
|
||||
|
||||
return pDeviceBase;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceBase::AllocateTarget(
|
||||
_Out_ FxIoTarget** Target,
|
||||
_In_ BOOLEAN SelfTarget
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Allocates an IO Target or an Self IO target for the FxDevice.
|
||||
|
||||
Arguments:
|
||||
|
||||
Target - Out - returns the pointer to the allocated IO target.
|
||||
|
||||
SelfTarget - If TRUE allocates an Self IO Target, if FALSE allocates
|
||||
a regular IO target.
|
||||
|
||||
Returns:
|
||||
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIoTarget* pTarget;
|
||||
NTSTATUS status;
|
||||
|
||||
if (SelfTarget) {
|
||||
pTarget = (FxIoTarget*) new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES)
|
||||
FxIoTargetSelf(GetDriverGlobals(), sizeof(FxIoTargetSelf));
|
||||
} else {
|
||||
pTarget = new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES)
|
||||
FxIoTarget(GetDriverGlobals(), sizeof(FxIoTarget));
|
||||
}
|
||||
|
||||
if (pTarget == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p could not allocate a WDFIOTARGET, %!STATUS!",
|
||||
GetHandle(), status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = AddIoTarget(pTarget);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p failed to initialize (add) a WDFIOTARGET, %!STATUS!",
|
||||
GetHandle(), status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = pTarget->Init(this);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p failed to initialize a WDFIOTARGET, %!STATUS!",
|
||||
GetHandle(), status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = pTarget->Commit(WDF_NO_OBJECT_ATTRIBUTES, NULL, this);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p failed to initialize (commit) a WDFIOTARGET, %!STATUS!",
|
||||
GetHandle(), status);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
Done:
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (pTarget != NULL) {
|
||||
pTarget->DeleteFromFailedCreate();
|
||||
pTarget = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*Target = pTarget;
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceControlAPI.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements external DDIs for control devices
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceControlAPI.tmh"
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfControlFinishInitializing)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice* pDevice;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
MxDeviceObject device(pDevice->GetDeviceObject());
|
||||
|
||||
if (pDevice->IsLegacy()) {
|
||||
pDevice->m_PkgWmi->Register();
|
||||
device.SetFlags(device.GetFlags() & ~DO_DEVICE_INITIALIZING);
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p not a control device", Device);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
}
|
||||
|
||||
} // entire extern "C" for the file
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceInit.cpp
|
||||
|
||||
Abstract:
|
||||
Internals for WDFDEVICE_INIT
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceInit.tmh"
|
||||
}
|
||||
|
||||
WDFDEVICE_INIT::WDFDEVICE_INIT(
|
||||
__in FxDriver* Driver
|
||||
) :
|
||||
Driver(Driver)
|
||||
{
|
||||
DriverGlobals = Driver->GetDriverGlobals();
|
||||
|
||||
ReadWriteIoType = WdfDeviceIoBuffered;
|
||||
PowerPageable = TRUE;
|
||||
Inrush = FALSE;
|
||||
DeviceType = FILE_DEVICE_UNKNOWN;
|
||||
Characteristics = FILE_DEVICE_SECURE_OPEN;
|
||||
|
||||
RtlZeroMemory(&FileObject, sizeof(FileObject));
|
||||
FileObject.AutoForwardCleanupClose = WdfUseDefault;
|
||||
|
||||
DeviceName = NULL;
|
||||
CreatedDevice = NULL;
|
||||
|
||||
CreatedOnStack = FALSE;
|
||||
Exclusive = FALSE;
|
||||
|
||||
RequiresSelfIoTarget = FALSE;
|
||||
|
||||
RemoveLockOptionFlags = 0;
|
||||
|
||||
RtlZeroMemory(&PnpPower.PnpPowerEventCallbacks, sizeof(PnpPower.PnpPowerEventCallbacks));
|
||||
RtlZeroMemory(&PnpPower.PolicyEventCallbacks, sizeof(PnpPower.PolicyEventCallbacks));
|
||||
PnpPower.PnpStateCallbacks = NULL;
|
||||
PnpPower.PowerStateCallbacks = NULL;
|
||||
PnpPower.PowerPolicyStateCallbacks = NULL;
|
||||
|
||||
PnpPower.PowerPolicyOwner = WdfUseDefault;
|
||||
|
||||
InitType = FxDeviceInitTypeFdo;
|
||||
|
||||
RtlZeroMemory(&Fdo.EventCallbacks, sizeof(Fdo.EventCallbacks));
|
||||
RtlZeroMemory(&Fdo.ListConfig, sizeof(Fdo.ListConfig));
|
||||
RtlZeroMemory(&Fdo.ListConfigAttributes, sizeof(Fdo.ListConfigAttributes));
|
||||
Fdo.Filter = FALSE;
|
||||
|
||||
RtlZeroMemory(&Pdo.EventCallbacks, sizeof(Pdo.EventCallbacks));
|
||||
Pdo.Raw = FALSE;
|
||||
Pdo.Static = FALSE;
|
||||
Pdo.DeviceID = NULL;
|
||||
Pdo.InstanceID = NULL;
|
||||
Pdo.ContainerID = NULL;
|
||||
Pdo.DefaultLocale = 0x0;
|
||||
Pdo.DescriptionEntry = NULL;
|
||||
Pdo.ForwardRequestToParent = FALSE;
|
||||
|
||||
RtlZeroMemory(&Security, sizeof(Security));
|
||||
|
||||
RtlZeroMemory(&RequestAttributes, sizeof(RequestAttributes));
|
||||
|
||||
PreprocessInfo = NULL;
|
||||
|
||||
IoInCallerContextCallback = NULL;
|
||||
|
||||
InitializeListHead(&CxDeviceInitListHead);
|
||||
|
||||
ReleaseHardwareOrderOnFailure = WdfReleaseHardwareOrderOnFailureEarly;
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
|
||||
DeviceControlIoType = WdfDeviceIoBuffered;
|
||||
DirectTransferThreshold = 0;
|
||||
|
||||
DevStack = NULL;
|
||||
|
||||
KernelDeviceName = NULL;
|
||||
|
||||
PdoKey = NULL;
|
||||
|
||||
DevInstanceID = NULL;
|
||||
|
||||
DriverID = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
WDFDEVICE_INIT::~WDFDEVICE_INIT()
|
||||
{
|
||||
PLIST_ENTRY next;
|
||||
|
||||
if (PnpPower.PnpStateCallbacks != NULL) {
|
||||
delete PnpPower.PnpStateCallbacks;
|
||||
}
|
||||
|
||||
if (PnpPower.PowerStateCallbacks != NULL) {
|
||||
delete PnpPower.PowerStateCallbacks;
|
||||
}
|
||||
|
||||
if (PnpPower.PowerPolicyStateCallbacks != NULL) {
|
||||
delete PnpPower.PowerPolicyStateCallbacks;
|
||||
}
|
||||
|
||||
if (DeviceName != NULL) {
|
||||
DeviceName->DeleteObject();
|
||||
}
|
||||
if (Pdo.DeviceID != NULL) {
|
||||
Pdo.DeviceID->DeleteObject();
|
||||
}
|
||||
if (Pdo.InstanceID != NULL) {
|
||||
Pdo.InstanceID->DeleteObject();
|
||||
}
|
||||
if (Pdo.ContainerID != NULL) {
|
||||
Pdo.ContainerID->DeleteObject();
|
||||
}
|
||||
|
||||
FxDeviceText::_CleanupList(&Pdo.DeviceText);
|
||||
|
||||
if (Security.Sddl != NULL) {
|
||||
Security.Sddl->DeleteObject();
|
||||
}
|
||||
if (PreprocessInfo != NULL) {
|
||||
delete PreprocessInfo;
|
||||
}
|
||||
|
||||
while(!IsListEmpty(&CxDeviceInitListHead)) {
|
||||
next = RemoveHeadList(&CxDeviceInitListHead);
|
||||
PWDFCXDEVICE_INIT cxInit;
|
||||
cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry);
|
||||
InitializeListHead(next);
|
||||
delete cxInit;
|
||||
}
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
delete [] KernelDeviceName;
|
||||
delete [] ConfigRegistryPath;
|
||||
delete [] DevInstanceID;
|
||||
|
||||
if (PdoKey != NULL) {
|
||||
RegCloseKey(PdoKey);
|
||||
PdoKey = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
WDFDEVICE_INIT::AssignName(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in const UNICODE_STRING* Name
|
||||
)
|
||||
{
|
||||
if (DeviceName == NULL) {
|
||||
DeviceName = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
|
||||
FxString(FxDriverGlobals);
|
||||
|
||||
if (DeviceName == NULL) {
|
||||
NTSTATUS status;
|
||||
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"DeviceName is NULL, %!STATUS!", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Clear out the autogenerate flag since we have a specific name
|
||||
//
|
||||
Characteristics &= ~FILE_AUTOGENERATED_DEVICE_NAME;
|
||||
}
|
||||
|
||||
return DeviceName->Assign(Name);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PWDFDEVICE_INIT
|
||||
WDFDEVICE_INIT::_AllocateControlDeviceInit(
|
||||
__in FxDriver* Driver,
|
||||
__in const UNICODE_STRING* SDDLString
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
PWDFDEVICE_INIT pInit;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = Driver->GetDriverGlobals();
|
||||
|
||||
pInit = new(pFxDriverGlobals) WDFDEVICE_INIT(Driver);
|
||||
|
||||
if (pInit == NULL) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDRIVER 0x%p couldn't allocate WDFDEVICE_INIT",
|
||||
Driver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pInit->InitType = FxDeviceInitTypeControlDevice;
|
||||
|
||||
//
|
||||
// Since we require and SDLL string, initialize to autogenerated device
|
||||
// name so the driver doesn't have to worry about creating a name if they
|
||||
// don't want it (useful if creating a DO for WMI tracing for instance).
|
||||
//
|
||||
pInit->Characteristics |= FILE_AUTOGENERATED_DEVICE_NAME;
|
||||
|
||||
pInit->Security.Sddl = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
|
||||
FxString(pFxDriverGlobals);
|
||||
|
||||
if (pInit->Security.Sddl != NULL) {
|
||||
status = pInit->Security.Sddl->Assign(SDDLString);
|
||||
}
|
||||
else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDRIVER 0x%p couldn't create Security String object %!STATUS!",
|
||||
Driver, status);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
delete pInit;
|
||||
pInit = NULL;
|
||||
}
|
||||
|
||||
return pInit;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
WDFDEVICE_INIT::ShouldCreateSecure(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Driver explicitly set a class or SDDL, we have to create a secure
|
||||
// device. This will be true for all control devices (SDDL required)
|
||||
// and raw PDOs (class required), could be true for FDOs or filters as
|
||||
// well.
|
||||
//
|
||||
if (Security.DeviceClassSet || Security.Sddl != NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// See if there is a name for the device
|
||||
//
|
||||
if (HasName()) {
|
||||
if (IsPdoInit()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ASSERT(Pdo.Raw == FALSE);
|
||||
|
||||
DoTraceLevelMessage(
|
||||
DriverGlobals,
|
||||
TRACE_LEVEL_WARNING,
|
||||
TRACINGDEVICE,
|
||||
"WDFDRIVER 0x%p asked for a named device object, but the PDO "
|
||||
"will be created without a name because an SDDL string has not "
|
||||
"been specified for the PDO.",
|
||||
Driver
|
||||
);
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// We are creating a named FDO or filter
|
||||
//
|
||||
ASSERT(IsFdoInit());
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// No name involved (FDO or filter)
|
||||
//
|
||||
ASSERT(IsFdoInit());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
WDFDEVICE_INIT::AddCxDeviceInit(
|
||||
__in PWDFCXDEVICE_INIT CxDeviceInit
|
||||
)
|
||||
{
|
||||
InsertHeadList(&CxDeviceInitListHead, &CxDeviceInit->ListEntry);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,305 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDisposeList.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This class implements a Disposal list for deferring Dispose
|
||||
processing from dispatch to passive level.
|
||||
|
||||
It works tightly with FxObject, and is a friend class.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
#include "FxDisposeList.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxDisposeList.tmh"
|
||||
}
|
||||
|
||||
FxDisposeList::FxDisposeList(
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_DISPOSELIST, 0, FxDriverGlobals)
|
||||
{
|
||||
m_List.Next = NULL;
|
||||
m_ListEnd = &m_List.Next;
|
||||
|
||||
m_SystemWorkItem = NULL;
|
||||
m_WorkItemThread = NULL;
|
||||
}
|
||||
|
||||
FxDisposeList::~FxDisposeList()
|
||||
{
|
||||
ASSERT(m_List.Next == NULL);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxDisposeList::_Create(
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
PVOID WdmObject,
|
||||
FxDisposeList** pObject
|
||||
)
|
||||
{
|
||||
FxDisposeList* list;
|
||||
NTSTATUS status;
|
||||
|
||||
*pObject = NULL;
|
||||
|
||||
list = new(FxDriverGlobals) FxDisposeList(FxDriverGlobals);
|
||||
|
||||
if (list == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = list->Initialize(WdmObject);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*pObject = list;
|
||||
}
|
||||
else {
|
||||
list->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxDisposeList::Initialize(
|
||||
PVOID WdmObject
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
|
||||
status = FxSystemWorkItem::_Create(FxDriverGlobals,
|
||||
WdmObject,
|
||||
&m_SystemWorkItem
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
|
||||
"Could not allocate workitem: %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
m_WdmObject = WdmObject;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxDisposeList::Dispose(
|
||||
)
|
||||
{
|
||||
if (m_SystemWorkItem != NULL) {
|
||||
m_SystemWorkItem->DeleteObject();
|
||||
m_SystemWorkItem = NULL;
|
||||
}
|
||||
|
||||
ASSERT(m_List.Next == NULL);
|
||||
|
||||
__super::Dispose();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDisposeList::Add(
|
||||
FxObject* Object
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Add an object to the cleanup list.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
The caller is expected to manage any reference counts on
|
||||
the object while on the cleanup list
|
||||
|
||||
Arguments:
|
||||
|
||||
object - Object to cleanup at passive level
|
||||
|
||||
Returns:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
KIRQL irql;
|
||||
BOOLEAN previouslyEmpty;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
ASSERT(Object->m_DisposeSingleEntry.Next == NULL);
|
||||
|
||||
previouslyEmpty = m_List.Next == NULL ? TRUE : FALSE;
|
||||
|
||||
//
|
||||
// Add to the end of m_List
|
||||
//
|
||||
*m_ListEnd = &Object->m_DisposeSingleEntry;
|
||||
|
||||
//
|
||||
// Update the end
|
||||
//
|
||||
m_ListEnd = &Object->m_DisposeSingleEntry.Next;
|
||||
|
||||
if (previouslyEmpty) {
|
||||
m_SystemWorkItem->TryToEnqueue(_WorkItemThunk, this);
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDisposeList::DrainListLocked(
|
||||
PKIRQL PreviousIrql
|
||||
)
|
||||
{
|
||||
FxObject* pObject;
|
||||
PSINGLE_LIST_ENTRY pEntry;
|
||||
|
||||
//
|
||||
// Process items on the list until it is empty
|
||||
//
|
||||
while (m_List.Next != NULL) {
|
||||
pEntry = m_List.Next;
|
||||
|
||||
//
|
||||
// Remove pEntry from the list
|
||||
//
|
||||
m_List.Next = pEntry->Next;
|
||||
|
||||
//
|
||||
// Indicate pEntry is no longer in the list
|
||||
//
|
||||
pEntry->Next = NULL;
|
||||
|
||||
//
|
||||
// Convert back to the object
|
||||
//
|
||||
pObject = FxObject::_FromDisposeEntry(pEntry);
|
||||
|
||||
//
|
||||
// If the list is empty, we just popped off the entry and we need to
|
||||
// update m_ListEnd to a head of the list so it points to valid pool.
|
||||
//
|
||||
if (m_List.Next == NULL) {
|
||||
m_ListEnd = &m_List.Next;
|
||||
}
|
||||
|
||||
Unlock(*PreviousIrql);
|
||||
|
||||
//
|
||||
// Invoke the objects deferred dispose entry
|
||||
//
|
||||
pObject->DeferredDisposeWorkItem();
|
||||
|
||||
//
|
||||
// pObject may be invalid at this point due to its dereferencing itself
|
||||
//
|
||||
Lock(PreviousIrql);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDisposeList::_WorkItemThunk(
|
||||
__in PVOID Parameter
|
||||
)
|
||||
{
|
||||
FxDisposeList* pThis;
|
||||
KIRQL irql;
|
||||
|
||||
pThis = (FxDisposeList*) Parameter;
|
||||
|
||||
pThis->Lock(&irql);
|
||||
|
||||
pThis->DrainListLocked(&irql);
|
||||
|
||||
pThis->Unlock(irql);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDisposeList::WaitForEmpty(
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Wait until the list goes empty with no items.
|
||||
|
||||
Note, on wakeup, new items could have been added, only the assurance
|
||||
is that the list at least went empty for a moment.
|
||||
|
||||
This allows a waiter to wait for all previous Add() items to
|
||||
finishing processing before return.
|
||||
|
||||
Arguments:
|
||||
|
||||
Returns:
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
KIRQL irql;
|
||||
BOOLEAN wait;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
wait = TRUE;
|
||||
|
||||
if (m_WorkItemThread == Mx::MxGetCurrentThread()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ASSERT(FALSE);
|
||||
DrainListLocked(&irql);
|
||||
wait = FALSE;
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
if (wait) {
|
||||
m_SystemWorkItem->WaitForExit();
|
||||
}
|
||||
|
||||
// Should only be true for an empty list
|
||||
ASSERT(m_List.Next == NULL);
|
||||
}
|
||||
@@ -0,0 +1,656 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDriver.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the main driver framework.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "fxiotarget.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxDriver.tmh"
|
||||
}
|
||||
|
||||
FxDriver::FxDriver(
|
||||
__in MdDriverObject ArgDriverObject,
|
||||
__in PWDF_DRIVER_CONFIG DriverConfig,
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_DRIVER, sizeof(FxDriver), FxDriverGlobals),
|
||||
m_DriverObject(ArgDriverObject),
|
||||
m_CallbackMutexLock(FxDriverGlobals)
|
||||
{
|
||||
RtlInitUnicodeString(&m_RegistryPath, NULL);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
m_ExecutionLevel = WdfExecutionLevelDispatch;
|
||||
#else
|
||||
m_ExecutionLevel = WdfExecutionLevelPassive;
|
||||
#endif
|
||||
|
||||
m_SynchronizationScope = WdfSynchronizationScopeNone;
|
||||
|
||||
m_CallbackLockPtr = NULL;
|
||||
m_CallbackLockObjectPtr = NULL;
|
||||
|
||||
m_DisposeList = NULL;
|
||||
|
||||
//
|
||||
// These are initialized up front so that sub objects
|
||||
// can have the right configuration
|
||||
//
|
||||
WDF_DRIVER_CONFIG_INIT(&m_Config, NULL);
|
||||
|
||||
// Only copy the smallest of what is specified and our size
|
||||
RtlCopyMemory(&m_Config, DriverConfig, min(sizeof(m_Config), DriverConfig->Size) );
|
||||
|
||||
m_DebuggerConnected = FALSE;
|
||||
|
||||
#if FX_IS_USER_MODE
|
||||
m_DriverParametersKey = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
FxDriver::~FxDriver()
|
||||
{
|
||||
// Make it always present right now even on free builds
|
||||
if (IsDisposed() == FALSE) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGDRIVER,
|
||||
"FxDriver 0x%p not disposed: this maybe a driver reference count "
|
||||
"problem with WDFDRIVER 0x%p", this, GetObjectHandleUnchecked());
|
||||
|
||||
FxVerifierBugCheck(GetDriverGlobals(),
|
||||
WDF_OBJECT_ERROR,
|
||||
(ULONG_PTR) GetObjectHandleUnchecked(),
|
||||
(ULONG_PTR) this);
|
||||
}
|
||||
|
||||
//
|
||||
// Free the memory for the registry path if required.
|
||||
//
|
||||
if (m_RegistryPath.Buffer) {
|
||||
FxPoolFree(m_RegistryPath.Buffer);
|
||||
}
|
||||
|
||||
if (m_DisposeList != NULL) {
|
||||
m_DisposeList->DeleteObject();
|
||||
}
|
||||
|
||||
#if FX_IS_USER_MODE
|
||||
//
|
||||
// Close the R/W handle to the driver's service parameters key
|
||||
// that we opened during Initialize.
|
||||
//
|
||||
if (m_DriverParametersKey != NULL) {
|
||||
NTSTATUS status = FxRegKey::_Close(m_DriverParametersKey);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Cannot close Driver Parameters key %!STATUS!",
|
||||
status);
|
||||
}
|
||||
m_DriverParametersKey = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// The host-created driver object holds a reference to this
|
||||
// FxDriver object. Clear it, since this object was deleted.
|
||||
//
|
||||
ClearDriverObjectFxDriver();
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxDriver::Dispose(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (m_DisposeList != NULL) {
|
||||
m_DisposeList->WaitForEmpty();
|
||||
}
|
||||
|
||||
return __super::Dispose();
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDriver::Unload(
|
||||
__in MdDriverObject DriverObject
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDriver *pDriver;
|
||||
|
||||
pDriver = FxDriver::GetFxDriver(DriverObject);
|
||||
if (pDriver == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pFxDriverGlobals = pDriver->GetDriverGlobals();
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
|
||||
"Unloading WDFDRIVER %p, PDRIVER_OBJECT_UM %p",
|
||||
pDriver->GetHandle(), DriverObject);
|
||||
//
|
||||
// Invoke the driver if they specified an unload routine.
|
||||
//
|
||||
if (pDriver->m_DriverUnload.Method) {
|
||||
pDriver->m_DriverUnload.Invoke(pDriver->GetHandle());
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
|
||||
"Driver unload routine Exit WDFDRIVER %p, PDRIVER_OBJECT_UM %p",
|
||||
pDriver->GetHandle(), DriverObject);
|
||||
}
|
||||
|
||||
//
|
||||
// Delete the FxDriver object.
|
||||
//
|
||||
// This releases the FxDriver reference. Must be called at PASSIVE
|
||||
//
|
||||
pDriver->DeleteObject();
|
||||
|
||||
pFxDriverGlobals->Driver = NULL;
|
||||
|
||||
FxDestroy(pFxDriverGlobals);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDriver::_InitializeDriverName(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PCUNICODE_STRING RegistryPath
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Create a CHAR version of the service name contained in RegistryPath.
|
||||
|
||||
Arguments:
|
||||
RegistryPath - the path to the service name in the registry.
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
PWCHAR pCur, pBegin, pEnd;
|
||||
|
||||
RtlZeroMemory(&FxDriverGlobals->Public.DriverName[0],
|
||||
sizeof(FxDriverGlobals->Public.DriverName) );
|
||||
|
||||
if (RegistryPath == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pBegin = RegistryPath->Buffer;
|
||||
|
||||
//
|
||||
// pEnd is one past the end of the string, while pCur is a pointer to the
|
||||
// last character of the string. We will decrement pCur down towards the
|
||||
// beginning of the string.
|
||||
//
|
||||
pEnd = pBegin + (RegistryPath->Length / sizeof(WCHAR));
|
||||
pCur = pEnd - 1;
|
||||
|
||||
for ( ; *pCur != L'\\' && pCur != pBegin; pCur--) {
|
||||
DO_NOTHING();
|
||||
}
|
||||
|
||||
if (pCur != pBegin && *pCur == L'\\') {
|
||||
size_t regLen;
|
||||
ULONG i;
|
||||
|
||||
pCur++;
|
||||
|
||||
//
|
||||
// Can't use wcslen becuase this is a UNICODE_STRING which means that it
|
||||
// does not necessarily have a terminating NULL in the buffer.
|
||||
//
|
||||
regLen = pEnd - pCur;
|
||||
if (regLen > WDF_DRIVER_GLOBALS_NAME_LEN-1) {
|
||||
regLen = WDF_DRIVER_GLOBALS_NAME_LEN-1;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < regLen; i++) {
|
||||
FxDriverGlobals->Public.DriverName[i] = (CHAR) pCur[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
NTSTATUS status;
|
||||
|
||||
#if FX_CORE_MODE==FX_CORE_KERNEL_MODE
|
||||
status = RtlStringCbCopyA(FxDriverGlobals->Public.DriverName,
|
||||
sizeof(FxDriverGlobals->Public.DriverName),
|
||||
"WDF");
|
||||
#else // USER_MODE
|
||||
HRESULT hr;
|
||||
hr = StringCbCopyA(FxDriverGlobals->Public.DriverName,
|
||||
sizeof(FxDriverGlobals->Public.DriverName),
|
||||
"WDF");
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32) {
|
||||
status = WinErrorToNtStatus(HRESULT_CODE(hr));
|
||||
}
|
||||
else {
|
||||
status = SUCCEEDED(hr) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
#endif
|
||||
|
||||
UNREFERENCED_PARAMETER(status);
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxDriver::_InitializeTag(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PWDF_DRIVER_CONFIG Config
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Tries to create a tag for the driver based off of its name. This tag is
|
||||
used for allocations made on behalf of the driver so that it is easier to
|
||||
track which allocations belong to which image.
|
||||
|
||||
Arguments:
|
||||
Config - driver writer provided config. in the future, may contain a tag
|
||||
value in it
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
PCHAR pBegin;
|
||||
size_t length;
|
||||
|
||||
UNREFERENCED_PARAMETER(Config);
|
||||
|
||||
length = strlen(FxDriverGlobals->Public.DriverName);
|
||||
pBegin = &FxDriverGlobals->Public.DriverName[0];
|
||||
|
||||
if (length >= 3) {
|
||||
//
|
||||
// If the driver name begins with "WDF" (case insensitive), start after
|
||||
// "WDF"
|
||||
//
|
||||
if ((pBegin[0] == 'w' || pBegin[0] == 'W') &&
|
||||
(pBegin[1] == 'd' || pBegin[1] == 'D') &&
|
||||
(pBegin[2] == 'f' || pBegin[2] == 'F')) {
|
||||
length -=3;
|
||||
pBegin += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (length <= 2) {
|
||||
//
|
||||
// 2 or less characters is not a unique enough tag, just use the default
|
||||
// tag.
|
||||
//
|
||||
FxDriverGlobals->Tag = FX_TAG;
|
||||
}
|
||||
else {
|
||||
|
||||
if (length > sizeof(ULONG)) {
|
||||
length = sizeof(ULONG);
|
||||
}
|
||||
|
||||
//
|
||||
// This copies the bytes in the right order (so that they appear correct
|
||||
// when dumped as a sequence of chars)
|
||||
//
|
||||
RtlCopyMemory(&FxDriverGlobals->Tag,
|
||||
pBegin,
|
||||
length);
|
||||
|
||||
FxDriverGlobals->Public.DriverTag = FxDriverGlobals->Tag;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDriver::Initialize(
|
||||
__in PCUNICODE_STRING ArgRegistryPath,
|
||||
__in PWDF_DRIVER_CONFIG Config,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
|
||||
NTSTATUS status;
|
||||
|
||||
// WDFDRIVER can not be deleted by the device driver
|
||||
MarkNoDeleteDDI();
|
||||
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
|
||||
//
|
||||
// Configure Constraints
|
||||
//
|
||||
ConfigureConstraints(DriverAttributes);
|
||||
|
||||
if (m_DriverObject.GetObject() == NULL) {
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// Allocate FxDisposeList
|
||||
status = FxDisposeList::_Create(FxDriverGlobals, m_DriverObject.GetObject(), &m_DisposeList);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Store FxDriver in Driver object extension
|
||||
//
|
||||
status = AllocateDriverObjectExtensionAndStoreFxDriver();
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Store away the callback functions.
|
||||
//
|
||||
if ((Config->DriverInitFlags & WdfDriverInitNoDispatchOverride) == 0) {
|
||||
//
|
||||
// Caller doesn't want to override the dispatch table. That
|
||||
// means that they want to create everything and still be in
|
||||
// control (or at least the port driver will take over)
|
||||
//
|
||||
m_DriverDeviceAdd.Method = Config->EvtDriverDeviceAdd;
|
||||
m_DriverUnload.Method = Config->EvtDriverUnload;
|
||||
}
|
||||
|
||||
if (ArgRegistryPath != NULL) {
|
||||
USHORT length;
|
||||
|
||||
length = ArgRegistryPath->Length + sizeof(UNICODE_NULL);
|
||||
|
||||
m_RegistryPath.Length = ArgRegistryPath->Length;
|
||||
m_RegistryPath.MaximumLength = length;
|
||||
m_RegistryPath.Buffer = (PWSTR) FxPoolAllocate(
|
||||
GetDriverGlobals(), PagedPool, length);
|
||||
|
||||
if (m_RegistryPath.Buffer != NULL) {
|
||||
RtlCopyMemory(m_RegistryPath.Buffer,
|
||||
ArgRegistryPath->Buffer,
|
||||
ArgRegistryPath->Length);
|
||||
|
||||
//
|
||||
// other parts of WDF assumes m_RegistryPath.Buffer is
|
||||
// a null terminated string. make sure it is.
|
||||
//
|
||||
m_RegistryPath.Buffer[length/sizeof(WCHAR)- 1] = UNICODE_NULL;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// We failed to allocate space for the registry path
|
||||
// so set the length to 0.
|
||||
//
|
||||
m_RegistryPath.Length = 0;
|
||||
m_RegistryPath.MaximumLength = 0;
|
||||
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
if ((Config->DriverInitFlags & WdfDriverInitNoDispatchOverride) == 0) {
|
||||
UCHAR i;
|
||||
|
||||
//
|
||||
// Set up dispatch routines.
|
||||
//
|
||||
if (Config->DriverInitFlags & WdfDriverInitNonPnpDriver) {
|
||||
//
|
||||
// NT4 style drivers must clear the AddDevice field in the
|
||||
// driver object so that they can be unloaded while still
|
||||
// having device objects around.
|
||||
//
|
||||
// If AddDevice is set, NT considers the driver a pnp driver
|
||||
// and will not allow net stop to unload the driver.
|
||||
//
|
||||
m_DriverObject.SetDriverExtensionAddDevice(NULL);
|
||||
|
||||
//
|
||||
// Unload for an NT4 driver is still optional if the driver
|
||||
// does not want to be stopped (through net stop for
|
||||
// instance).
|
||||
//
|
||||
if (Config->EvtDriverUnload != NULL) {
|
||||
m_DriverObject.SetDriverUnload(Unload);
|
||||
}
|
||||
else {
|
||||
m_DriverObject.SetDriverUnload(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
//
|
||||
// PnP driver, set our routines up
|
||||
//
|
||||
m_DriverObject.SetDriverExtensionAddDevice(AddDevice);
|
||||
m_DriverObject.SetDriverUnload(Unload);
|
||||
}
|
||||
|
||||
//
|
||||
// For any major control code that we use a remove lock, the
|
||||
// following locations must be updated:
|
||||
//
|
||||
// 1) FxDevice::_RequiresRemLock() which decides if the remlock
|
||||
// is required
|
||||
// 2) FxDefaultIrpHandler::Dispatch might need to be changed if
|
||||
// there is catchall generic post processing that must be done
|
||||
// 3) Whereever the major code irp handler completes the irp or
|
||||
// sends it down the stack. A good design would have all
|
||||
// spots in the irp handler where this is done to call a
|
||||
// common function.
|
||||
//
|
||||
WDFCASSERT(IRP_MN_REMOVE_DEVICE != 0x0);
|
||||
|
||||
#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
|
||||
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
|
||||
if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) {
|
||||
m_DriverObject.SetMajorFunction(i, FxDevice::Dispatch);
|
||||
}
|
||||
else {
|
||||
m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLock);
|
||||
}
|
||||
}
|
||||
#else // USER_MODE
|
||||
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
|
||||
if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) {
|
||||
m_DriverObject.SetMajorFunction(i, FxDevice::DispatchUm);
|
||||
}
|
||||
else {
|
||||
m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLockUm);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Determine if the debugger is connected.
|
||||
//
|
||||
#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
|
||||
if (KD_DEBUGGER_ENABLED == TRUE && KD_DEBUGGER_NOT_PRESENT == FALSE) {
|
||||
m_DebuggerConnected = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Log this notable event after tracing has been initialized.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if ((Config->DriverInitFlags & WdfDriverInitNonPnpDriver) &&
|
||||
Config->EvtDriverUnload == NULL) {
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER,
|
||||
"Driver Object %p, reg path %wZ cannot be "
|
||||
"unloaded, no DriverUnload routine specified",
|
||||
m_DriverObject.GetObject(), &m_RegistryPath);
|
||||
}
|
||||
|
||||
#if FX_IS_USER_MODE
|
||||
//
|
||||
// Open a R/W handle to the driver's service parameters key
|
||||
//
|
||||
status = OpenParametersKey();
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Cannot open Driver Parameters key %!STATUS!",
|
||||
status);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxString *
|
||||
FxDriver::GetRegistryPath(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
FxString *pString;
|
||||
|
||||
pString = new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES)
|
||||
FxString(GetDriverGlobals());
|
||||
|
||||
if (pString != NULL) {
|
||||
NTSTATUS status;
|
||||
|
||||
status = pString->Assign(m_RegistryPath.Buffer);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pString->Release();
|
||||
pString = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pString;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FxDriver::ConfigureConstraints(
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Determine the pointer to the proper lock to acquire
|
||||
for event callbacks from the FxDriver to the device driver
|
||||
depending on the configured locking model.
|
||||
|
||||
Arguments:
|
||||
DriverAttributes - caller supplied scope and level, used only if they
|
||||
are not InheritFromParent.
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
BOOLEAN automaticLockingRequired;
|
||||
|
||||
automaticLockingRequired = FALSE;
|
||||
|
||||
// Initialize the mutex lock
|
||||
m_CallbackMutexLock.Initialize(this);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
MarkPassiveCallbacks(ObjectDoNotLock);
|
||||
|
||||
m_CallbackLockPtr = &m_CallbackMutexLock;
|
||||
m_CallbackLockObjectPtr = this;
|
||||
|
||||
//
|
||||
// Use the caller supplied scope and level only if they are not
|
||||
// InheritFromParent.
|
||||
//
|
||||
if (DriverAttributes != NULL) {
|
||||
|
||||
if (DriverAttributes->ExecutionLevel !=
|
||||
WdfExecutionLevelInheritFromParent) {
|
||||
m_ExecutionLevel = DriverAttributes->ExecutionLevel;
|
||||
}
|
||||
|
||||
if (DriverAttributes->SynchronizationScope !=
|
||||
WdfSynchronizationScopeInheritFromParent) {
|
||||
m_SynchronizationScope = DriverAttributes->SynchronizationScope;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If the driver asks for any synchronization, we synchronize the
|
||||
// WDFDRIVER object's own callbacks as well.
|
||||
//
|
||||
// (No option to extend synchronization for regular operations
|
||||
// across all WDFDEVICE objects)
|
||||
//
|
||||
if (m_SynchronizationScope == WdfSynchronizationScopeDevice ||
|
||||
m_SynchronizationScope == WdfSynchronizationScopeQueue) {
|
||||
|
||||
automaticLockingRequired = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// No FxDriver events are delivered from a thread that is
|
||||
// not already at PASSIVE_LEVEL, so we don't need to
|
||||
// allocate an FxSystemWorkItem if the execution level
|
||||
// constraint is WdfExecutionLevelPassive.
|
||||
//
|
||||
// If any events are added FxDriver that could occur on a thread
|
||||
// that is above PASSIVE_LEVEL, then an FxSystemWorkItem would
|
||||
// need to be allocated to deliver those events similar to the
|
||||
// code in FxIoQueue.
|
||||
//
|
||||
|
||||
//
|
||||
// Configure FxDriver event callback locks
|
||||
//
|
||||
if (automaticLockingRequired) {
|
||||
m_DriverDeviceAdd.SetCallbackLockPtr(m_CallbackLockPtr);
|
||||
}
|
||||
else {
|
||||
m_DriverDeviceAdd.SetCallbackLockPtr(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,522 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDriverApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains the "C" interface for the FxDriver object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include <ntverp.h>
|
||||
#include "FxDriverApi.tmh"
|
||||
}
|
||||
|
||||
#include "FxTelemetry.hpp"
|
||||
|
||||
//
|
||||
// extern the whole file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
//
|
||||
// Driver Pool Allocations
|
||||
//
|
||||
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
PWSTR
|
||||
WDFEXPORT(WdfDriverGetRegistryPath)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDRIVER Driver
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxDriver *pDriver;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Driver,
|
||||
FX_TYPE_DRIVER,
|
||||
(PVOID *)&pDriver,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pDriver->GetRegistryPathUnicodeString()->Buffer;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDriverCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
MdDriverObject DriverObject,
|
||||
__in
|
||||
PCUNICODE_STRING RegistryPath,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES DriverAttributes,
|
||||
__in
|
||||
PWDF_DRIVER_CONFIG DriverConfig,
|
||||
__out_opt
|
||||
WDFDRIVER* Driver
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDriver *pDriver;
|
||||
NTSTATUS status;
|
||||
WDFDRIVER hDriver;
|
||||
const LONG validFlags = WdfDriverInitNonPnpDriver |
|
||||
WdfDriverInitNoDispatchOverride;
|
||||
|
||||
hDriver = NULL;
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, DriverObject);
|
||||
FxPointerNotNull(pFxDriverGlobals, RegistryPath);
|
||||
FxPointerNotNull(pFxDriverGlobals, DriverConfig);
|
||||
|
||||
//
|
||||
// Validate the size of the input Driver Config structure. The size changed
|
||||
// after v1.1. The size is the same for v1.1 and v1.0, verify that.
|
||||
//
|
||||
WDFCASSERT(sizeof(WDF_DRIVER_CONFIG_V1_0) == sizeof(WDF_DRIVER_CONFIG_V1_1));
|
||||
|
||||
if (DriverConfig->Size != sizeof(WDF_DRIVER_CONFIG)
|
||||
&&
|
||||
DriverConfig->Size != sizeof(WDF_DRIVER_CONFIG_V1_1)) {
|
||||
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"WDF_DRIVER_CONFIG got Size %d, expected v1.1 size %d or cur ver size %d, %!STATUS!",
|
||||
DriverConfig->Size,
|
||||
sizeof(WDF_DRIVER_CONFIG_V1_1), sizeof(WDF_DRIVER_CONFIG), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate the DriverInitFlags value in the Driver Config.
|
||||
//
|
||||
if ((DriverConfig->DriverInitFlags & ~validFlags) != 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"DriverInitFlags 0x%x invalid, valid flags are 0x%x, %!STATUS!",
|
||||
DriverConfig->DriverInitFlags, validFlags, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateUnicodeString(pFxDriverGlobals, RegistryPath);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Driver and Public.Driver are set once WdfDriverCreate returns successfully.
|
||||
// If they are set, that means this DDI has already been called for this
|
||||
// client. Return an error if this occurrs.
|
||||
//
|
||||
if (pFxDriverGlobals->Driver != NULL ||
|
||||
pFxDriverGlobals->Public.Driver != NULL) {
|
||||
|
||||
status = STATUS_DRIVER_INTERNAL_ERROR;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"WdfDriverCreate can only be called one time per "
|
||||
"WDM PDRIVER_OBJECT %p, %!STATUS!",
|
||||
DriverObject, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Driver != NULL) {
|
||||
*Driver = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Initializing the tag requires initializing the driver name first.
|
||||
//
|
||||
FxDriver::_InitializeDriverName(pFxDriverGlobals, RegistryPath);
|
||||
|
||||
//
|
||||
// Initialize the tag before any allocation so that we can use the correct
|
||||
// tag value when allocating on behalf of the driver (for all allocations,
|
||||
// including FxDriver).
|
||||
//
|
||||
// Use the client's driver tag value if they specified one. First check
|
||||
// to make sure the size of the structure is the new size (vs the old size
|
||||
// in v1.1).
|
||||
//
|
||||
// ' kdD' - was the default tag in many DDKs, don't allow its use.
|
||||
//
|
||||
if (DriverConfig->Size == sizeof(WDF_DRIVER_CONFIG) &&
|
||||
DriverConfig->DriverPoolTag != 0x0 &&
|
||||
DriverConfig->DriverPoolTag != ' kdD') {
|
||||
//
|
||||
// Copy directly using the driver's value
|
||||
//
|
||||
pFxDriverGlobals->Tag = DriverConfig->DriverPoolTag;
|
||||
pFxDriverGlobals->Public.DriverTag = DriverConfig->DriverPoolTag;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Derive the value from the driver's service name
|
||||
//
|
||||
FxDriver::_InitializeTag(pFxDriverGlobals, DriverConfig);
|
||||
}
|
||||
|
||||
//
|
||||
// Check to see if this is an NT4 style device driver. If so, fail if they
|
||||
// specified an AddDevice routine. If no dispatch override is set,
|
||||
// do not do any checking at all.
|
||||
//
|
||||
if (DriverConfig->DriverInitFlags & WdfDriverInitNoDispatchOverride) {
|
||||
DO_NOTHING();
|
||||
}
|
||||
else if ((DriverConfig->DriverInitFlags & WdfDriverInitNonPnpDriver) &&
|
||||
DriverConfig->EvtDriverDeviceAdd != NULL) {
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Invalid Driver flags or EvtDriverDeviceAdd callback already added"
|
||||
"STATUS_INVALID_PARAMETER");
|
||||
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, DriverAttributes,
|
||||
(FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED |
|
||||
FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED |
|
||||
FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED)
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// FxDriver stores the driver wide configuration
|
||||
//
|
||||
FxInitialize(pFxDriverGlobals, DriverObject, RegistryPath, DriverConfig);
|
||||
|
||||
//
|
||||
// FxDriver stores the driver wide configuration
|
||||
//
|
||||
pDriver = new(pFxDriverGlobals, DriverAttributes)
|
||||
FxDriver(DriverObject, DriverConfig, pFxDriverGlobals);
|
||||
|
||||
if (pDriver != NULL) {
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
|
||||
status = pDriver->Initialize(RegistryPath, DriverConfig, DriverAttributes);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = pDriver->Commit(DriverAttributes, (WDFOBJECT*)&hDriver, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// Only return a valid handle on success. Upon error, release any memory
|
||||
// and do not rely on any other function (like the driver unload routine) to
|
||||
// be called.
|
||||
//
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// **** Note ****
|
||||
// Do not introduce failures after this point without ensuring
|
||||
// FxObject::DeleteFromFailedCreate has a chance to clear out any
|
||||
// assigned callbacks on the object.
|
||||
//
|
||||
|
||||
//
|
||||
// Store the WDFDRIVER and FxDriver* globally so the driver can retrieve
|
||||
// it anytime.
|
||||
//
|
||||
pFxDriverGlobals->Driver = pDriver;
|
||||
pFxDriverGlobals->Public.Driver = hDriver;
|
||||
|
||||
//
|
||||
// Record the flags so that diagnostics knows what type of driver it is.
|
||||
//
|
||||
pFxDriverGlobals->Public.DriverFlags |= DriverConfig->DriverInitFlags;
|
||||
|
||||
if (DriverConfig->DriverInitFlags &
|
||||
(WdfDriverInitNoDispatchOverride | WdfDriverInitNonPnpDriver)) {
|
||||
//
|
||||
// If there is no dispatch override or if it is an NT4 legacy style
|
||||
// driver then we will not displace unload in the stub if one was not
|
||||
// specified.
|
||||
//
|
||||
if (DriverConfig->EvtDriverUnload != NULL) {
|
||||
pFxDriverGlobals->Public.DisplaceDriverUnload = TRUE;
|
||||
}
|
||||
else {
|
||||
pFxDriverGlobals->Public.DisplaceDriverUnload = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pFxDriverGlobals->Public.DisplaceDriverUnload = TRUE;
|
||||
}
|
||||
|
||||
if (Driver != NULL) {
|
||||
*Driver = hDriver;
|
||||
}
|
||||
|
||||
if (FX_TELEMETRY_ENABLED(g_TelemetryProvider, pFxDriverGlobals)) {
|
||||
FxAutoString imageName;
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
const PWCHAR pVersionStr =
|
||||
FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WDF_BUILD_NUMBER) ;
|
||||
#else // USER_MODE
|
||||
const PWCHAR pVersionStr =
|
||||
FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WUDF_SERVICE_VERSION) ;
|
||||
#endif
|
||||
|
||||
//
|
||||
// GetImageName can fail if the registry cannot be accessed. This
|
||||
// can happen during system shutdown. Since the image name is only
|
||||
// used for telemetry the failure can be ignored.
|
||||
//
|
||||
(VOID) GetImageName(pFxDriverGlobals, &imageName.m_UnicodeString);
|
||||
|
||||
WDF_CENSUS_EVT_WRITE_DRIVER_LOAD(g_TelemetryProvider,
|
||||
pFxDriverGlobals,
|
||||
imageName.m_UnicodeString.Buffer,
|
||||
pVersionStr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (pDriver != NULL) {
|
||||
pDriver->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
FxDestroy(pFxDriverGlobals);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDriverRegisterTraceInfo)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PDRIVER_OBJECT DriverObject,
|
||||
__in
|
||||
PFN_WDF_TRACE_CALLBACK EvtTraceCallback,
|
||||
__in
|
||||
PVOID ControlBlock
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
UNREFERENCED_PARAMETER(DriverGlobals);
|
||||
UNREFERENCED_PARAMETER(DriverObject);
|
||||
UNREFERENCED_PARAMETER(EvtTraceCallback);
|
||||
UNREFERENCED_PARAMETER(ControlBlock);
|
||||
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDriverRetrieveVersionString)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDRIVER Driver,
|
||||
__in
|
||||
WDFSTRING String
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDriver* pDriver;
|
||||
FxString* pString;
|
||||
NTSTATUS status;
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
const PWCHAR pVersionStr =
|
||||
L"Kernel Mode Driver Framework version "
|
||||
FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WDF_BUILD_NUMBER) ;
|
||||
|
||||
const PWCHAR pVersionStrVerifier =
|
||||
L"Kernel Mode Driver Framework (verifier on) version "
|
||||
FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WDF_BUILD_NUMBER);
|
||||
#else // USER_MODE
|
||||
const PWCHAR pVersionStr =
|
||||
L"User Mode Driver Framework version "
|
||||
FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WUDF_SERVICE_VERSION) ;
|
||||
|
||||
const PWCHAR pVersionStrVerifier =
|
||||
L"User Mode Driver Framework (verifier on) version "
|
||||
FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"."
|
||||
FX_MAKE_WSTR(__WUDF_SERVICE_VERSION);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Even though it is unused, still convert it to make sure a valid handle is
|
||||
// being passed in.
|
||||
//
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Driver,
|
||||
FX_TYPE_DRIVER,
|
||||
(PVOID *)&pDriver,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, String);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtr(pFxDriverGlobals,
|
||||
String,
|
||||
FX_TYPE_STRING,
|
||||
(PVOID *)&pString);
|
||||
|
||||
status = pString->Assign(
|
||||
pFxDriverGlobals->FxVerifierOn ? pVersionStrVerifier : pVersionStr
|
||||
);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
BOOLEAN
|
||||
WDFEXPORT(WdfDriverIsVersionAvailable)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDRIVER Driver,
|
||||
__in
|
||||
PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDriver* pDriver;
|
||||
NTSTATUS status;
|
||||
ULONG major, minor;
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
major = __WDF_MAJOR_VERSION;
|
||||
minor = __WDF_MINOR_VERSION;
|
||||
#else
|
||||
major = __WUDF_MAJOR_VERSION;
|
||||
minor = __WUDF_MINOR_VERSION;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Even though it is unused, still convert it to make sure a valid handle is
|
||||
// being passed in.
|
||||
//
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Driver,
|
||||
FX_TYPE_DRIVER,
|
||||
(PVOID *)&pDriver,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, VersionAvailableParams);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (VersionAvailableParams->Size != sizeof(WDF_DRIVER_VERSION_AVAILABLE_PARAMS)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"VersionAvailableParams Size 0x%x, expected 0x%x, %!STATUS!",
|
||||
VersionAvailableParams->Size, sizeof(WDF_DRIVER_VERSION_AVAILABLE_PARAMS),
|
||||
status);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// We log at TRACE_LEVEL_INFORMATION so that we know it gets into the IFR at
|
||||
// all times. This will make it easier to debug drivers which fail to load
|
||||
// when a new minor version of WDF is installed b/c they are failing
|
||||
// version checks.
|
||||
//
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER,
|
||||
"IsVersionAvailable, current WDF ver major %d, minor %d, caller asking "
|
||||
"about major %d, minor %d", major, minor,
|
||||
VersionAvailableParams->MajorVersion, VersionAvailableParams->MinorVersion);
|
||||
|
||||
//
|
||||
// Currently we only support one major version per KMDF binary and we support
|
||||
// all minor versions of that major version down to 0x0.
|
||||
//
|
||||
if (VersionAvailableParams->MajorVersion == major &&
|
||||
VersionAvailableParams->MinorVersion <= minor) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,565 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxFileObject.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed FileObject
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxFileObject.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Public constructors
|
||||
//
|
||||
|
||||
|
||||
FxFileObject::FxFileObject(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in MdFileObject pWdmFileObject,
|
||||
__in FxDevice* pDevice
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_FILEOBJECT, sizeof(FxFileObject), FxDriverGlobals)
|
||||
{
|
||||
m_FileObject.SetFileObject(pWdmFileObject);
|
||||
m_PkgContext = NULL;
|
||||
m_Device = pDevice;
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
RtlInitUnicodeString(&m_FileName, NULL);
|
||||
m_RelatedFileObject = NULL;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Cannot be deleted by the device driver
|
||||
//
|
||||
MarkNoDeleteDDI();
|
||||
}
|
||||
|
||||
FxFileObject::~FxFileObject()
|
||||
{
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
SAFE_RELEASE(m_RelatedFileObject);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Create the WDFFILEOBJECT and associate it with the WDM PFILE_OBJECT.
|
||||
//
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxFileObject::_CreateFileObject(
|
||||
__in FxDevice* pDevice,
|
||||
__in MdIrp Irp,
|
||||
__in WDF_FILEOBJECT_CLASS FileObjectClass,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES pObjectAttributes,
|
||||
__in_opt MdFileObject pWdmFileObject,
|
||||
__deref_out_opt FxFileObject** pFileObject
|
||||
)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
FxFileObject* pfo;
|
||||
KIRQL irql;
|
||||
WDF_FILEOBJECT_CLASS normalizedFileClass;
|
||||
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
|
||||
|
||||
//
|
||||
// Create does require a WDM file obj based on the normalized file obj
|
||||
// class value.
|
||||
//
|
||||
normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);
|
||||
|
||||
//
|
||||
// No FileObject support
|
||||
//
|
||||
if( normalizedFileClass == WdfFileObjectNotRequired ) {
|
||||
if( pFileObject != NULL ) *pFileObject = NULL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// If fileobject support was specified, and a NULL
|
||||
// WDM PFILE_OBJECT is supplied, then it's an error
|
||||
//
|
||||
if( pWdmFileObject == NULL ) {
|
||||
|
||||
//
|
||||
// Seems like some filter driver above us sending a create without fileobject.
|
||||
// We support this only if the FileObjectClass class is set to
|
||||
// WdfFileObjectWdfCannotUseFsContexts and device is created to be
|
||||
// exclusive.
|
||||
//
|
||||
if ( normalizedFileClass == WdfFileObjectWdfCannotUseFsContexts &&
|
||||
pDevice->IsExclusive() ) {
|
||||
|
||||
DO_NOTHING();
|
||||
|
||||
} else {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"WdfFileObjectWdfCanUseFsContexts is specified, but the Create "
|
||||
"IRP %p doesn't have a fileObject\n",
|
||||
Irp);
|
||||
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
||||
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Allocate a new FxFileObject with context
|
||||
pfo = new(pDevice->GetDriverGlobals(), pObjectAttributes)
|
||||
FxFileObject(pDevice->GetDriverGlobals(), pWdmFileObject, pDevice);
|
||||
|
||||
if( pfo == NULL ) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
pfo->Initialize(Irp);
|
||||
|
||||
// Assign FxDevice as the parent for the file object
|
||||
Status = pfo->Commit(pObjectAttributes, NULL, pDevice);
|
||||
if( !NT_SUCCESS(Status) ) {
|
||||
pfo->DeleteFromFailedCreate();
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Place it on the list of FxFileObject's for this FxDevice
|
||||
//
|
||||
pDevice->Lock(&irql);
|
||||
InsertHeadList(&pDevice->m_FileObjectListHead, &pfo->m_Link);
|
||||
pDevice->Unlock(irql);
|
||||
|
||||
//
|
||||
// Set file object context in mode-specific manner
|
||||
//
|
||||
pfo->SetFileObjectContext(pWdmFileObject,
|
||||
normalizedFileClass,
|
||||
Irp,
|
||||
pDevice);
|
||||
|
||||
// FxFileObject* to caller
|
||||
if( pFileObject != NULL ) {
|
||||
*pFileObject = pfo;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Destroy (dereference) the WDFFILEOBJECT related to the
|
||||
// WDM PFILE_OBJECT according to its FileObjectClass.
|
||||
//
|
||||
VOID
|
||||
FxFileObject::_DestroyFileObject(
|
||||
__in FxDevice* pDevice,
|
||||
__in WDF_FILEOBJECT_CLASS FileObjectClass,
|
||||
__in_opt MdFileObject pWdmFileObject
|
||||
)
|
||||
{
|
||||
FxFileObject* pfo = NULL;
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
|
||||
WDF_FILEOBJECT_CLASS normalizedFileClass;
|
||||
|
||||
//
|
||||
// Close does require a WDM file obj based on the normalized file obj
|
||||
// class value.
|
||||
//
|
||||
normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);
|
||||
|
||||
if( normalizedFileClass == WdfFileObjectNotRequired ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Driver has specified file object support, and we
|
||||
// allocated one at Create, so they must pass one
|
||||
// to close, otherwise it's an error and we will leak
|
||||
// the file object.
|
||||
//
|
||||
MxFileObject wdmFileObject(pWdmFileObject);
|
||||
if( pWdmFileObject == NULL &&
|
||||
normalizedFileClass != WdfFileObjectWdfCannotUseFsContexts) {
|
||||
|
||||
//
|
||||
// It's likely that IRP_MJ_CREATE had NULL for the Wdm FileObject as well.
|
||||
//
|
||||
// If a driver passes != NULL for Wdm FileObject to create, and NULL to
|
||||
// this routine, a WDF FxFileObject object leak will occur, which will
|
||||
// be reported at driver unload.
|
||||
//
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"PFILE_OBJECT in close IRP is NULL, *Possible Leak of FxFileObject*\n");
|
||||
|
||||
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
||||
|
||||
return;
|
||||
}
|
||||
else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) {
|
||||
pfo = (FxFileObject*)wdmFileObject.GetFsContext();
|
||||
wdmFileObject.SetFsContext(NULL);
|
||||
|
||||
}
|
||||
else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) {
|
||||
pfo = (FxFileObject*)wdmFileObject.GetFsContext2();
|
||||
wdmFileObject.SetFsContext2(NULL);
|
||||
}
|
||||
else {
|
||||
NTSTATUS status;
|
||||
//
|
||||
// We must find the associated FxFileObject from the list
|
||||
// on the device
|
||||
//
|
||||
status = FxFileObject::_GetFileObjectFromWdm(
|
||||
pDevice,
|
||||
WdfFileObjectWdfCannotUseFsContexts,
|
||||
pWdmFileObject,
|
||||
&pfo
|
||||
);
|
||||
|
||||
//
|
||||
// We should find it, unless a different one was passed to IRP_MJ_CLOSE
|
||||
// than to IRP_MJ_CREATE, which is an error.
|
||||
//
|
||||
if (NT_SUCCESS(status) == FALSE || pfo == NULL) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not find WDFFILEOBJECT for PFILE_OBJECT 0x%p",
|
||||
pWdmFileObject);
|
||||
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Did a different PFILE_OBJECT get passed to "
|
||||
"IRP_MJ_CLOSE than did to IRP_MJ_CREATE?");
|
||||
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
||||
}
|
||||
}
|
||||
|
||||
if( pfo != NULL ) {
|
||||
KIRQL irql;
|
||||
|
||||
//
|
||||
// Remove it from the list of FxFileObjects on the FxDevice
|
||||
//
|
||||
pDevice->Lock(&irql);
|
||||
RemoveEntryList(&pfo->m_Link);
|
||||
pDevice->Unlock(irql);
|
||||
|
||||
// Delete the file object
|
||||
pfo->DeleteObject();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Return the FxFileObject* for the given WDM PFILE_OBJECT
|
||||
//
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxFileObject::_GetFileObjectFromWdm(
|
||||
__in FxDevice* pDevice,
|
||||
__in WDF_FILEOBJECT_CLASS FileObjectClass,
|
||||
__in_opt MdFileObject pWdmFileObject,
|
||||
__deref_out_opt FxFileObject** ppFxFileObject
|
||||
)
|
||||
{
|
||||
FxFileObject* pfo = NULL;
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
|
||||
WDF_FILEOBJECT_CLASS normalizedFileClass;
|
||||
|
||||
//
|
||||
// Normalize file object class value.
|
||||
//
|
||||
normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);
|
||||
|
||||
//
|
||||
// No FileObject support
|
||||
//
|
||||
if( normalizedFileClass == WdfFileObjectNotRequired ) {
|
||||
*ppFxFileObject = NULL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if( pWdmFileObject == NULL ) {
|
||||
|
||||
//
|
||||
// Warn if an I/O request has NULL for the WDM PFILE_OBJECT
|
||||
//
|
||||
if ( pDevice->IsExclusive() &&
|
||||
normalizedFileClass == WdfFileObjectWdfCannotUseFsContexts ) {
|
||||
//
|
||||
// We allow a NULL file object iff the device is exclusive and
|
||||
// we have to look up the WDFFILEOBJECT by PFILE_OBJECT value
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
else if ( FxIsFileObjectOptional(FileObjectClass) ) {
|
||||
//
|
||||
// Driver told us that it's able to handle this case.
|
||||
//
|
||||
*ppFxFileObject = NULL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"NULL passed for PFILE_OBJECT when FileObject "
|
||||
"support is requested in an I/O request");
|
||||
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
||||
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Depending on the drivers configuration, we can quickly
|
||||
// get the FxFileObject* from FxContext, or FxContext2.
|
||||
//
|
||||
// Some drivers can not touch either of the FxContext(s), and
|
||||
// in that case we must resort to a list or hashtable.
|
||||
//
|
||||
MxFileObject wdmFileObject(pWdmFileObject);
|
||||
if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) {
|
||||
pfo = (FxFileObject*)wdmFileObject.GetFsContext();
|
||||
}
|
||||
else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) {
|
||||
pfo = (FxFileObject*)wdmFileObject.GetFsContext2();
|
||||
}
|
||||
else {
|
||||
PLIST_ENTRY next;
|
||||
FxFileObject* f;
|
||||
KIRQL irql;
|
||||
|
||||
//
|
||||
// Must look it up from the FxDevice->m_FileObjectListHead.
|
||||
//
|
||||
pfo = NULL;
|
||||
|
||||
pDevice->Lock(&irql);
|
||||
|
||||
next = pDevice->m_FileObjectListHead.Flink;
|
||||
|
||||
if(pWdmFileObject == NULL) {
|
||||
//
|
||||
// If the pWdmFileObject is NULL then we will pass the first entry
|
||||
// in the list because the device must be exclusive and there
|
||||
// can be only one fileobject in the list.
|
||||
//
|
||||
ASSERT(IsListEmpty(&pDevice->m_FileObjectListHead) == FALSE);
|
||||
|
||||
f = CONTAINING_RECORD(next, FxFileObject, m_Link);
|
||||
pfo = f;
|
||||
|
||||
} else {
|
||||
|
||||
while( next != &pDevice->m_FileObjectListHead ) {
|
||||
f = CONTAINING_RECORD(next, FxFileObject, m_Link);
|
||||
|
||||
if( f->m_FileObject.GetFileObject()== pWdmFileObject ) {
|
||||
pfo = f;
|
||||
break;
|
||||
}
|
||||
|
||||
next = next->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(pfo == NULL
|
||||
&& pDevice->IsExclusive()
|
||||
&& pDevice->GetMxDeviceObject()->GetDeviceType() == FILE_DEVICE_SERIAL_PORT
|
||||
&& !IsListEmpty(&pDevice->m_FileObjectListHead)) {
|
||||
|
||||
f = CONTAINING_RECORD(pDevice->m_FileObjectListHead.Flink,
|
||||
FxFileObject, m_Link);
|
||||
pfo = f;
|
||||
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE,
|
||||
"The PFILE_OBJECT 0x%p in this request (cleanup/close) "
|
||||
"is different from the one specified in "
|
||||
"create request 0x%p.This is bad!", pWdmFileObject,
|
||||
((f != NULL) ? f->m_FileObject.GetFileObject(): NULL));
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE,
|
||||
"Since this is a serial port device, framework is "
|
||||
"using a workaround to allow this");
|
||||
}
|
||||
|
||||
pDevice->Unlock(irql);
|
||||
}
|
||||
|
||||
//
|
||||
// This can happen if a different PFILE_OBJECT is passed to an I/O
|
||||
// request than was presented to IRP_MJ_CREATE
|
||||
//
|
||||
if (pfo == NULL && FxIsFileObjectOptional(FileObjectClass) == FALSE) {
|
||||
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not locate WDFFILEOBJECT for "
|
||||
"PFILE_OBJECT 0x%p",pWdmFileObject);
|
||||
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Did a different PFILE_OBJECT get passed to the "
|
||||
"request than was to IRP_MJ_CREATE?");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) {
|
||||
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We don't do an extra reference count since the file objects
|
||||
// lifetime is controlled by the IoMgr. When the IRP_MJ_CLOSE
|
||||
// occurs, the reference is released after the optional
|
||||
// driver event callback.
|
||||
//
|
||||
|
||||
*ppFxFileObject = pfo;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxFileObject::DeleteFileObjectFromFailedCreate(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
//
|
||||
// Remove it from the list of FxFileObjects on the FxDevice
|
||||
//
|
||||
m_Device->Lock(&irql);
|
||||
RemoveEntryList(&m_Link);
|
||||
m_Device->Unlock(irql);
|
||||
|
||||
// Delete the file object
|
||||
DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxFileObject::QueryInterface(
|
||||
__in FxQueryInterfaceParams* Params
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
This routine is used to return the pointer to the Object itself.
|
||||
|
||||
Arguments:
|
||||
Params - query interface parameters.
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
switch (Params->Type) {
|
||||
case FX_TYPE_FILEOBJECT:
|
||||
*Params->Object = (FxFileObject*) this;
|
||||
break;
|
||||
|
||||
case FX_TYPE_IHASCALLBACKS:
|
||||
*Params->Object = (IFxHasCallbacks*) this;
|
||||
break;
|
||||
|
||||
default:
|
||||
return __super::QueryInterface(Params);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxFileObject::GetConstraints(
|
||||
__in WDF_EXECUTION_LEVEL* ExecutionLevel,
|
||||
__in WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
This routine implements the GetConstraints IfxCallback. The caller gets the
|
||||
ExecutionLevel and the SynchronizationScope of the FileObject. The FileObject's
|
||||
SynchronizationScope and ExecutionLevel is strored in the FxPkgGeneral object.
|
||||
|
||||
Arguments:
|
||||
ExecutionLevel - (opt) receives the execution level.
|
||||
|
||||
SynchronizationScope - (opt) receives the synchronization scope.
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
//
|
||||
// Get it from FxPkgGeneral which has the File attributes passed to it at device Creation time.
|
||||
//
|
||||
return GetDevice()->m_PkgGeneral->GetConstraintsHelper(ExecutionLevel, SynchronizationScope);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxCallbackLock*
|
||||
FxFileObject::GetCallbackLockPtr(
|
||||
__deref_out_opt FxObject** LockObject
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
This routine implements the GetCallbackLockPtr IfxCallback. The caller gets the
|
||||
LockObject to be used before calling the driver callbacks.
|
||||
|
||||
Arguments:
|
||||
LockObject - receives the lock object.
|
||||
|
||||
Return Value:
|
||||
FxCallbackLock *
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
//
|
||||
// Get it from FxPkgGeneral which has the File attributes passed to it at device Creation time.
|
||||
//
|
||||
return GetDevice()->m_PkgGeneral->GetCallbackLockPtrHelper(LockObject);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxFileObjectApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This modules implements the C API's for the FxFileObject.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxFileObject.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxFileObjectApi.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
PUNICODE_STRING
|
||||
WDFEXPORT(WdfFileObjectGetFileName)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFFILEOBJECT FileObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This returns the UNICODE_STRING for the FileName inside
|
||||
the WDM fileobject.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - WDFFILEOBJECT
|
||||
|
||||
Return Value:
|
||||
|
||||
PUNICODE_STRING (file name)
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxFileObject* pFO;
|
||||
|
||||
//
|
||||
// Validate the FileObject object handle, and get its FxFileObject*
|
||||
//
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
FileObject,
|
||||
FX_TYPE_FILEOBJECT,
|
||||
(PVOID*)&pFO,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pFO->GetWdmFileObject() != NULL) {
|
||||
return pFO->GetFileName();
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
ULONG
|
||||
WDFEXPORT(WdfFileObjectGetFlags)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFFILEOBJECT FileObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This returns the flags inside the WDM fileobject.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - WDFFILEOBJECT
|
||||
|
||||
Return Value:
|
||||
|
||||
ULONG (flags)
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxFileObject* pFO;
|
||||
|
||||
//
|
||||
// Validate the FileObject object handle, and get its FxFileObject*
|
||||
//
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
FileObject,
|
||||
FX_TYPE_FILEOBJECT,
|
||||
(PVOID*)&pFO);
|
||||
|
||||
if (pFO->GetWdmFileObject() != NULL) {
|
||||
return pFO->GetFlags();
|
||||
}
|
||||
else {
|
||||
return 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDEVICE
|
||||
WDFEXPORT(WdfFileObjectGetDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFFILEOBJECT FileObject
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This returns the Device that the fileobject is associated with.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - WDFFILEOBJECT
|
||||
|
||||
Return Value:
|
||||
|
||||
WDFDEVICE
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxFileObject* pFO;
|
||||
|
||||
//
|
||||
// Validate the FileObject object handle, and get its FxFileObject*
|
||||
//
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
FileObject,
|
||||
FX_TYPE_FILEOBJECT,
|
||||
(PVOID*)&pFO);
|
||||
|
||||
return pFO->GetDevice()->GetHandle();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,964 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxIrpQueue.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a common queue structure for the
|
||||
driver frameworks built around the Cancel Safe Queue model
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxIrpQueue.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Public constructors
|
||||
//
|
||||
|
||||
FxIrpQueue::FxIrpQueue(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
InitializeListHead(&m_Queue);
|
||||
|
||||
m_LockObject = NULL;
|
||||
|
||||
m_CancelCallback = NULL;
|
||||
|
||||
m_RequestCount = 0;
|
||||
}
|
||||
|
||||
FxIrpQueue::~FxIrpQueue()
|
||||
{
|
||||
ASSERT(IsListEmpty(&m_Queue));
|
||||
}
|
||||
|
||||
VOID
|
||||
FxIrpQueue::Initialize(
|
||||
__in FxNonPagedObject* LockObject,
|
||||
__in PFN_IRP_QUEUE_CANCEL Callback
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize the FxIrpQueue.
|
||||
|
||||
Set the callback for when an IRP gets cancelled.
|
||||
|
||||
The callback function is only called when an IRP
|
||||
gets cancelled, and is called with no locks held.
|
||||
|
||||
The cancel function that the caller registers is
|
||||
responsible for completing the IRP with IoCompleteRequest.
|
||||
|
||||
If no Cancel Callback is set, or is set to NULL, IRP's will
|
||||
be automatically completed with STATUS_CANCELED by
|
||||
the FxIrpQueue when they are canceled.
|
||||
|
||||
|
||||
If the caller supplies a LockObject, this object is used
|
||||
to synchronize cancellation access to the list, but it is
|
||||
expected that the caller be holding the same lock for insert/remove
|
||||
operations. This allows the caller to perform insert/remove operations
|
||||
using its own lock in a race free manner.
|
||||
|
||||
If a LockObject is not supplied, the FxIrpQueue uses its own lock.
|
||||
|
||||
Arguments:
|
||||
|
||||
LockObject - Object whose lock controls the queue
|
||||
|
||||
Callback - Driver callback function
|
||||
|
||||
Returns:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ASSERT(LockObject != NULL);
|
||||
|
||||
m_CancelCallback = Callback;
|
||||
m_LockObject = LockObject;
|
||||
}
|
||||
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxIrpQueue::InsertTailRequest(
|
||||
__inout MdIrp Irp,
|
||||
__in_opt PMdIoCsqIrpContext Context,
|
||||
__out_opt ULONG* pRequestCount
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Enqueue a request to the end of the queue (FIFO) and
|
||||
marks it as pending.
|
||||
|
||||
The PMdIoCsqIrpContext is associated with the IRP.
|
||||
|
||||
PIO_CSQ_IRP_CONTEXT must be in non-paged pool, and can
|
||||
not be released until the IRP is is finally released from
|
||||
the queue.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Pointer to IRP
|
||||
|
||||
Context - Pointer to caller allocated CSQ context
|
||||
|
||||
pRequestCount - Location to return new request count of queue
|
||||
after insertion
|
||||
|
||||
Returns:
|
||||
|
||||
STATUS_SUCCESS - Operation completed.
|
||||
|
||||
STATUS_CANCELLED - Request was cancelled, and not inserted
|
||||
Call is responsible for completing it.
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
// Note: This marks the IRP Pending
|
||||
Status = InsertIrpInQueue(
|
||||
Irp, // Irp to insert
|
||||
Context, // PIO_CSQ_IRP_CONTEXT
|
||||
FALSE, // InsertInHead
|
||||
pRequestCount
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxIrpQueue::InsertHeadRequest(
|
||||
__inout MdIrp Irp,
|
||||
__in_opt PMdIoCsqIrpContext Context,
|
||||
__out_opt ULONG* pRequestCount
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Enqueue a request to the head of the queue and
|
||||
marks it as pending.
|
||||
|
||||
The PIO_CSQ_IRP_CONTEXT is associated with the IRP.
|
||||
|
||||
PIO_CSQ_IRP_CONTEXT must be in non-paged pool, and can
|
||||
not be released until the IRP is is finally released from
|
||||
the queue.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Pointer to IRP
|
||||
|
||||
Context - Pointer to caller allocated CSQ context
|
||||
|
||||
pRequestCount - Location to return new request count of queue
|
||||
after insertion
|
||||
Returns:
|
||||
|
||||
STATUS_SUCCESS - Operation completed.
|
||||
|
||||
STATUS_CANCELLED - Request was cancelled, and not inserted
|
||||
Call is responsible for completing it.
|
||||
--*/
|
||||
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
// Note: This marks the IRP Pending
|
||||
Status = InsertIrpInQueue(
|
||||
Irp, // Irp to insert
|
||||
Context, // PIO_CSQ_IRP_CONTEXT
|
||||
TRUE, // InsertInHead
|
||||
pRequestCount
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
MdIrp
|
||||
FxIrpQueue::GetNextRequest(
|
||||
__out PMdIoCsqIrpContext* pCsqContext
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Returns an IRP from the queue, and if successful
|
||||
the IRP is no longer on the CSQ (m_Queue) and
|
||||
is not non-cancellable.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
return RemoveNextIrpFromQueue(NULL, pCsqContext);
|
||||
}
|
||||
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxIrpQueue::GetNextRequest(
|
||||
__in_opt PMdIoCsqIrpContext TagContext,
|
||||
__in_opt MdFileObject FileObject,
|
||||
__out FxRequest** ppOutRequest
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Returns a request from the queue using an optional
|
||||
FileObject or TagContext.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
MdIrp Irp;
|
||||
FxRequest* pRequest;
|
||||
PMdIoCsqIrpContext pCsqContext;
|
||||
|
||||
if( TagContext == NULL ) {
|
||||
|
||||
//
|
||||
// Returns an IRP from the queue, and if successful
|
||||
// the IRP is no longer on the CSQ (m_Queue) and
|
||||
// is not non-cancellable.
|
||||
//
|
||||
Irp = RemoveNextIrpFromQueue(
|
||||
FileObject, // PeekContext
|
||||
&pCsqContext
|
||||
);
|
||||
|
||||
if( Irp != NULL ) {
|
||||
|
||||
pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext);
|
||||
|
||||
*ppOutRequest = pRequest;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return STATUS_NO_MORE_ENTRIES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// Handle TagRequest Case
|
||||
Irp = RemoveIrpFromQueueByContext(
|
||||
TagContext
|
||||
);
|
||||
|
||||
if( Irp != NULL ) {
|
||||
pRequest = FxRequest::RetrieveFromCsqContext(TagContext);
|
||||
|
||||
*ppOutRequest = pRequest;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return STATUS_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxIrpQueue::PeekRequest(
|
||||
__in_opt PMdIoCsqIrpContext TagContext,
|
||||
__in_opt MdFileObject FileObject,
|
||||
__out FxRequest** ppOutRequest
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
PeekRequest allows a caller to enumerate through requests in
|
||||
a queue, optionally only returning requests that match a specified
|
||||
FileObject.
|
||||
|
||||
The first call specifies TagContext == NULL, and the first request
|
||||
in the queue that matches the FileObject is returned.
|
||||
|
||||
Subsequent requests specify the previous request value as the
|
||||
TagContext, and searching will continue at the request that follows.
|
||||
|
||||
If the queue is empty, there are no requests after TagContext, or no
|
||||
requests match the FileObject, NULL is returned.
|
||||
|
||||
If FileObject == NULL, this matches any FileObject in a request.
|
||||
|
||||
If a WDF_REQUEST_PARAMETERS structure is supplied, the information
|
||||
from the request is returned to allow the driver to further examine
|
||||
the request to decide whether to service it.
|
||||
|
||||
If a TagRequest is specified, and it is not found, the return
|
||||
status STATUS_NOT_FOUND means that the queue should
|
||||
be re-scanned. This is because the TagRequest was cancelled from
|
||||
the queue, or if the queue was active, delivered to the driver.
|
||||
There may still be un-examined requests on the queue that match
|
||||
the drivers search criteria, but the search marker has been lost.
|
||||
|
||||
Re-scanning the queue starting with TagRequest == NULL and
|
||||
continuing until STATUS_NO_MORE_ENTRIES is returned will ensure
|
||||
all requests have been examined.
|
||||
|
||||
Enumerating an active queue with this API could result in the
|
||||
driver frequently having to re-scan.
|
||||
|
||||
If a successful return of a Request object handle occurs, the driver
|
||||
*must* call WdfObjectDereference when done with it.
|
||||
|
||||
NOTE: Synchronization Details
|
||||
|
||||
The driver is allowed to "peek" at requests that are still on
|
||||
the Cancel Safe Queue without removing them. This means that
|
||||
the peek context value used (TagRequest) could go away while
|
||||
still holding it. This does not seem bad in itself, but the request
|
||||
could immediately be re-used by a look aside list and be re-submitted
|
||||
to the queue. At this point, the "tag" value means a completely different
|
||||
request.
|
||||
|
||||
This race is dealt with by reference counting the FxRequest object
|
||||
that contains our PIO_CSQ_IRP_CONTEXT, so its memory remains valid
|
||||
after a cancel, and the driver explicitly releases it with
|
||||
WdfObjectDereference.
|
||||
|
||||
But if this reference is not added under the CSQ's spinlock, there
|
||||
could be a race in which the I/O gets cancelled and the cancel
|
||||
callback completes the request, before we add our reference count.
|
||||
This would then result in attempting to reference count invalid
|
||||
memory. So to close this race, this routine returns the referenced
|
||||
FxRequest object as its result.
|
||||
|
||||
Arguments:
|
||||
|
||||
TagRequest - If !NULL, request to begin search at
|
||||
|
||||
FileObject - If !NULL, FileObject to match in the request
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
STATUS_NOT_FOUND - TagContext was specified, but not
|
||||
found in the queue. This could be
|
||||
because the request was cancelled,
|
||||
or is part of an active queue and
|
||||
the request was passed to the driver
|
||||
or forwarded to another queue.
|
||||
|
||||
STATUS_NO_MORE_ENTRYS - The queue is empty, or no more requests
|
||||
match the selection criteria of TagRequest
|
||||
and FileObject specified above.
|
||||
|
||||
STATUS_SUCCESS - A request context was returned in
|
||||
pOutRequest.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PLIST_ENTRY nextEntry;
|
||||
FxIrp nextIrp(NULL);
|
||||
PMdIoCsqIrpContext pCsqContext;
|
||||
BOOLEAN FoundTag = (TagContext == NULL) ? TRUE : FALSE;
|
||||
FxRequest* pRequest;
|
||||
|
||||
for( nextEntry = m_Queue.Flink; nextEntry != &this->m_Queue; nextEntry = nextEntry->Flink) {
|
||||
|
||||
nextIrp.SetIrp(FxIrp::GetIrpFromListEntry(nextEntry));
|
||||
|
||||
if(nextIrp.IsCanceled()) {
|
||||
//
|
||||
// This IRP is cancelled and the WdmCancelRoutine is about to run or waiting
|
||||
// for us to drop the lock. So skip this one.
|
||||
//
|
||||
continue;
|
||||
}
|
||||
|
||||
pCsqContext = (PMdIoCsqIrpContext)nextIrp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY);
|
||||
|
||||
if( FoundTag ) {
|
||||
|
||||
if( FileObject != NULL ) {
|
||||
|
||||
if(nextIrp.GetFileObject() == FileObject ) {
|
||||
|
||||
pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext);
|
||||
|
||||
//
|
||||
// Must add the reference here under the protection
|
||||
// of the cancel safe queues spinlock
|
||||
//
|
||||
pRequest->ADDREF(NULL);
|
||||
|
||||
*ppOutRequest = pRequest;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext);
|
||||
|
||||
//
|
||||
// Must add the reference here under the protection
|
||||
// of the cancel safe queues spinlock
|
||||
//
|
||||
pRequest->ADDREF(NULL);
|
||||
|
||||
*ppOutRequest = pRequest;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// If we found the tag, we want the *next* entry
|
||||
if( pCsqContext == TagContext ) {
|
||||
FoundTag = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// If the caller supplied a tag, and it was
|
||||
// not found, return a different code since
|
||||
// the caller needs to re-scan the queue.
|
||||
//
|
||||
if( (TagContext != NULL) && !FoundTag ) {
|
||||
return STATUS_NOT_FOUND;
|
||||
}
|
||||
else {
|
||||
return STATUS_NO_MORE_ENTRIES;
|
||||
}
|
||||
}
|
||||
|
||||
MdIrp
|
||||
FxIrpQueue::RemoveRequest(
|
||||
__in PMdIoCsqIrpContext Context
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Returns a request from the queue.
|
||||
|
||||
--*/
|
||||
{
|
||||
MdIrp Irp;
|
||||
|
||||
ASSERT(Context != NULL);
|
||||
|
||||
//
|
||||
// Returns an IRP from the queue, and if success
|
||||
// the IRP is no longer on the CSQ (m_Queue) and
|
||||
// is not non-cancellable.
|
||||
//
|
||||
Irp = RemoveIrpFromQueueByContext(Context);
|
||||
|
||||
return Irp;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxIrpQueue::InsertIrpInQueue(
|
||||
__inout MdIrp Irp,
|
||||
__in_opt PMdIoCsqIrpContext Context,
|
||||
__in BOOLEAN InsertInHead,
|
||||
__out_opt ULONG* pRequestCount
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Insert the IRP in the queue. If the IRP is already cancelled
|
||||
it removes the IRP from the queue and returns STATUS_CANCELLED.
|
||||
|
||||
If the IRP is cancelled and the CancelRoutine has already started
|
||||
execution, then this function returns STATUS_SUCCESS.
|
||||
|
||||
Arguments:
|
||||
|
||||
Irp - Pointer to IRP
|
||||
|
||||
Context - Pointer to caller allocated CSQ context
|
||||
|
||||
InsertInHead - TRUE for head, FALSE for tail.
|
||||
|
||||
pRequestCount - Location to return new request count of queue
|
||||
after insertion
|
||||
|
||||
Returns:
|
||||
|
||||
STATUS_SUCCESS - Operation completed.
|
||||
|
||||
STATUS_CANCELLED - if the request is already cancelled.
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIrp irp(Irp);
|
||||
MdCancelRoutine cancelRoutine;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
//
|
||||
// Set the association between the context and the IRP.
|
||||
//
|
||||
|
||||
if (Context) {
|
||||
irp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, Context);
|
||||
Context->Irp = Irp;
|
||||
Context->Csq = (PIO_CSQ)this;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Context->Type = FX_IRP_QUEUE_ENTRY_IDENTIFIER;
|
||||
} else {
|
||||
|
||||
//
|
||||
// Currently always require context, but this will change when we
|
||||
// allow queuing or low level IRP's without FxRequest headers allocated
|
||||
//
|
||||
ASSERT(FALSE);
|
||||
|
||||
irp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, this);
|
||||
}
|
||||
|
||||
// See if it's a head insertion
|
||||
if( InsertInHead ) {
|
||||
InsertHeadList(
|
||||
&m_Queue,
|
||||
irp.ListEntry()
|
||||
);
|
||||
}
|
||||
else {
|
||||
InsertTailList(
|
||||
&m_Queue,
|
||||
irp.ListEntry()
|
||||
);
|
||||
}
|
||||
|
||||
m_RequestCount++;
|
||||
|
||||
if( pRequestCount != NULL ) {
|
||||
*pRequestCount = m_RequestCount;
|
||||
}
|
||||
|
||||
irp.MarkIrpPending();
|
||||
|
||||
cancelRoutine = irp.SetCancelRoutine(_WdmCancelRoutineInternal);
|
||||
|
||||
ASSERT(!cancelRoutine);
|
||||
UNREFERENCED_PARAMETER(cancelRoutine);
|
||||
|
||||
if (irp.IsCanceled()) {
|
||||
|
||||
cancelRoutine = irp.SetCancelRoutine(NULL);
|
||||
|
||||
if (cancelRoutine) {
|
||||
|
||||
// Remove the IRP from the list
|
||||
RemoveIrpFromListEntry(&irp);
|
||||
|
||||
if (Context) {
|
||||
Context->Irp = NULL;
|
||||
}
|
||||
|
||||
irp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, NULL);
|
||||
|
||||
//
|
||||
// Caller does not want us to recurse on their lock by invoking
|
||||
// the m_CancelCallback on the insert path. So they will complete
|
||||
// the IRP themselves.
|
||||
//
|
||||
return STATUS_CANCELLED;
|
||||
} else {
|
||||
|
||||
//
|
||||
// The cancel routine beat us to it.
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FX_VF_METHOD(FxIrpQueue, VerifyRemoveIrpFromQueueByContext)(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PMdIoCsqIrpContext Context
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Makes sure that the specified Request (context) belongs to this IRP queue.
|
||||
|
||||
--*/
|
||||
{
|
||||
PAGED_CODE_LOCKED();
|
||||
|
||||
if (FxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) {
|
||||
if (Context->Irp != NULL &&
|
||||
(Context->Type != FX_IRP_QUEUE_ENTRY_IDENTIFIER ||
|
||||
Context->Csq != (PIO_CSQ)this)) {
|
||||
|
||||
//
|
||||
// This should never happen. Bugcheck before corrupting memory.
|
||||
//
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
|
||||
"Irp 0x%p (Context 0x%p) not on IRP queue 0x%p\n",
|
||||
Context->Irp, Context, this);
|
||||
|
||||
FxVerifierBugCheck(FxDriverGlobals,
|
||||
WDF_REQUEST_FATAL_ERROR,
|
||||
WDF_REQUEST_FATAL_ERROR_REQUEST_NOT_IN_QUEUE,
|
||||
(ULONG_PTR) Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MdIrp
|
||||
FxIrpQueue::RemoveIrpFromQueueByContext(
|
||||
__in PMdIoCsqIrpContext Context
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Using the context it remove the associated IRP from the queue.
|
||||
|
||||
--*/
|
||||
{
|
||||
MdIrp irp;
|
||||
MdCancelRoutine cancelRoutine;
|
||||
|
||||
if (Context->Irp ) {
|
||||
//
|
||||
// Make sure the Irp belongs to this queue.
|
||||
//
|
||||
ASSERT(Context->Csq == (PIO_CSQ)this);
|
||||
VerifyRemoveIrpFromQueueByContext(m_LockObject->GetDriverGlobals(),
|
||||
Context);
|
||||
|
||||
irp = Context->Irp;
|
||||
|
||||
FxIrp fxIrp(irp);
|
||||
|
||||
cancelRoutine = fxIrp.SetCancelRoutine(NULL);
|
||||
if (!cancelRoutine) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASSERT(Context == fxIrp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY));
|
||||
|
||||
RemoveIrpFromListEntry(&fxIrp);
|
||||
|
||||
//
|
||||
// Break the association.
|
||||
//
|
||||
|
||||
Context->Irp = NULL;
|
||||
fxIrp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, NULL);
|
||||
|
||||
ASSERT(Context->Csq == (PIO_CSQ)this);
|
||||
|
||||
return irp;
|
||||
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MdIrp
|
||||
FxIrpQueue::PeekNextIrpFromQueue(
|
||||
__in_opt MdIrp Irp,
|
||||
__in_opt PVOID PeekContext
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This API look up IRP's in the queue.
|
||||
|
||||
If Irp == NULL, it returns one from the head
|
||||
of the queue.
|
||||
|
||||
If Irp != NULL, it is a "peek context", and the
|
||||
routine returns the *next* IRP in the queue.
|
||||
|
||||
--*/
|
||||
{
|
||||
PLIST_ENTRY nextEntry;
|
||||
PLIST_ENTRY listHead;
|
||||
FxIrp irp(Irp);
|
||||
FxIrp nextIrp(NULL);
|
||||
|
||||
listHead = &m_Queue;
|
||||
|
||||
//
|
||||
// If the IRP is NULL, we will start peeking from the listhead, else
|
||||
// we will start from that IRP onwards. This is done under the
|
||||
// assumption that new IRPs are always inserted at the tail.
|
||||
//
|
||||
|
||||
if(Irp == NULL) {
|
||||
nextEntry = listHead->Flink;
|
||||
} else {
|
||||
nextEntry = irp.ListEntry()->Flink;
|
||||
}
|
||||
|
||||
while(nextEntry != listHead) {
|
||||
|
||||
nextIrp.SetIrp(FxIrp::GetIrpFromListEntry(nextEntry));
|
||||
|
||||
//
|
||||
// If PeekContext is supplied, it's a search for an IRP associated
|
||||
// with a particular file object.
|
||||
//
|
||||
if(PeekContext) {
|
||||
|
||||
if(nextIrp.GetFileObject() == (MdFileObject) PeekContext) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
nextIrp.SetIrp(NULL);
|
||||
|
||||
nextEntry = nextEntry->Flink;
|
||||
}
|
||||
|
||||
return nextIrp.GetIrp();
|
||||
}
|
||||
|
||||
MdIrp
|
||||
FxIrpQueue::RemoveNextIrpFromQueue(
|
||||
__in_opt PVOID PeekContext,
|
||||
__out_opt PMdIoCsqIrpContext* pCsqContext
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine will return a pointer to the next IRP in the queue adjacent to
|
||||
the irp passed as a parameter. If the irp is NULL, it returns the IRP at the head of
|
||||
the queue.
|
||||
|
||||
--*/
|
||||
{
|
||||
PMdIoCsqIrpContext context;
|
||||
MdCancelRoutine cancelRoutine;
|
||||
FxIrp fxIrp(NULL);
|
||||
|
||||
fxIrp.SetIrp(PeekNextIrpFromQueue(NULL, PeekContext));
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (!fxIrp.GetIrp()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cancelRoutine = fxIrp.SetCancelRoutine(NULL);
|
||||
if (!cancelRoutine) {
|
||||
fxIrp.SetIrp(PeekNextIrpFromQueue(fxIrp.GetIrp(), PeekContext));
|
||||
continue;
|
||||
}
|
||||
|
||||
RemoveIrpFromListEntry(&fxIrp); // Remove this IRP from the queue
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
context = (PMdIoCsqIrpContext)fxIrp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY);
|
||||
if (context->Type == FX_IRP_QUEUE_ENTRY_IDENTIFIER) {
|
||||
context->Irp = NULL;
|
||||
ASSERT(context->Csq == (PIO_CSQ)this);
|
||||
}
|
||||
|
||||
if(pCsqContext != NULL) {
|
||||
*pCsqContext = context;
|
||||
}
|
||||
|
||||
fxIrp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, NULL);
|
||||
|
||||
return fxIrp.GetIrp();
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FxIrpQueue::_WdmCancelRoutineInternal(
|
||||
__inout MdDeviceObject DeviceObject,
|
||||
__in __drv_useCancelIRQL MdIrp Irp
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the function called by WDM on the IRP when a cancel occurs
|
||||
|
||||
--*/
|
||||
{
|
||||
PMdIoCsqIrpContext irpContext;
|
||||
FxIrpQueue* p;
|
||||
KIRQL irql;
|
||||
FxIrp irp(Irp);
|
||||
|
||||
UNREFERENCED_PARAMETER (DeviceObject);
|
||||
|
||||
Mx::ReleaseCancelSpinLock(irp.GetCancelIrql());
|
||||
|
||||
irpContext = (PMdIoCsqIrpContext)irp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY);
|
||||
|
||||
//
|
||||
// Decide if we have a PIO_CSQ_IRP_CONTEXT or an FxIrpQueue*
|
||||
//
|
||||
if (irpContext->Type == FX_IRP_QUEUE_ENTRY_IDENTIFIER) {
|
||||
p = (FxIrpQueue*)irpContext->Csq;
|
||||
} else {
|
||||
ASSERT(FALSE);
|
||||
p = (FxIrpQueue*)irpContext;
|
||||
}
|
||||
|
||||
ASSERT(p);
|
||||
|
||||
p->LockFromCancel(&irql);
|
||||
|
||||
// Remove the IRP from the list
|
||||
p->RemoveIrpFromListEntry(&irp);
|
||||
|
||||
//
|
||||
// Break the association if necessary.
|
||||
//
|
||||
|
||||
if (irpContext != (PMdIoCsqIrpContext)p) {
|
||||
irpContext->Irp = NULL;
|
||||
|
||||
irp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, NULL);
|
||||
}
|
||||
|
||||
//
|
||||
// We are calling cancel-callback of the owning object with the lock
|
||||
// held so that it can successfully deliver the canceled request to the driver
|
||||
// if needed. If we don't hold the lock, we run into a race condition between
|
||||
// thread that's deleting the queue and this routine that's trying to deliver
|
||||
// a request to the queue being deleted. So the way it happens is that the dispose
|
||||
// call of queue waits for the request count to go zero. When we remove the
|
||||
// last Irp from the list above, we end up dropping the count to zero. This causes
|
||||
// the delete thread to run thru and destroy the FxIoQueue object. So to avoid that
|
||||
// after popping the request from the FxIrpQueue, we have to call into the FxIoQueue
|
||||
// with the lock and insert the request back into the FxIoQueue list so that delete
|
||||
// thread will wait until the request is delivered to the driver.
|
||||
//
|
||||
if( p->m_CancelCallback != NULL ) {
|
||||
p->m_CancelCallback(p, Irp, irpContext, irql);
|
||||
}
|
||||
else {
|
||||
|
||||
p->UnlockFromCancel(irql);
|
||||
|
||||
//
|
||||
// Dispose of the IRP ourselves
|
||||
//
|
||||
irp.SetStatus(STATUS_CANCELLED);
|
||||
irp.SetInformation(0);
|
||||
|
||||
DoTraceLevelMessage(p->m_LockObject->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Irp 0x%p on Queue 0x%p Cancelled\n", Irp, p);
|
||||
|
||||
//
|
||||
// Breakpoint for now. This usually means that someone
|
||||
// is going to leak some driver frameworks state...
|
||||
//
|
||||
FxVerifierDbgBreakPoint(p->m_LockObject->GetDriverGlobals());
|
||||
|
||||
irp.CompleteRequest(IO_NO_INCREMENT);
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxIrpQueue::IsIrpInQueue(
|
||||
__in PMdIoCsqIrpContext Context
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Enumerates the list to see if any of the IRPs there has
|
||||
a context that matches the input one.
|
||||
|
||||
--*/
|
||||
{
|
||||
PLIST_ENTRY nextEntry;
|
||||
FxIrp nextIrp(NULL);
|
||||
PMdIoCsqIrpContext pCsqContext;
|
||||
|
||||
nextEntry = m_Queue.Flink;
|
||||
|
||||
while( nextEntry != &m_Queue ) {
|
||||
nextIrp.SetIrp(FxIrp::GetIrpFromListEntry(nextEntry));
|
||||
|
||||
pCsqContext = (PMdIoCsqIrpContext)nextIrp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY);
|
||||
|
||||
if( pCsqContext == Context ) {
|
||||
ASSERT(Context->Irp == nextIrp.GetIrp());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
nextEntry = nextEntry->Flink;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxLock.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains the implementation of FxLock
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
VOID
|
||||
FxLock::Initialize(
|
||||
__in FxObject * ParentObject
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
This is called to initialize the verifier with the object type so it can
|
||||
track lock order and sequence.
|
||||
|
||||
Arguments:
|
||||
ParentObject - the owning object
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
pFxDriverGlobals = ParentObject->GetDriverGlobals();
|
||||
|
||||
if (pFxDriverGlobals->FxVerifierLock) {
|
||||
//
|
||||
// Allocation failure is not fatal, we just won't track anything
|
||||
//
|
||||
|
||||
(void) FxVerifierLock::CreateAndInitialize(&m_Verifier,
|
||||
pFxDriverGlobals,
|
||||
ParentObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxLookasideList.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed FxLookasideList
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxLookasideList.hpp"
|
||||
|
||||
FxLookasideList::FxLookasideList(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in USHORT ObjectSize,
|
||||
__in ULONG PoolTag
|
||||
) :
|
||||
FxObject(FX_TYPE_LOOKASIDE, ObjectSize, FxDriverGlobals),
|
||||
m_BufferSize(0), m_PoolTag(PoolTag), m_MemoryObjectSize(0)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for FxLookasideList
|
||||
|
||||
Arguments:
|
||||
ObjectSize - Size of the derived object.
|
||||
|
||||
PoolTag - Tag to use when allocating memory.
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
FxLookasideList::~FxLookasideList()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for FxLookasideList. Default implementation does nothing.
|
||||
Derived classes will call the appropriate NTOS export to remove itself from
|
||||
the list of lookaside lists.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxLookasideList::InitializeLookaside(
|
||||
__in USHORT BufferSize,
|
||||
__in USHORT MemoryObjectSize,
|
||||
__in PWDF_OBJECT_ATTRIBUTES MemoryAttributes
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Computes the memory object size to be used by the derived class. This
|
||||
function handles the overflow in computing the size and returns an error
|
||||
if that occurs.
|
||||
|
||||
Arguments:
|
||||
BufferSize - the length of the buffer being allocated alongside the object
|
||||
|
||||
MemoryObjectSize - the raw size of the FxObject derived object, ie
|
||||
sizeof(FxMemoryBufferFromLookaside)
|
||||
|
||||
MemoryAttributes - attributes to be associated for each memory object created
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
size_t size;
|
||||
NTSTATUS status;
|
||||
|
||||
if (MemoryAttributes != NULL) {
|
||||
RtlCopyMemory(&m_MemoryAttributes,
|
||||
MemoryAttributes,
|
||||
sizeof(m_MemoryAttributes));
|
||||
}
|
||||
else {
|
||||
RtlZeroMemory(&m_MemoryAttributes, sizeof(m_MemoryAttributes));
|
||||
}
|
||||
|
||||
status = FxCalculateObjectTotalSize(GetDriverGlobals(),
|
||||
MemoryObjectSize,
|
||||
BufferSize,
|
||||
&m_MemoryAttributes,
|
||||
&size);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
//
|
||||
// FxCalculateObjectTotalSize logs an error to the IFR
|
||||
//
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxPoolAddHeaderSize(GetDriverGlobals(), size, &size);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
//
|
||||
// FxPoolAddHeaderSize logs to the IFR on error
|
||||
//
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// It is *required* to set these values only once we know we are returning
|
||||
// success b/c the derived classes use == 0 as an indication that Initialization
|
||||
// failed and that any associated lookaside lists were not initialized.
|
||||
//
|
||||
m_MemoryObjectSize = size;
|
||||
m_BufferSize = BufferSize;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#pragma prefast(push)
|
||||
|
||||
|
||||
|
||||
//This routine intentionally accesses the header of the allocated memory.
|
||||
#pragma prefast(disable:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY)
|
||||
PVOID
|
||||
FxLookasideList::InitObjectAlloc(
|
||||
__out_bcount(this->m_MemoryObjectSize) PVOID Alloc
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Initializes the object allocation so that it can be tracked and inserted
|
||||
in this drivers POOL.
|
||||
|
||||
Arguments:
|
||||
Alloc - the raw allocation
|
||||
|
||||
Return Value:
|
||||
the start of where the object memory should be, not necessarily == Alloc
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
PFX_POOL_HEADER pHeader;
|
||||
PFX_POOL_TRACKER tracker;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
RtlZeroMemory(Alloc, m_MemoryObjectSize);
|
||||
|
||||
if (pFxDriverGlobals->IsPoolTrackingOn()) {
|
||||
//
|
||||
// PoolTracking is active, so format and insert
|
||||
// a tracker in the NonPagedHeader list of the pool.
|
||||
//
|
||||
tracker = (PFX_POOL_TRACKER) Alloc;
|
||||
pHeader = WDF_PTR_ADD_OFFSET_TYPE(Alloc,
|
||||
sizeof(FX_POOL_TRACKER),
|
||||
PFX_POOL_HEADER);
|
||||
|
||||
pHeader->Base = Alloc;
|
||||
pHeader->FxDriverGlobals = pFxDriverGlobals;
|
||||
|
||||
FxPoolInsertNonPagedAllocateTracker(
|
||||
&pFxDriverGlobals->FxPoolFrameworks,
|
||||
tracker,
|
||||
m_BufferSize,
|
||||
m_PoolTag,
|
||||
_ReturnAddress());
|
||||
}
|
||||
else {
|
||||
//
|
||||
// PoolTracking is inactive, only format FX_POOL_HEADER area.
|
||||
//
|
||||
pHeader = (PFX_POOL_HEADER) Alloc;
|
||||
pHeader->Base = Alloc;
|
||||
pHeader->FxDriverGlobals = pFxDriverGlobals;
|
||||
}
|
||||
|
||||
return &pHeader->AllocationStart[0];
|
||||
}
|
||||
#pragma prefast(pop)
|
||||
|
||||
VOID
|
||||
FxLookasideList::_Reclaim(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__inout PNPAGED_LOOKASIDE_LIST List,
|
||||
__in FxMemoryBufferFromLookaside* Memory
|
||||
)
|
||||
{
|
||||
PFX_POOL_HEADER pHeader;
|
||||
|
||||
pHeader = FxObject::_CleanupPointer(FxDriverGlobals, (FxObject*) Memory);
|
||||
|
||||
FxFreeToNPagedLookasideList(List, pHeader->Base);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxLookasideListApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This modules implements the C API's for the FxLookasideList.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxNPagedLookasideList.hpp"
|
||||
#include "FxPagedLookasideList.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxLookasideListAPI.tmh"
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_when(PoolType == 1 || PoolType == 257, __drv_maxIRQL(APC_LEVEL))
|
||||
__drv_when(PoolType == 0 || PoolType == 256, __drv_maxIRQL(DISPATCH_LEVEL))
|
||||
NTSTATUS
|
||||
WDFAPI
|
||||
WDFEXPORT(WdfLookasideListCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES LookasideAttributes,
|
||||
__in
|
||||
__drv_when(BufferSize == 0, __drv_reportError(BufferSize cannot be zero))
|
||||
size_t BufferSize,
|
||||
__in
|
||||
__drv_strictTypeMatch(__drv_typeExpr)
|
||||
POOL_TYPE PoolType,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES MemoryAttributes,
|
||||
__in_opt
|
||||
ULONG PoolTag,
|
||||
__out
|
||||
WDFLOOKASIDE* PLookaside
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Creates a WDFLOOKASIDE list handle. The returned handle can then create
|
||||
WDFMEMORY handles on behalf of the client driver. The underlying
|
||||
WDFLOOKASIDE is a true NTOS lookaside list (of the appropriate paged or
|
||||
npaged variety).
|
||||
|
||||
Arguments:
|
||||
LookasideAttributes - Object attributes for the lookaside handle being
|
||||
created
|
||||
|
||||
BufferSize - Specifies how big each buffer created by the lookaside is
|
||||
|
||||
PoolType - Indicates whether the lookaside list is to create paged or
|
||||
nonpaged WDFMEMORY handles.
|
||||
|
||||
MemoryAttributes - Attributes to be associated with each memory handle created
|
||||
using the created lookaside list handle
|
||||
|
||||
PoolTag - Pool tag to use for each allocation. If 0, the frameworks tag
|
||||
will be used
|
||||
|
||||
PLookaside - Pointer to store the created handle
|
||||
|
||||
Return Value:
|
||||
STATUS_INVALID_PARAMETER if any of the required parameters are incorrect
|
||||
|
||||
STATUS_INSUFFICIENT_RESOURCES if no memory is available to create the list
|
||||
|
||||
STATUS SUCCESS if succesful
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxLookasideList *pLookaside;
|
||||
WDFLOOKASIDE hLookaside;
|
||||
NTSTATUS status;
|
||||
FxObject* pParent;
|
||||
|
||||
pParent = NULL;
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
//
|
||||
// Get the parent's globals if it is present
|
||||
//
|
||||
if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(
|
||||
pFxDriverGlobals,
|
||||
LookasideAttributes))) {
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
LookasideAttributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
}
|
||||
else if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(
|
||||
pFxDriverGlobals,
|
||||
MemoryAttributes))) {
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
MemoryAttributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
}
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, PLookaside);
|
||||
|
||||
hLookaside = NULL;
|
||||
*PLookaside = NULL;
|
||||
|
||||
if (BufferSize == 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Zero BufferSize not allowed, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, LookasideAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, MemoryAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (PoolTag == 0) {
|
||||
PoolTag = pFxDriverGlobals->Tag;
|
||||
}
|
||||
|
||||
FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, PoolTag);
|
||||
|
||||
//
|
||||
// Create the appropriate object
|
||||
//
|
||||
if (FxIsPagedPoolType(PoolType) == FALSE) {
|
||||
if (BufferSize < PAGE_SIZE) {
|
||||
pLookaside = new(pFxDriverGlobals, LookasideAttributes)
|
||||
FxNPagedLookasideList(pFxDriverGlobals, PoolTag);
|
||||
}
|
||||
else {
|
||||
pLookaside = new(pFxDriverGlobals, LookasideAttributes)
|
||||
FxNPagedLookasideListFromPool(pFxDriverGlobals, PoolTag);
|
||||
}
|
||||
}
|
||||
else {
|
||||
FxDeviceBase* pLookasideDB, *pMemoryDB;
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
pLookasideDB = FxDeviceBase::_SearchForDevice(pFxDriverGlobals,
|
||||
LookasideAttributes);
|
||||
|
||||
pMemoryDB = FxDeviceBase::_SearchForDevice(pFxDriverGlobals,
|
||||
MemoryAttributes);
|
||||
|
||||
if (pLookasideDB != NULL && pMemoryDB != NULL &&
|
||||
pLookasideDB != pMemoryDB) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
//
|
||||
// No need to check if LookasideAttributes or MemoryAttributes are
|
||||
// equal to NULL b/c we could not get a valid pLookasideDB or
|
||||
// pMemoryDB if they were NULL.
|
||||
//
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Lookaside Attributes ancestor WDFDEVICE %p (from ParentObject %p) "
|
||||
" is not the same as Memory Attributes ancestor WDFDEVICE %p "
|
||||
"(from ParentObject %p), %!STATUS!",
|
||||
pLookasideDB->GetHandle(), LookasideAttributes->ParentObject,
|
||||
pMemoryDB->GetHandle(), MemoryAttributes->ParentObject,
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// For paged allocations we always split the WDFMEMORY from its buffer
|
||||
// pointer because the memory behind the WDFMEMORY must be non pageable
|
||||
// while its buffer is pageable.
|
||||
//
|
||||
pLookaside = new(pFxDriverGlobals, LookasideAttributes)
|
||||
FxPagedLookasideListFromPool(pFxDriverGlobals,
|
||||
PoolTag,
|
||||
pLookasideDB,
|
||||
pMemoryDB);
|
||||
}
|
||||
|
||||
if (pLookaside == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = pLookaside->Initialize(BufferSize, MemoryAttributes);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Follow the global driver policy and either return a PVOID cookie or
|
||||
// an index into a handle table.
|
||||
//
|
||||
status = pLookaside->Commit(LookasideAttributes, (WDFOBJECT*)&hLookaside);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*PLookaside = hLookaside;
|
||||
}
|
||||
else {
|
||||
pLookaside->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFAPI
|
||||
WDFEXPORT(WdfMemoryCreateFromLookaside)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFLOOKASIDE Lookaside,
|
||||
__out
|
||||
WDFMEMORY* Memory
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Allocates a WDFMEMORY handle from a lookaside HANDLE that the caller
|
||||
previously created with WdfLookasideListCreate.
|
||||
|
||||
Arguments:
|
||||
Lookaside - Handle to a lookaside list previously created by the caller
|
||||
|
||||
Memory - Handle to be returned to the caller
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
FxLookasideList* pLookaside;
|
||||
FxMemoryObject *pMemory;
|
||||
WDFMEMORY hMemory;
|
||||
NTSTATUS status;
|
||||
|
||||
pLookaside = NULL;
|
||||
pMemory = NULL;
|
||||
|
||||
//
|
||||
// Make sure the caller passed in a valid handle
|
||||
//
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Lookaside,
|
||||
FX_TYPE_LOOKASIDE,
|
||||
(PVOID*)&pLookaside);
|
||||
|
||||
FxPointerNotNull(pLookaside->GetDriverGlobals(), Memory);
|
||||
|
||||
*Memory = NULL;
|
||||
|
||||
status = pLookaside->Allocate(&pMemory);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pMemory->Commit(&pLookaside->m_MemoryAttributes,
|
||||
(WDFOBJECT*) &hMemory);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*Memory = hMemory;
|
||||
}
|
||||
else {
|
||||
pMemory->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,181 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxMemoryBuffer.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed FxMemoryBuffer
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxMemoryBuffer.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxMemoryBuffer.tmh"
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxMemoryBuffer::_Create(
|
||||
__in PFX_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in ULONG PoolTag,
|
||||
__in size_t BufferSize,
|
||||
__in POOL_TYPE PoolType,
|
||||
__out FxMemoryObject** Object
|
||||
)
|
||||
{
|
||||
FxMemoryBuffer* pBuffer;
|
||||
|
||||
pBuffer = new(DriverGlobals, Attributes, (USHORT) BufferSize, PoolTag, PoolType)
|
||||
FxMemoryBuffer(DriverGlobals, BufferSize);
|
||||
|
||||
if (pBuffer == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
*Object = pBuffer;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
FxMemoryBuffer::FxMemoryBuffer(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in size_t BufferSize
|
||||
) :
|
||||
FxMemoryObject(FxDriverGlobals,
|
||||
(USHORT) COMPUTE_OBJECT_SIZE(sizeof(*this), (ULONG) BufferSize),
|
||||
BufferSize)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for FxMemoryBuffer. Initializes the entire data structure.
|
||||
|
||||
Arguments:
|
||||
BufferSize - Size of the buffer represented by this object
|
||||
|
||||
We round up the object size (via COMPUTE_OBJECT_SIZE) because the object,
|
||||
the context and the memory it returns via GetBuffer() are all in one allocation
|
||||
and the returned memory needs to match the alignment that raw pool follows.
|
||||
|
||||
Note on downcasting to USHORT
|
||||
==============================
|
||||
Note that FxMemoryBuffer is used for buffer less than a page size, and
|
||||
object-size and buffer-size are added and allocated together.
|
||||
Downcasting to USHORT is safe because size of object plus buffer (<page size)
|
||||
would be smaller than 64K that could fit in USHORT.
|
||||
|
||||
For buffer larger than 1 page size, object memory is allocated separately
|
||||
from buffer memory and the object used is FxMemoryBufferFromPool.
|
||||
There is no downcasting done in that case.
|
||||
|
||||
See comments in FxMemoryObject.hpp for info on various fx memory objects.
|
||||
|
||||
Assumes:
|
||||
FxMemoryBuffer::operator new has already initialized the entire allocation
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
ASSERT(BufferSize <= USHORT_MAX);
|
||||
}
|
||||
|
||||
FxMemoryBuffer::FxMemoryBuffer(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in USHORT ObjectSize,
|
||||
__in size_t BufferSize
|
||||
) :
|
||||
FxMemoryObject(FxDriverGlobals,
|
||||
(USHORT) COMPUTE_OBJECT_SIZE(ObjectSize, (ULONG) BufferSize),
|
||||
BufferSize)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for derivations FxMemoryBuffer. Initializes the entire data
|
||||
structure.
|
||||
|
||||
We round up the object size (via COMPUTE_OBJECT_SIZE) because the object,
|
||||
the context and the memory it returns via GetBuffer() are all in one allocation
|
||||
and the returned memory needs to match the alignment that raw pool follows.
|
||||
|
||||
Note on downcasting to USHORT
|
||||
==============================
|
||||
Note that FxMemoryBuffer is used for buffer less than a page size, and
|
||||
object-size and buffer-size are added and allocated together.
|
||||
Downcasting to USHORT is safe because size of object plus buffer (<page size)
|
||||
would be smaller than 64K that could fit in USHORT.
|
||||
|
||||
For buffer larger than 1 page size, object memory is allocated separately
|
||||
from buffer memory and the object used is FxMemoryBufferFromPool.
|
||||
There is no downcasting done in that case.
|
||||
|
||||
See comments in FxMemoryObject.hpp for info on various fx memory objects.
|
||||
|
||||
Arguments:
|
||||
ObjectSize - Size of the derived object
|
||||
|
||||
BufferSize - Size of the buffer represented by this object
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
ASSERT(BufferSize <= USHORT_MAX);
|
||||
}
|
||||
|
||||
FxMemoryBuffer::~FxMemoryBuffer()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for this object. Since the object + buffer is one
|
||||
allocation, there is no need to free any more memory.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
PVOID
|
||||
FxMemoryBuffer::GetBuffer(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the buffer associated with this object
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
a valid pointer, of size GetBufferSize()
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// The buffer follows the struct itself
|
||||
//
|
||||
return ((PUCHAR) this) + COMPUTE_RAW_OBJECT_SIZE(sizeof(*this));
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxMemoryBufferApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This modules implements the C API's for the FxMemoryBuffer.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxMemoryBuffer.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxMemoryBufferAPI.tmh"
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_when(PoolType == 1 || PoolType == 257, __drv_maxIRQL(APC_LEVEL))
|
||||
__drv_when(PoolType == 0 || PoolType == 256, __drv_maxIRQL(DISPATCH_LEVEL))
|
||||
WDFAPI
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfMemoryCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in
|
||||
__drv_strictTypeMatch(__drv_typeExpr)
|
||||
POOL_TYPE PoolType,
|
||||
__in_opt
|
||||
ULONG PoolTag,
|
||||
__in
|
||||
__drv_when(BufferSize == 0, __drv_reportError(BufferSize cannot be zero))
|
||||
size_t BufferSize,
|
||||
__out
|
||||
WDFMEMORY* Memory,
|
||||
__out_opt
|
||||
PVOID* Buffer
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Creates a WDFMEMORY handle based on the caller's specifications
|
||||
|
||||
Arguments:
|
||||
Attributes - Attributes associated with this object
|
||||
|
||||
PoolType - The type of pool created
|
||||
|
||||
PoolTag - Tag to use when allocating the memory. If 0, then the frameworks
|
||||
tag is used
|
||||
|
||||
BufferSize - The size of the buffer represented by the returned handle
|
||||
|
||||
Memory - The returned handle to the caller
|
||||
|
||||
Buffer - (opt) Pointer to the associated memory buffer.
|
||||
|
||||
Return Value:
|
||||
STATUS_INVALID_PARAMETER - any required parameters are not present
|
||||
|
||||
STATUS_INSUFFICIENT_RESOURCES - could not allocated the object that backs
|
||||
the handle
|
||||
|
||||
STATUS_SUCCESS - success
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxMemoryObject* pBuffer;
|
||||
WDFMEMORY hMemory;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
//
|
||||
// Get the parent's globals if it is present
|
||||
//
|
||||
if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
|
||||
Attributes))) {
|
||||
FxObject* pParent;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
Attributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
}
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Memory);
|
||||
|
||||
if (FxIsPagedPoolType(PoolType)) {
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (BufferSize == 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"BufferSize == 0 not allowed, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
*Memory = NULL;
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (PoolTag == 0) {
|
||||
PoolTag = pFxDriverGlobals->Tag;
|
||||
}
|
||||
|
||||
FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, PoolTag);
|
||||
|
||||
status = FxMemoryObject::_Create(
|
||||
pFxDriverGlobals,
|
||||
Attributes,
|
||||
PoolType,
|
||||
PoolTag,
|
||||
BufferSize,
|
||||
&pBuffer);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pBuffer->Commit(Attributes, (WDFOBJECT*)&hMemory);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*Memory = hMemory;
|
||||
if (Buffer != NULL) {
|
||||
*Buffer = pBuffer->GetBuffer();
|
||||
}
|
||||
}
|
||||
else {
|
||||
pBuffer->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PVOID
|
||||
WDFAPI
|
||||
WDFEXPORT(WdfMemoryGetBuffer)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFMEMORY Memory,
|
||||
__out_opt
|
||||
size_t* BufferSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Retrieves the raw pointers associated with WDFMEMORY handle
|
||||
|
||||
Arguments:
|
||||
Memory - handle to the WDFMEMORY
|
||||
|
||||
BufferSize - the size / length of the buffer
|
||||
|
||||
Return Value:
|
||||
raw buffer
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
IFxMemory* pMemory;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Memory,
|
||||
IFX_TYPE_MEMORY,
|
||||
(PVOID*)&pMemory);
|
||||
|
||||
if (BufferSize != NULL) {
|
||||
*BufferSize = pMemory->GetBufferSize();
|
||||
}
|
||||
|
||||
return pMemory->GetBuffer();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFAPI
|
||||
WDFEXPORT(WdfMemoryCopyToBuffer)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFMEMORY SourceMemory,
|
||||
__in
|
||||
size_t SourceOffset,
|
||||
__out_bcount( NumBytesToCopyTo)
|
||||
PVOID Buffer,
|
||||
__in
|
||||
__drv_when(NumBytesToCopyTo == 0, __drv_reportError(NumBytesToCopyTo cannot be zero))
|
||||
size_t NumBytesToCopyTo
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Copies memory from a WDFMEMORY handle to a raw pointer
|
||||
|
||||
Arguments:
|
||||
SourceMemory - Memory handle whose contents we are copying from.
|
||||
|
||||
SourceOffset - Offset into SourceMemory from which the copy starts.
|
||||
|
||||
Buffer - Memory whose contents we are copying into
|
||||
|
||||
NumBytesToCopyTo - Number of bytes to copy into buffer.
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_BUFFER_TOO_SMALL - SourceMemory is smaller than the requested number
|
||||
of bytes to be copied.
|
||||
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
IFxMemory* pSource;
|
||||
WDFMEMORY_OFFSET srcOffsets;
|
||||
WDFMEMORY_OFFSET dstOffsets;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
SourceMemory,
|
||||
IFX_TYPE_MEMORY,
|
||||
(PVOID*) &pSource);
|
||||
|
||||
pFxDriverGlobals = pSource->GetDriverGlobals();
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Buffer);
|
||||
|
||||
if (NumBytesToCopyTo == 0) {
|
||||
status =STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Zero bytes to copy not allowed, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
RtlZeroMemory(&srcOffsets, sizeof(srcOffsets));
|
||||
srcOffsets.BufferLength = NumBytesToCopyTo;
|
||||
srcOffsets.BufferOffset = SourceOffset;
|
||||
|
||||
RtlZeroMemory(&dstOffsets, sizeof(dstOffsets));
|
||||
dstOffsets.BufferLength = NumBytesToCopyTo;
|
||||
dstOffsets.BufferOffset = 0;
|
||||
|
||||
return pSource->CopyToPtr(&srcOffsets,
|
||||
Buffer,
|
||||
NumBytesToCopyTo,
|
||||
&dstOffsets);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFAPI
|
||||
WDFEXPORT(WdfMemoryCopyFromBuffer)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFMEMORY DestinationMemory,
|
||||
__in
|
||||
size_t DestinationOffset,
|
||||
__in
|
||||
PVOID Buffer,
|
||||
__in
|
||||
__drv_when(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero))
|
||||
size_t NumBytesToCopyFrom
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Copies memory from a raw pointer into a WDFMEMORY handle
|
||||
|
||||
Arguments:
|
||||
DestinationMemory - Memory handle whose contents we are copying into
|
||||
|
||||
DestinationOffset - Offset into DestinationMemory from which the copy
|
||||
starts.
|
||||
|
||||
Buffer - Buffer whose context we are copying from
|
||||
|
||||
NumBytesToCopyFrom - Number of bytes to copy from
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_INVALID_BUFFER_SIZE - DestinationMemory is not large enough to contain
|
||||
the number of bytes requested to be copied
|
||||
|
||||
NTSATUS
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
WDFMEMORY_OFFSET srcOffsets;
|
||||
WDFMEMORY_OFFSET dstOffsets;
|
||||
IFxMemory* pDest;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
DestinationMemory,
|
||||
IFX_TYPE_MEMORY,
|
||||
(PVOID*) &pDest);
|
||||
|
||||
pFxDriverGlobals = pDest->GetDriverGlobals();
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Buffer);
|
||||
|
||||
if (NumBytesToCopyFrom == 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Zero bytes to copy not allowed, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
RtlZeroMemory(&srcOffsets, sizeof(srcOffsets));
|
||||
srcOffsets.BufferLength = NumBytesToCopyFrom;
|
||||
srcOffsets.BufferOffset = 0;
|
||||
|
||||
RtlZeroMemory(&dstOffsets, sizeof(dstOffsets));
|
||||
dstOffsets.BufferLength = NumBytesToCopyFrom;
|
||||
dstOffsets.BufferOffset = DestinationOffset;
|
||||
|
||||
return pDest->CopyFromPtr(&dstOffsets,
|
||||
Buffer,
|
||||
NumBytesToCopyFrom,
|
||||
&srcOffsets);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,298 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxMemoryBufferFromLookaside.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed FxMemoryBufferFromLookaside
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxNPagedLookasideList.hpp"
|
||||
#include "FxMemoryBufferFromLookaside.hpp"
|
||||
|
||||
FxMemoryBufferFromLookaside::FxMemoryBufferFromLookaside(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__inout FxLookasideList* Lookaside,
|
||||
__in size_t BufferSize
|
||||
) :
|
||||
FxMemoryObject(FxDriverGlobals,
|
||||
COMPUTE_OBJECT_SIZE(sizeof(*this), (ULONG) BufferSize),
|
||||
BufferSize),
|
||||
m_pLookaside(Lookaside)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for this object. Remembers which lookaside list this object
|
||||
was allocated from
|
||||
|
||||
We round up the object size (via COMPUTE_OBJECT_SIZE) because the object,
|
||||
the context and the memory it returns via GetBuffer() are all in one allocation
|
||||
and the returned memory needs to match the alignment that raw pool follows.
|
||||
|
||||
Arguments:
|
||||
Lookaside - The lookaside list which this object will return itself to when
|
||||
its last reference is removed
|
||||
|
||||
BufferSize - The buffer size associated with this object
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
FxMemoryBufferFromLookaside::FxMemoryBufferFromLookaside(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__inout FxLookasideList* Lookaside,
|
||||
__in size_t BufferSize,
|
||||
__in USHORT ObjectSize
|
||||
) :
|
||||
FxMemoryObject(FxDriverGlobals, ObjectSize, BufferSize),
|
||||
m_pLookaside(Lookaside)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for this object. Remembers which lookaside list this object
|
||||
was allocated from
|
||||
|
||||
There is no round up of the ObjectSize because the derived class may not
|
||||
embed the buffer in the same allocation as the object. If it were to do so,
|
||||
the derived object should do the round up on its own.
|
||||
|
||||
Arguments:
|
||||
Lookaside - The lookaside list which this object will return itself to when
|
||||
its last reference is removed
|
||||
|
||||
BufferSize - The buffer size associated with this object
|
||||
|
||||
ObjectSize - The size of this object.
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
VOID
|
||||
FxMemoryBufferFromLookaside::Init(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
m_pLookaside->ADDREF(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FxMemoryBufferFromLookaside::~FxMemoryBufferFromLookaside()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for this object. This function does nothing, it lets
|
||||
SelfDestruct do all the work.
|
||||
|
||||
Arguments:
|
||||
|
||||
Return Value:
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PVOID
|
||||
FxMemoryBufferFromLookaside::operator new(
|
||||
__in size_t Size,
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__inout PVOID ValidMemory,
|
||||
__in size_t BufferSize,
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Displacement new operator overload. Since the lookaside list actually
|
||||
allocates the memory block, we just return the block given to us.
|
||||
|
||||
Arguments:
|
||||
Size - Compiler supplied parameter indicating the
|
||||
sizeof(FxMemoryBufferFromLookaside)
|
||||
|
||||
FxDriverGlobals - Driver's globals.
|
||||
|
||||
ValidMemory - Previously allocated block
|
||||
|
||||
BufferSize - The buffer size associated with this object
|
||||
|
||||
Attributes - Description of context.
|
||||
|
||||
Return Value:
|
||||
ValidMemory pointer value
|
||||
|
||||
--*/
|
||||
{
|
||||
size_t objectSize;
|
||||
|
||||
UNREFERENCED_PARAMETER(Size);
|
||||
|
||||
ASSERT(Size >= sizeof(FxMemoryBufferFromLookaside));
|
||||
|
||||
//
|
||||
// We round up the object size (via COMPUTE_OBJECT_SIZE) because the object,
|
||||
// and the buffer are all in one allocation and the returned memory needs to
|
||||
// match the alignment that raw pool follows.
|
||||
//
|
||||
// Note that FxMemoryBufferFromLookaside is used for buffer less than a page
|
||||
// size so downcasting to USHORT (via COMPUTE_OBJECT_SIZE) is safe because
|
||||
// size of object plus buffer (<page size) would be smaller than 64K that
|
||||
// could fit in USHORT. See comments in FxMemoryObject.hpp for info on
|
||||
// various fx memory objects.
|
||||
//
|
||||
objectSize = COMPUTE_OBJECT_SIZE(sizeof(FxMemoryBufferFromLookaside),
|
||||
(ULONG) BufferSize);
|
||||
|
||||
return FxObjectAndHandleHeaderInit(
|
||||
FxDriverGlobals,
|
||||
ValidMemory,
|
||||
(USHORT) objectSize,
|
||||
Attributes,
|
||||
FxObjectTypeExternal
|
||||
);
|
||||
}
|
||||
|
||||
PVOID
|
||||
FxMemoryBufferFromLookaside::GetBuffer()
|
||||
{
|
||||
//
|
||||
// The buffer follows the struct itself
|
||||
//
|
||||
return ((PUCHAR) this) + COMPUTE_RAW_OBJECT_SIZE(sizeof(*this));
|
||||
}
|
||||
|
||||
VOID
|
||||
FxMemoryBufferFromLookaside::SelfDestruct()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Self destruction routine called when the last reference has been removed
|
||||
on this object. This functions behaves as if "delete this" has been called
|
||||
without calling operator delete. It manually calls the destructor and then
|
||||
returns the memory to the lookaside.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
FxLookasideList* pLookaside;
|
||||
|
||||
//
|
||||
// Call the destructor first.
|
||||
//
|
||||
// Since we were allocated from a lookaside list, return ourself to this
|
||||
// list and then free the reference we have on it. We can't call this from
|
||||
// within the destructor b/c then all parent objects would be destructing on
|
||||
// freed pool.
|
||||
//
|
||||
FxMemoryBufferFromLookaside::~FxMemoryBufferFromLookaside();
|
||||
|
||||
//
|
||||
// After FxLookaside::Reclaim, this no longer points to valid memory so we
|
||||
// must stash off m_pLookaside first so we can use it after the reclaim.
|
||||
//
|
||||
pLookaside = m_pLookaside;
|
||||
pLookaside->Reclaim(this);
|
||||
pLookaside->RELEASE(this);
|
||||
}
|
||||
|
||||
FxMemoryBufferFromPoolLookaside::FxMemoryBufferFromPoolLookaside(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__inout FxLookasideList* Lookaside,
|
||||
__in size_t BufferSize,
|
||||
__in_bcount(BufferSize) PVOID Buffer
|
||||
) :
|
||||
FxMemoryBufferFromLookaside(FxDriverGlobals,
|
||||
Lookaside,
|
||||
BufferSize,
|
||||
sizeof(*this)),
|
||||
m_Pool(Buffer)
|
||||
{
|
||||
}
|
||||
|
||||
FxMemoryBufferFromPoolLookaside::FxMemoryBufferFromPoolLookaside(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__inout FxLookasideList* Lookaside,
|
||||
__in size_t BufferSize,
|
||||
__in_bcount(BufferSize) PVOID Buffer,
|
||||
__in USHORT ObjectSize
|
||||
) :
|
||||
FxMemoryBufferFromLookaside(FxDriverGlobals,
|
||||
Lookaside,
|
||||
BufferSize,
|
||||
ObjectSize),
|
||||
m_Pool(Buffer)
|
||||
{
|
||||
}
|
||||
|
||||
VOID
|
||||
FxMemoryBufferFromPoolLookaside::SelfDestruct(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Free the 2ndary allocation
|
||||
//
|
||||
((FxLookasideListFromPool*) m_pLookaside)->ReclaimPool(m_Pool);
|
||||
|
||||
//
|
||||
// Free the object itself
|
||||
//
|
||||
__super::SelfDestruct();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PVOID
|
||||
FxMemoryBufferFromPoolLookaside::operator new(
|
||||
__in size_t Size,
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__inout PVOID ValidMemory,
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes
|
||||
)
|
||||
{
|
||||
size_t objectSize;
|
||||
|
||||
UNREFERENCED_PARAMETER(Size);
|
||||
|
||||
ASSERT(Size >= sizeof(FxMemoryBufferFromPoolLookaside));
|
||||
|
||||
objectSize = COMPUTE_OBJECT_SIZE(sizeof(FxMemoryBufferFromPoolLookaside), 0);
|
||||
|
||||
return FxObjectAndHandleHeaderInit(
|
||||
FxDriverGlobals,
|
||||
ValidMemory,
|
||||
(USHORT) objectSize,
|
||||
Attributes,
|
||||
FxObjectTypeExternal
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxMemoryBufferFromPool.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed FxMemoryBufferFromPool
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
FxMemoryBufferFromPool::FxMemoryBufferFromPool(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in size_t BufferSize
|
||||
) :
|
||||
FxMemoryObject(FxDriverGlobals, sizeof(*this), BufferSize)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for this object.
|
||||
|
||||
Arguments:
|
||||
BufferSize - The buffer size associated with this object
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
m_Pool = NULL;
|
||||
}
|
||||
|
||||
FxMemoryBufferFromPool::FxMemoryBufferFromPool(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in size_t BufferSize,
|
||||
__in USHORT ObjectSize
|
||||
) :
|
||||
FxMemoryObject(FxDriverGlobals, ObjectSize, BufferSize)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for this object.
|
||||
|
||||
Arguments:
|
||||
BufferSize - The buffer size associated with this object
|
||||
|
||||
ObjectSize - size of the derived object
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
m_Pool = NULL;
|
||||
}
|
||||
|
||||
FxMemoryBufferFromPool::~FxMemoryBufferFromPool()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for this object. This function does nothing, it lets
|
||||
SelfDestruct do all the work.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
if (m_Pool != NULL) {
|
||||
MxMemory::MxFreePool(m_Pool);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxMemoryBufferFromPool::_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in POOL_TYPE PoolType,
|
||||
__in ULONG PoolTag,
|
||||
__in size_t BufferSize,
|
||||
__out FxMemoryObject** Buffer
|
||||
)
|
||||
{
|
||||
CfxDeviceBase* pDeviceBase;
|
||||
FxMemoryBufferFromPool* pBuffer;
|
||||
NTSTATUS status;
|
||||
BOOLEAN isPaged;
|
||||
|
||||
isPaged = FxIsPagedPoolType(PoolType);
|
||||
|
||||
if (isPaged) {
|
||||
pDeviceBase = FxDeviceBase::_SearchForDevice(FxDriverGlobals,
|
||||
Attributes);
|
||||
}
|
||||
else {
|
||||
pDeviceBase = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// FxMemoryBufferFromPool can handle paged allocation as well. We only
|
||||
// use FxMemoryPagedBufferFromPool if we have an FxDeviceBase that we can use
|
||||
// in the dispose path, otherwise these 2 classes are the same.
|
||||
//
|
||||
if (pDeviceBase != NULL) {
|
||||
ASSERT(isPaged);
|
||||
pBuffer = new(FxDriverGlobals, Attributes)
|
||||
FxMemoryPagedBufferFromPool(FxDriverGlobals, BufferSize, pDeviceBase);
|
||||
}
|
||||
else {
|
||||
pBuffer = new(FxDriverGlobals, Attributes)
|
||||
FxMemoryBufferFromPool(FxDriverGlobals, BufferSize);
|
||||
}
|
||||
|
||||
if (pBuffer == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
if (pBuffer->AllocateBuffer(PoolType, PoolTag) == FALSE) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pBuffer->DeleteFromFailedCreate();
|
||||
return status;
|
||||
}
|
||||
|
||||
if (isPaged) {
|
||||
//
|
||||
// Callbacks might be a bit excessive (passive dispose is what we are
|
||||
// really after) because this object has no callbacks, but this is being
|
||||
// proactive in case any callbacks are added. If they are added, this
|
||||
// will take care of them w/out additional changes to object setup.
|
||||
//
|
||||
pBuffer->MarkPassiveCallbacks(ObjectDoNotLock);
|
||||
}
|
||||
|
||||
*Buffer = pBuffer;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxMemoryBufferPreallocated.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed FxMemoryBufferPreallocated
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxMemoryBufferPreallocated.hpp"
|
||||
|
||||
FxMemoryBufferPreallocated::FxMemoryBufferPreallocated(
|
||||
_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
_Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer,
|
||||
_In_ size_t BufferSize
|
||||
) :
|
||||
FxMemoryObject(FxDriverGlobals, sizeof(*this), BufferSize),
|
||||
m_pBuffer(Buffer)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Contstructor for this object. Stores off all the pointers and sizes passed
|
||||
in by the caller.
|
||||
|
||||
Arguments:
|
||||
Buffer - Buffer to associate with this object
|
||||
|
||||
BufferSize - Size of Buffer in bytes
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
FxMemoryBufferPreallocated::FxMemoryBufferPreallocated(
|
||||
_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
_In_ USHORT ObjectSize,
|
||||
_Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer,
|
||||
_In_ size_t BufferSize
|
||||
) :
|
||||
FxMemoryObject(FxDriverGlobals, ObjectSize, BufferSize),
|
||||
m_pBuffer(Buffer)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Contstructor for this object. Stores off all the pointers and sizes passed
|
||||
in by the caller.
|
||||
|
||||
Arguments:
|
||||
ObjectSize - Size of the derived object
|
||||
|
||||
Buffer - Buffer to associate with this object
|
||||
|
||||
BufferSize - Size of Buffer in bytes
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FxMemoryBufferPreallocated::FxMemoryBufferPreallocated(
|
||||
__in USHORT ObjectSize,
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) : FxMemoryObject(FxDriverGlobals, ObjectSize, 0), m_pBuffer(NULL)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Contstructor for this object. Stores off all the pointers and sizes passed
|
||||
in by the caller.
|
||||
|
||||
Arguments:
|
||||
ObjectSize - Size of the derived object.
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
FxMemoryBufferPreallocated::~FxMemoryBufferPreallocated()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for this object. Does nothing with the client memory since
|
||||
the client owns it.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxMemoryBufferPreallocated::QueryInterface(
|
||||
__inout FxQueryInterfaceParams* Params
|
||||
)
|
||||
{
|
||||
if (Params->Type == FX_TYPE_MEMORY_PREALLOCATED) {
|
||||
*Params->Object = (FxMemoryBufferPreallocated*) this;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return __super::QueryInterface(Params);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxMemoryBufferPreallocated::UpdateBuffer(
|
||||
_Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer,
|
||||
_In_ size_t BufferSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Updates the internal pointer to a new value.
|
||||
|
||||
|
||||
Arguments:
|
||||
Buffer - new buffer
|
||||
|
||||
BufferSize - length of Buffer in bytes
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
m_pBuffer = Buffer;
|
||||
m_BufferSize = BufferSize;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxMemoryBufferPreallocatedApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This modules implements the C API's for the FxMemoryBufferPreallocated.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxMemoryBufferPreallocated.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxMemoryBufferPreallocatedAPI.tmh"
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFAPI
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfMemoryCreatePreallocated)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in
|
||||
PVOID Buffer,
|
||||
__in
|
||||
__drv_when(BufferSize == 0, __drv_reportError(BufferSize cannot be zero))
|
||||
size_t BufferSize,
|
||||
__out //deref cud be null if unable to allocate memory
|
||||
WDFMEMORY* PMemory
|
||||
)/*++
|
||||
|
||||
Routine Description:
|
||||
External API provided to the client driver to create a WDFMEMORY object
|
||||
whose associated buffers are supplied by the caller. This API is provided
|
||||
so that the caller does not need to allocate a new buffer every time she
|
||||
wants to pass a WDFMEMORY object to an API which requires it. It is up to
|
||||
the client driver to free the Buffer and Context at the appropriate time.
|
||||
|
||||
Arguments:
|
||||
Attributes - Context to associate with the returned WDFMEMORY handle
|
||||
|
||||
Buffer - Buffer to associate with the returned WDFMEMORY handle
|
||||
|
||||
BufferSize - Size of Buffer in bytes
|
||||
|
||||
PMemory - Handle to be returned to the caller
|
||||
|
||||
Return Value:
|
||||
STATUS_INVALID_PARAMETER - if required parameters are incorrect
|
||||
|
||||
STATUS_INSUFFICIENT_RESOURCES - if no resources are available
|
||||
|
||||
STATUS_SUCCESS - success
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxMemoryBufferPreallocated *pBuffer;
|
||||
WDFMEMORY hMemory;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
//
|
||||
// Get the parent's globals if it is present
|
||||
//
|
||||
if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
|
||||
Attributes))) {
|
||||
FxObject* pParent;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
Attributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
}
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Buffer);
|
||||
FxPointerNotNull(pFxDriverGlobals, PMemory);
|
||||
|
||||
*PMemory = NULL;
|
||||
|
||||
if (BufferSize == 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Zero BufferSize not allowed, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
pBuffer = new(pFxDriverGlobals, Attributes)
|
||||
FxMemoryBufferPreallocated(pFxDriverGlobals, Buffer, BufferSize);
|
||||
|
||||
if (pBuffer == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = pBuffer->Commit(Attributes, (WDFOBJECT*)&hMemory);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*PMemory = hMemory;
|
||||
}
|
||||
else {
|
||||
pBuffer->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFAPI
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfMemoryAssignBuffer)(
|
||||
_In_
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
_In_
|
||||
WDFMEMORY Memory,
|
||||
_Pre_notnull_ _Pre_writable_byte_size_(BufferSize)
|
||||
PVOID Buffer,
|
||||
_In_
|
||||
__drv_when(BufferSize == 0, __drv_reportError(BufferSize cannot be zero))
|
||||
size_t BufferSize
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxMemoryBufferPreallocated* pMemory;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Memory,
|
||||
FX_TYPE_MEMORY_PREALLOCATED,
|
||||
(PVOID*) &pMemory,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Buffer);
|
||||
|
||||
if (BufferSize == 0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Zero BufferSize not allowed, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
pMemory->UpdateBuffer(Buffer, BufferSize);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,319 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxMemoryObject.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed FxMemoryObject
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxMemoryObject.tmh"
|
||||
}
|
||||
|
||||
FxMemoryObject::FxMemoryObject(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in USHORT ObjectSize,
|
||||
__in size_t BufferSize
|
||||
) :
|
||||
// intentionally do not pass IFX_TYPE_MEMORY to the base constructor
|
||||
// because we need to pass the interface back when converting from
|
||||
// handle to object and that will require a different this pointer offset
|
||||
// which will be handled by QueryInterface
|
||||
FxObject(FX_TYPE_OBJECT, ObjectSize, FxDriverGlobals),
|
||||
m_BufferSize(BufferSize)
|
||||
{
|
||||
//
|
||||
// Since we are passing the generic object type FX_TYPE_OBJECT to FxObject,
|
||||
// we need to figure out on our own if need to allocate a tag tracker or not.
|
||||
//
|
||||
if (IsDebug()) {
|
||||
AllocateTagTracker(IFX_TYPE_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxMemoryObject::_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in POOL_TYPE PoolType,
|
||||
__in ULONG PoolTag,
|
||||
__in size_t BufferSize,
|
||||
__out FxMemoryObject** Object
|
||||
)
|
||||
{
|
||||
//
|
||||
// If the buffer is
|
||||
// a) a PAGE or larger
|
||||
// b) we are debugging allocations
|
||||
// c) less then a page and pageable
|
||||
//
|
||||
// separate the object from its memory so that we can assure
|
||||
//
|
||||
// 1) the buffer pointer is PAGE aligned
|
||||
// 2) the kernel's buffer overrun/underrun checking can be used
|
||||
// 3) for case c), that the object is non pageable while the memory pointer
|
||||
// it returns to the driver is pageable
|
||||
//
|
||||
|
||||
//
|
||||
// By placing FxIsPagedPool last in the list, BufferSize < PAGE_SIZE
|
||||
//
|
||||
if (BufferSize >= PAGE_SIZE ||
|
||||
(FxDriverGlobals->FxVerifierOn && FxDriverGlobals->FxPoolTrackingOn) ||
|
||||
FxIsPagedPoolType(PoolType)) {
|
||||
return FxMemoryBufferFromPool::_Create(
|
||||
FxDriverGlobals,
|
||||
Attributes,
|
||||
PoolType,
|
||||
PoolTag,
|
||||
BufferSize,
|
||||
Object);
|
||||
}
|
||||
else {
|
||||
|
||||
//
|
||||
// Before the changes for NxPool this code path assumed NonPagedPool
|
||||
//
|
||||
// To maintain compatibility with existing behavior (and add on NxPool
|
||||
// options we pass in PoolType to FxMemoryBuffer::_Create but
|
||||
// normalize NonPagedPool variants to NonPagedPool.
|
||||
//
|
||||
switch(PoolType)
|
||||
{
|
||||
case NonPagedPoolBaseMustSucceed:
|
||||
case NonPagedPoolBaseCacheAligned:
|
||||
case NonPagedPoolBaseCacheAlignedMustS:
|
||||
PoolType = NonPagedPool;
|
||||
}
|
||||
|
||||
return FxMemoryBuffer::_Create(
|
||||
FxDriverGlobals,
|
||||
Attributes,
|
||||
PoolTag,
|
||||
BufferSize,
|
||||
PoolType,
|
||||
Object);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
IFxMemory::CopyFromPtr(
|
||||
__in_opt PWDFMEMORY_OFFSET DestinationOffsets,
|
||||
__in_bcount(SourceBufferLength) PVOID SourceBuffer,
|
||||
__in size_t SourceBufferLength,
|
||||
__in_opt PWDFMEMORY_OFFSET SourceOffsets
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
//
|
||||
// We read from the supplied buffer writing to the current FxMemoryBuffer
|
||||
//
|
||||
if (GetFlags() & IFxMemoryFlagReadOnly) {
|
||||
//
|
||||
// FxMemoryBuffer is not writeable
|
||||
//
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Target WDFMEMORY 0x%p is ReadOnly", GetHandle());
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
|
||||
return STATUS_ACCESS_VIOLATION;
|
||||
}
|
||||
|
||||
return _CopyPtrToPtr(
|
||||
SourceBuffer,
|
||||
SourceBufferLength,
|
||||
SourceOffsets,
|
||||
GetBuffer(),
|
||||
GetBufferSize(),
|
||||
DestinationOffsets
|
||||
);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
IFxMemory::CopyToPtr(
|
||||
__in_opt PWDFMEMORY_OFFSET SourceOffsets,
|
||||
__out_bcount(DestinationBufferLength)PVOID DestinationBuffer,
|
||||
__in size_t DestinationBufferLength,
|
||||
__in_opt PWDFMEMORY_OFFSET DestinationOffsets
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Worker routine for the various copy APIs. Verifies that a copy will not
|
||||
overrun a buffer, or write into a read only memory buffer
|
||||
|
||||
Arguments:
|
||||
|
||||
SourceOffsets - Offsets into SourceBuffer from which the copy starts. If
|
||||
NULL, an offset of 0 is used.
|
||||
|
||||
DestinationBuffer - Memory whose contents we are copying into
|
||||
|
||||
DestinationBufferLength - Size of DestinationBuffer in bytes
|
||||
|
||||
DestinationOffsets - Offsets into DestinationMemory from which the copy
|
||||
starts and indicates how many bytes to copy. If length is 0 or
|
||||
parameter is NULL, the entire length of DestinationMemory is used.
|
||||
|
||||
Return Value:
|
||||
STATUS_BUFFER_TOO_SMALL - SourceMemory is smaller then the requested number
|
||||
of bytes to be copied.
|
||||
STATUS_INVALID_BUFFER_SIZE - DestinationMemory is not large enough to contain
|
||||
the number of bytes requested to be copied
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// We are reading from the FxMemoryBuffer, so no need to check for ReadOnly
|
||||
//
|
||||
return _CopyPtrToPtr(
|
||||
GetBuffer(),
|
||||
GetBufferSize(),
|
||||
SourceOffsets,
|
||||
DestinationBuffer,
|
||||
DestinationBufferLength,
|
||||
DestinationOffsets
|
||||
);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
IFxMemory::_CopyPtrToPtr(
|
||||
__in_bcount(SourceBufferLength)PVOID SourceBuffer,
|
||||
__in size_t SourceBufferLength,
|
||||
__in_opt PWDFMEMORY_OFFSET SourceOffsets,
|
||||
__out_bcount(DestinationBufferLength) PVOID DestinationBuffer,
|
||||
__in size_t DestinationBufferLength,
|
||||
__in_opt PWDFMEMORY_OFFSET DestinationOffsets
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Worker routine for the various copy APIs. Verifies that a copy will not
|
||||
overrun a buffer.
|
||||
|
||||
Arguments:
|
||||
SourceBuffer - Memory whose contents we are copying from.
|
||||
|
||||
SourceBufferLength - Size of SourceBuffer in bytes
|
||||
|
||||
SourceOffsets - Offsets into SourceBuffer from which the copy starts. If
|
||||
NULL, an offset of 0 is used.
|
||||
|
||||
DestinationBuffer - Memory whose contents we are copying into
|
||||
|
||||
DestinationBufferLength - Size of DestinationBuffer in bytes
|
||||
|
||||
DestinationOffsets - Offsets into DestinationMemory from which the copy
|
||||
starts and indicates how many bytes to copy. If length is 0 or
|
||||
parameter is NULL, the entire length of DestinationMemory is used.
|
||||
|
||||
Return Value:
|
||||
STATUS_BUFFER_TOO_SMALL - SourceMemory is smaller then the requested number
|
||||
of bytes to be copied.
|
||||
STATUS_INVALID_BUFFER_SIZE - DestinationMemory is not large enough to contain
|
||||
the number of bytes requested to be copied
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
size_t srcSize, copyLength;
|
||||
PUCHAR pSrcBuf, pDstBuf;
|
||||
|
||||
if (SourceBuffer == NULL) {
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pSrcBuf = (PUCHAR) SourceBuffer;
|
||||
srcSize = SourceBufferLength;
|
||||
|
||||
pDstBuf = (PUCHAR) DestinationBuffer;
|
||||
copyLength = DestinationBufferLength;
|
||||
|
||||
if (SourceOffsets != NULL) {
|
||||
if (SourceOffsets->BufferOffset != 0) {
|
||||
if (SourceOffsets->BufferOffset >= srcSize) {
|
||||
//
|
||||
// Offset is beyond end of buffer
|
||||
//
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
//
|
||||
// Adjust the start and source size to reflect the offset info the
|
||||
// source
|
||||
//
|
||||
pSrcBuf += SourceOffsets->BufferOffset;
|
||||
srcSize -= SourceOffsets->BufferOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (DestinationOffsets != NULL) {
|
||||
if (DestinationOffsets->BufferOffset != 0) {
|
||||
if (DestinationOffsets->BufferOffset >= copyLength) {
|
||||
//
|
||||
// Offset is beyond end of buffer
|
||||
//
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
//
|
||||
// Adjust the start and copy length to reflect the offset info the
|
||||
// destination
|
||||
//
|
||||
pDstBuf += DestinationOffsets->BufferOffset;
|
||||
copyLength -= DestinationOffsets->BufferOffset;
|
||||
}
|
||||
|
||||
//
|
||||
// Non zero buffer length overrides previously calculated copy length
|
||||
//
|
||||
if (DestinationOffsets->BufferLength != 0) {
|
||||
//
|
||||
// Is the desired buffer length greater than the amount of buffer
|
||||
// available?
|
||||
//
|
||||
if (DestinationOffsets->BufferLength > copyLength) {
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
copyLength = DestinationOffsets->BufferLength;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Compare the final computed copy length against the length of the source
|
||||
// buffer.
|
||||
//
|
||||
if (copyLength > srcSize) {
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
RtlCopyMemory(pDstBuf, pSrcBuf, copyLength);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxPagedLookasideList.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed FxPagedLookasideList
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
#include "FxPagedLookasideList.hpp"
|
||||
#include "FxMemoryBufferFromLookaside.hpp"
|
||||
|
||||
FxPagedLookasideListFromPool::FxPagedLookasideListFromPool(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in ULONG PoolTag,
|
||||
__in FxDeviceBase* DeviceBase,
|
||||
__in FxDeviceBase* MemoryDeviceBase
|
||||
) : FxLookasideListFromPool(FxDriverGlobals, sizeof(*this), PoolTag),
|
||||
m_RawBufferSize(0), m_MemoryDeviceBase(MemoryDeviceBase)
|
||||
{
|
||||
SetDeviceBase(DeviceBase);
|
||||
|
||||
//
|
||||
// Callbacks might be a bit excessive (passive dispose is what we are
|
||||
// really after) because this object has no callbacks, but this is being
|
||||
// proactive in case any callbacks are added. If they are added, this
|
||||
// will take care of them w/out additional changes to object setup.
|
||||
//
|
||||
MarkPassiveCallbacks(ObjectDoNotLock);
|
||||
}
|
||||
|
||||
FxPagedLookasideListFromPool::~FxPagedLookasideListFromPool(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (m_MemoryObjectSize != 0) {
|
||||
Mx::MxDeleteNPagedLookasideList(&m_ObjectLookaside);
|
||||
}
|
||||
|
||||
if (m_RawBufferSize != 0) {
|
||||
Mx::MxDeletePagedLookasideList(&m_PoolLookaside);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxPagedLookasideListFromPool::Initialize(
|
||||
__in size_t BufferSize,
|
||||
__in PWDF_OBJECT_ATTRIBUTES MemoryAttributes
|
||||
)
|
||||
{
|
||||
size_t rawBufferSize;
|
||||
NTSTATUS status;
|
||||
|
||||
if (BufferSize >= PAGE_SIZE) {
|
||||
//
|
||||
// We don't want to burn extra entire pages for tracking information
|
||||
// so we just use the size as is.
|
||||
//
|
||||
rawBufferSize = BufferSize;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Allocate extra space for tracking the allocation
|
||||
//
|
||||
status = FxPoolAddHeaderSize(GetDriverGlobals(),
|
||||
BufferSize,
|
||||
&rawBufferSize);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
//
|
||||
// FxPoolAddHeaderSize logs to the IFR on error
|
||||
//
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (UsePagedBufferObject()) {
|
||||
status = InitializeLookaside(0,
|
||||
sizeof(FxMemoryPagedBufferFromPoolLookaside),
|
||||
MemoryAttributes);
|
||||
}
|
||||
else {
|
||||
status = InitializeLookaside(0,
|
||||
sizeof(FxMemoryBufferFromPoolLookaside),
|
||||
MemoryAttributes);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// We use m_RawBufferSize == 0 as a condition not to delete the lookaside, so
|
||||
// only assign it a value once we know success is guaranteed.
|
||||
//
|
||||
m_BufferSize = BufferSize;
|
||||
m_RawBufferSize = rawBufferSize;
|
||||
|
||||
//
|
||||
// Initialize a non paged pool with these characteristics. All FxObject
|
||||
// derived objects must come from non paged pool.
|
||||
//
|
||||
Mx::MxInitializeNPagedLookasideList(&m_ObjectLookaside,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
m_MemoryObjectSize,
|
||||
m_PoolTag,
|
||||
0);
|
||||
|
||||
//
|
||||
// Initialize a paged pool with these characteristics.
|
||||
//
|
||||
// Free and Allocate are left intentionally NULL so that we use the Ex
|
||||
// versions.
|
||||
//
|
||||
// bufferSize is used b/c it is full size of the object + pool requirements.
|
||||
// m_BufferSize is the size the client wants the buffer to be.
|
||||
//
|
||||
Mx::MxInitializePagedLookasideList(&m_PoolLookaside,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
m_RawBufferSize,
|
||||
m_PoolTag,
|
||||
0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#pragma prefast(push)
|
||||
|
||||
|
||||
|
||||
//This routine intentionally accesses the header of the allocated memory.
|
||||
#pragma prefast(disable:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY)
|
||||
PVOID
|
||||
FxPagedLookasideListFromPool::InitPagedAlloc(
|
||||
__out_bcount(this->m_RawBufferSize) PVOID Alloc
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Initializes the object allocation so that it can be tracked and inserted
|
||||
in this drivers POOL.
|
||||
|
||||
Arguments:
|
||||
Alloc - the raw allocation
|
||||
|
||||
Return Value:
|
||||
the start of where the object memory should be, not necessarily == Alloc
|
||||
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
PFX_POOL_HEADER pHeader;
|
||||
PFX_POOL_TRACKER tracker;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
RtlZeroMemory(Alloc, m_RawBufferSize);
|
||||
|
||||
if (pFxDriverGlobals->IsPoolTrackingOn()) {
|
||||
//
|
||||
// PoolTracking is active, so format and insert
|
||||
// a tracker in the NonPagedHeader list of the pool.
|
||||
//
|
||||
tracker = (PFX_POOL_TRACKER) Alloc;
|
||||
pHeader = WDF_PTR_ADD_OFFSET_TYPE(Alloc,
|
||||
sizeof(FX_POOL_TRACKER),
|
||||
PFX_POOL_HEADER);
|
||||
|
||||
pHeader->Base = Alloc;
|
||||
pHeader->FxDriverGlobals = pFxDriverGlobals;
|
||||
|
||||
FxPoolInsertPagedAllocateTracker(
|
||||
&pFxDriverGlobals->FxPoolFrameworks,
|
||||
tracker,
|
||||
m_RawBufferSize,
|
||||
m_PoolTag,
|
||||
_ReturnAddress());
|
||||
}
|
||||
else {
|
||||
//
|
||||
// PoolTracking is inactive, only format FX_POOL_HEADER area.
|
||||
//
|
||||
pHeader = (PFX_POOL_HEADER) Alloc;
|
||||
pHeader->Base = Alloc;
|
||||
pHeader->FxDriverGlobals = pFxDriverGlobals;
|
||||
}
|
||||
|
||||
return &pHeader->AllocationStart[0];
|
||||
}
|
||||
#pragma prefast(pop)
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxPagedLookasideListFromPool::Allocate(
|
||||
__out FxMemoryObject** PPMemory
|
||||
)
|
||||
{
|
||||
FxMemoryBufferFromPoolLookaside* pBuffer;
|
||||
PVOID pObj, pBuf;
|
||||
|
||||
//
|
||||
// Allocate the object which will contain the 2ndary allocation
|
||||
//
|
||||
pObj = FxAllocateFromNPagedLookasideList(&m_ObjectLookaside);
|
||||
|
||||
if (pObj == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
pObj = InitObjectAlloc(pObj);
|
||||
|
||||
//
|
||||
// Create the 2ndary allocation (the one the driver writer uses), what will
|
||||
// be FxMemoryBufferFromPoolLookaside::m_Pool below.
|
||||
//
|
||||
pBuf = FxAllocateFromPagedLookasideList(&m_PoolLookaside);
|
||||
if (pBuf == NULL) {
|
||||
//
|
||||
// This case is safe because Reclaim doesn't treat the pointer as an
|
||||
// object, rather it just performs pointer math and then frees the alloc
|
||||
//
|
||||
Reclaim((FxMemoryBufferFromPoolLookaside*) pObj);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (m_BufferSize < PAGE_SIZE) {
|
||||
//
|
||||
// For allocations < PAGE, allocate a header, otherwise leave the
|
||||
// allocation alone.
|
||||
//
|
||||
pBuf = InitPagedAlloc(pBuf);
|
||||
}
|
||||
else {
|
||||
//
|
||||
// There is no tracking info before the real allocation start since we
|
||||
// don't want to burn an entire page.
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
|
||||
//
|
||||
// Construct a new FxMemoryBufferFromPoolLookaside using the pool will allocated
|
||||
// above.
|
||||
//
|
||||
// Both objects will know that the base object is one allocation and the
|
||||
// buffer is another. FxMemoryPagedBufferFromPoolLookaside also knows to
|
||||
// dispose itself on the owning FxDeviceBase* pointer.
|
||||
//
|
||||
if (UsePagedBufferObject()) {
|
||||
pBuffer = new(GetDriverGlobals(), pObj, &m_MemoryAttributes)
|
||||
FxMemoryPagedBufferFromPoolLookaside(GetDriverGlobals(),
|
||||
this,
|
||||
m_BufferSize,
|
||||
pBuf,
|
||||
m_MemoryDeviceBase);
|
||||
}
|
||||
else {
|
||||
pBuffer = new(GetDriverGlobals(), pObj, &m_MemoryAttributes)
|
||||
FxMemoryBufferFromPoolLookaside(GetDriverGlobals(),
|
||||
this,
|
||||
m_BufferSize,
|
||||
pBuf);
|
||||
}
|
||||
|
||||
//
|
||||
// pBuffer might be displaced if there is a debug extension
|
||||
//
|
||||
ASSERT(_GetBase(pBuffer) == pObj);
|
||||
|
||||
//
|
||||
// Callbacks might be a bit excessive (passive dispose is what we are
|
||||
// really after) because this object has no callbacks, but this is being
|
||||
// proactive in case any callbacks are added. If they are added, this
|
||||
// will take care of them w/out additional changes to object setup.
|
||||
//
|
||||
pBuffer->MarkPassiveCallbacks(ObjectDoNotLock);
|
||||
|
||||
*PPMemory = pBuffer;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxPagedLookasideListFromPool::Reclaim(
|
||||
__in FxMemoryBufferFromLookaside * Memory
|
||||
)
|
||||
{
|
||||
_Reclaim(GetDriverGlobals(), &m_ObjectLookaside, Memory);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,832 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRequestBase.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements FxRequestBase object
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxRequestBase.tmh"
|
||||
}
|
||||
|
||||
FxRequestBase::FxRequestBase(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in USHORT ObjectSize,
|
||||
__in_opt MdIrp Irp,
|
||||
__in FxRequestIrpOwnership Ownership,
|
||||
__in FxRequestConstructorCaller Caller,
|
||||
__in FxObjectType ObjectType
|
||||
) : FxNonPagedObject(FX_TYPE_REQUEST, ObjectSize, FxDriverGlobals, ObjectType),
|
||||
m_Irp(Irp)
|
||||
{
|
||||
//
|
||||
// By default requests cannot be completed except for request associated with
|
||||
// IRP allocated from I/O (upper drivers).
|
||||
//
|
||||
m_CanComplete = FALSE;
|
||||
|
||||
//
|
||||
// After is all said and done with assigning to m_IrpAllocation value, if
|
||||
// m_Irp().GetIrp == NULL, then m_IrpAllocation can be overridden in
|
||||
// ValidateTarget.
|
||||
//
|
||||
if (Caller == FxRequestConstructorCallerIsDriver) {
|
||||
if (Ownership == FxRequestOwnsIrp) {
|
||||
//
|
||||
// Driver writer gave the irp to the framework but still owns it
|
||||
// or there is no irp passed in when the FxRequest was created.
|
||||
//
|
||||
m_IrpAllocation = REQUEST_ALLOCATED_INTERNAL;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Driver writer gave the irp to the framework but still owns it
|
||||
//
|
||||
m_IrpAllocation = REQUEST_ALLOCATED_DRIVER;
|
||||
}
|
||||
|
||||
//
|
||||
// Cleanup request's context in Dispose. Please see Dispose below
|
||||
// for specific scenario we are trying to fix. Enable Dispose only if
|
||||
// driver is v1.11 or above b/c it may be possible that older driver
|
||||
// may have used invalid/bad scenarios similar to this one:
|
||||
// - create target object.
|
||||
// - create one or more driver created requests parented to the target.
|
||||
// - send one or more of these requests to the target (lower stack).
|
||||
// - delete the target object while requests are pending.
|
||||
// Deleting a target while it has a pending request is a valid
|
||||
// operation, what is not valid is for these request to be also
|
||||
// parented to the target at the same time.
|
||||
// In this scenario if we turn on Dispose, the Dispose callback will
|
||||
// be called before the request is completed.
|
||||
// Note that if the driver had specified any Cleanup callbacks on
|
||||
// these requests, these also are called before the requests are
|
||||
// completed.
|
||||
//
|
||||
if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1, 11)) {
|
||||
MarkDisposeOverride();
|
||||
}
|
||||
}
|
||||
else if (Ownership == FxRequestOwnsIrp) {
|
||||
//
|
||||
// The request will own the irp and free it when the request is freed
|
||||
//
|
||||
m_IrpAllocation = REQUEST_ALLOCATED_INTERNAL;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Request is owned by the io queue
|
||||
//
|
||||
m_IrpAllocation = REQUEST_ALLOCATED_FROM_IO;
|
||||
m_CanComplete = TRUE;
|
||||
}
|
||||
|
||||
m_Target = NULL;
|
||||
m_TargetFlags = 0;
|
||||
|
||||
m_TargetCompletionContext = NULL;
|
||||
|
||||
m_Completed = m_Irp.GetIrp() ? FALSE : TRUE;
|
||||
m_Canceled = FALSE;
|
||||
|
||||
m_PriorityBoost = 0;
|
||||
|
||||
m_RequestContext = NULL;
|
||||
m_Timer = NULL;
|
||||
|
||||
InitializeListHead(&m_ListEntry);
|
||||
m_DrainSingleEntry.Next = NULL;
|
||||
|
||||
m_IrpReferenceCount = 0;
|
||||
|
||||
m_IrpQueue = NULL;
|
||||
|
||||
m_SystemBufferOffset = 0;
|
||||
m_OutputBufferOffset = 0;
|
||||
m_IrpCompletionReferenceCount = 0;
|
||||
|
||||
m_AllocatedMdl = NULL;
|
||||
|
||||
m_VerifierFlags = 0;
|
||||
m_RequestBaseFlags = 0;
|
||||
m_RequestBaseStaticFlags = 0x0;
|
||||
m_CompletionState = FxRequestCompletionStateNone;
|
||||
}
|
||||
|
||||
FxRequestBase::~FxRequestBase(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
MdIrp irp;
|
||||
|
||||
//
|
||||
// Since m_ListEntry is a union with the CSQ context and the irp have just
|
||||
// come off of a CSQ, we cannot be guaranteed that the m_ListEntry is
|
||||
// initialized to point to itself.
|
||||
//
|
||||
// ASSERT(IsListEmpty(&m_ListEntry));
|
||||
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
//
|
||||
// If an MDL is associated with the request, free it
|
||||
//
|
||||
if (m_AllocatedMdl != NULL) {
|
||||
FxMdlFree(GetDriverGlobals(), m_AllocatedMdl);
|
||||
}
|
||||
#endif
|
||||
|
||||
irp = m_Irp.GetIrp();
|
||||
|
||||
//
|
||||
// If the request was created through WdfRequestCreate, formatted, and not
|
||||
// reused, we can still have a request context.
|
||||
//
|
||||
if (m_RequestContext != NULL) {
|
||||
if (irp != NULL) {
|
||||
m_RequestContext->ReleaseAndRestore(this);
|
||||
}
|
||||
|
||||
delete m_RequestContext;
|
||||
}
|
||||
|
||||
if (irp != NULL && m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) {
|
||||
m_Irp.FreeIrp();
|
||||
}
|
||||
|
||||
if (m_Timer != NULL) {
|
||||
delete m_Timer;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FX_VF_METHOD(FxRequestBase, VerifyDispose) (
|
||||
_In_ PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
)
|
||||
{
|
||||
SHORT flags;
|
||||
KIRQL irql;
|
||||
|
||||
PAGED_CODE_LOCKED();
|
||||
|
||||
Lock(&irql);
|
||||
flags = GetVerifierFlagsLocked();
|
||||
if (flags & FXREQUEST_FLAG_SENT_TO_TARGET) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
|
||||
"Driver is trying to delete WDFREQUEST 0x%p while it is still "
|
||||
"active on WDFIOTARGET 0x%p. ",
|
||||
GetTraceObjectHandle(), GetTarget()->GetHandle());
|
||||
FxVerifierDbgBreakPoint(FxDriverGlobals);
|
||||
}
|
||||
Unlock(irql);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxRequestBase::Dispose()
|
||||
{
|
||||
//
|
||||
// Make sure request is not in use.
|
||||
//
|
||||
VerifyDispose(GetDriverGlobals());
|
||||
|
||||
//
|
||||
// Now call Cleanup on any handle context's exposed
|
||||
// to the device driver.
|
||||
//
|
||||
CallCleanup();
|
||||
|
||||
//
|
||||
// Call the request's cleanup (~dtor or Dispose).
|
||||
//
|
||||
if (m_RequestContext != NULL) {
|
||||
if (IsAllocatedFromIo() == FALSE && m_Irp.GetIrp() != NULL) {
|
||||
//
|
||||
// This code allows the following scenario to work correctly b/c
|
||||
// the original request can be completed without worrying that the
|
||||
// new request's context has references on the original request.
|
||||
//
|
||||
// * Driver receives an ioctl request.
|
||||
// * Driver creates a new request.
|
||||
// * Driver formats the new request with buffers from original ioctl.
|
||||
// * Driver sends the new request synchronously.
|
||||
// * Driver retrieves info/status from the new request.
|
||||
// * Driver deletes the new request.
|
||||
// * Driver completes the original request.
|
||||
//
|
||||
m_RequestContext->ReleaseAndRestore(this);
|
||||
|
||||
//
|
||||
// ~dtor cleans up everything. No need to call its Dispose method.
|
||||
//
|
||||
delete m_RequestContext;
|
||||
m_RequestContext = NULL;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Let request's context know that Dispose is in progress.
|
||||
// RequestContext may receive the following two calls after Dispose:
|
||||
// . ReleaseAndRestore if an IRP is still present.
|
||||
// . Destructor
|
||||
//
|
||||
m_RequestContext->Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestBase::ClearFieldsForReuse(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
if (m_AllocatedMdl != NULL) {
|
||||
FxMdlFree(GetDriverGlobals(), m_AllocatedMdl);
|
||||
m_AllocatedMdl = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_RequestBaseFlags = 0;
|
||||
m_RequestBaseStaticFlags = 0x0;
|
||||
m_VerifierFlags = 0;
|
||||
m_Canceled = FALSE;
|
||||
|
||||
SetCompleted(FALSE);
|
||||
SetPriorityBoost(0);
|
||||
|
||||
m_NextStackLocationFormatted = FALSE;
|
||||
|
||||
if (m_Timer != NULL) {
|
||||
delete m_Timer;
|
||||
m_Timer = NULL;
|
||||
}
|
||||
|
||||
m_Target = NULL;
|
||||
m_TargetFlags = 0;
|
||||
m_TargetCompletionContext = NULL;
|
||||
|
||||
InitializeListHead(&m_ListEntry);
|
||||
|
||||
m_DrainSingleEntry.Next = NULL;
|
||||
m_IrpCompletionReferenceCount = 0;
|
||||
m_CompletionState = FxRequestCompletionStateNone;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRequestBase::ValidateTarget(
|
||||
__in FxIoTarget* Target
|
||||
)
|
||||
{
|
||||
MdIrp pIrp, pOldIrp;
|
||||
FxIrp fxIrp;
|
||||
NTSTATUS status;
|
||||
|
||||
pOldIrp = NULL;
|
||||
|
||||
pIrp = GetSubmitIrp();
|
||||
fxIrp.SetIrp(pIrp);
|
||||
|
||||
//
|
||||
// Must restore to the previous irp in case we reallocate the irp
|
||||
//
|
||||
ContextReleaseAndRestore();
|
||||
|
||||
if (Target->HasValidStackSize() == FALSE) {
|
||||
|
||||
//
|
||||
// Target is closed down
|
||||
//
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||||
"WDFIOTARGET %p is closed, cannot validate, %!STATUS!",
|
||||
Target->GetHandle(), status);
|
||||
}
|
||||
else if (pIrp != NULL && Target->HasEnoughStackLocations(&fxIrp)) {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else if (pIrp == NULL || m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) {
|
||||
//
|
||||
// Try to allocate a new irp.
|
||||
//
|
||||
pIrp = FxIrp::AllocateIrp(Target->m_TargetStackSize, Target->GetDevice());
|
||||
|
||||
if (pIrp == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||||
"Could not allocate irp for WDFREQUEST %p for WDFIOTARGET %p,"
|
||||
" %!STATUS!", GetTraceObjectHandle(), Target->GetHandle(), status);
|
||||
}
|
||||
else {
|
||||
pOldIrp = SetSubmitIrp(pIrp, FALSE);
|
||||
m_IrpAllocation = REQUEST_ALLOCATED_INTERNAL;
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// The internal IRP is not owned by this object, so we can't reallocate
|
||||
// it.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
status = STATUS_REQUEST_NOT_ACCEPTED;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||||
"Cannot reallocate PIRP for WDFREQUEST %p using WDFIOTARGET %p,"
|
||||
" %!STATUS!", GetTraceObjectHandle(), Target->GetHandle(), status);
|
||||
}
|
||||
|
||||
if (pOldIrp != NULL) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Freeing irp %p from WDFREQUEST %p\n",
|
||||
pOldIrp, GetTraceObjectHandle());
|
||||
FxIrp oldIrp(pOldIrp);
|
||||
oldIrp.FreeIrp();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
MdIrp
|
||||
FxRequestBase::SetSubmitIrp(
|
||||
__in_opt MdIrp NewIrp,
|
||||
__in BOOLEAN FreeIrp
|
||||
)
|
||||
{
|
||||
MdIrp pOldIrp, pIrpToFree;
|
||||
|
||||
pIrpToFree = NULL;
|
||||
pOldIrp = m_Irp.SetIrp(NewIrp);
|
||||
|
||||
if (NewIrp != NULL) {
|
||||
m_Completed = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// If there is a previous irp that is not the current value and we
|
||||
// allocated it ourselves and the caller wants us to free it, do so.
|
||||
//
|
||||
if (pOldIrp != NULL &&
|
||||
pOldIrp != NewIrp &&
|
||||
m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) {
|
||||
if (FreeIrp) {
|
||||
FxIrp oldIrp(pOldIrp);
|
||||
oldIrp.FreeIrp();
|
||||
}
|
||||
else {
|
||||
pIrpToFree = pOldIrp;
|
||||
}
|
||||
}
|
||||
|
||||
return pIrpToFree;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestBase::CompleteSubmittedNoContext(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Invokes the completion routine and uses a completion params that is on the
|
||||
stack. This is in a separate function so that we only consume the stack
|
||||
space if we need to.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
WDF_REQUEST_COMPLETION_PARAMS params;
|
||||
|
||||
params.Type = WdfRequestTypeNoFormat;
|
||||
|
||||
GetSubmitFxIrp()->CopyStatus(¶ms.IoStatus);
|
||||
|
||||
RtlZeroMemory(¶ms.Parameters, sizeof(params.Parameters));
|
||||
|
||||
|
||||
//
|
||||
// Once we call the completion routine we can't touch any fields anymore
|
||||
// since the request may be resent down the stack.
|
||||
//
|
||||
ClearCompletionRoutine()(GetHandle(),
|
||||
m_Target->GetHandle(),
|
||||
¶ms,
|
||||
ClearCompletionContext());
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestBase::CompleteSubmitted(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Routine that handles the setting up of the request packet for being passed
|
||||
back to the completion routine. This includes copying over parameters from
|
||||
the PIRP and any dereferences necessary.
|
||||
|
||||
Arguments:
|
||||
None.
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIoTarget* pTarget;
|
||||
|
||||
pTarget = m_Target;
|
||||
|
||||
FX_TRACK_DRIVER(GetDriverGlobals());
|
||||
|
||||
if (GetDriverGlobals()->FxVerifierOn) {
|
||||
//
|
||||
// Zero out any values previous driver may have set; when completing the irp
|
||||
// through FxRequest::CompleteInternal, we check to see what the lastest
|
||||
// package was (stored off in the DriverContext). Since the request was
|
||||
// sent off to another devobj, don't assume any valid values in the
|
||||
// DriverContext anymore.
|
||||
//
|
||||
ZeroOutDriverContext();
|
||||
|
||||
//
|
||||
// ClearFormatted also checks for WdfVefiefierOn, but that's OK
|
||||
//
|
||||
VerifierClearFormatted();
|
||||
}
|
||||
|
||||
if (m_RequestContext != NULL) {
|
||||
//
|
||||
// Always do the copy because the driver can retrieve the parameters
|
||||
// later even if there is no completion routine set.
|
||||
//
|
||||
GetSubmitFxIrp()->CopyStatus(
|
||||
&m_RequestContext->m_CompletionParams.IoStatus
|
||||
);
|
||||
|
||||
m_RequestContext->CopyParameters(this);
|
||||
|
||||
//
|
||||
// Call the completion routine if present. Once we call the completion
|
||||
// routine we can't touch any fields anymore since the request may be resent
|
||||
// down the stack.
|
||||
//
|
||||
if (m_CompletionRoutine.m_Completion != NULL) {
|
||||
ClearCompletionRoutine()(GetHandle(),
|
||||
pTarget->GetHandle(),
|
||||
&m_RequestContext->m_CompletionParams,
|
||||
ClearCompletionContext());
|
||||
}
|
||||
}
|
||||
else if (m_CompletionRoutine.m_Completion != NULL) {
|
||||
//
|
||||
// Only put a completion parameters struct on the stack if we have to.
|
||||
// By putting it into a separate function, we can control stack usage
|
||||
// in this way.
|
||||
//
|
||||
CompleteSubmittedNoContext();
|
||||
}
|
||||
|
||||
//
|
||||
// Release the tag that was acquired when the request was submitted or
|
||||
// pended.
|
||||
//
|
||||
RELEASE(pTarget);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxRequestBase::Cancel(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Attempts to cancel a previously submitted or pended request.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
TRUE if the request was successfully cancelled, FALSE otherwise
|
||||
|
||||
--*/
|
||||
{
|
||||
BOOLEAN result;
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Request %p", this);
|
||||
|
||||
//
|
||||
// It is critical to set m_Canceled before we check the reference count.
|
||||
// We could be racing with FxIoTarget::SubmitLocked and if this call executes
|
||||
// before SubmitLocked, the completion reference count will still be zero.
|
||||
// SubmitLocked will check m_Canceled after setting the reference count to
|
||||
// one so that it decrement the count back.
|
||||
//
|
||||
m_Canceled = TRUE;
|
||||
|
||||
//
|
||||
// If the ref count is zero, the irp has completed already. This means we
|
||||
// cannot safely touch the underlying PIRP because we cannot guarantee it
|
||||
// will not be completed from underneath us.
|
||||
//
|
||||
if (FxInterlockedIncrementGTZero(&m_IrpCompletionReferenceCount) != 0) {
|
||||
//
|
||||
// Successfully incremented the ref count. The PIRP will not be completed
|
||||
// until the count goes to zero.
|
||||
//
|
||||
// Cancelling the irp handles all 2 states:
|
||||
//
|
||||
// 1) the request is pended in a target. the target will attempt to
|
||||
// complete the request immediately in the cancellation routine, but
|
||||
// will not be able to because of the added count to the ref count
|
||||
// done above. The count will move back to zero below and
|
||||
// CompletedCanceledRequest will complete the request
|
||||
//
|
||||
// 2) The irp is in flight to the target WDM device. In which case the
|
||||
// target WDM device should complete the request immediatley. If
|
||||
// it does not, it becomes the same as the case where the target WDM
|
||||
// device has already pended it and placed a cancellation routine
|
||||
// on the request and the request will (a)synchronously complete
|
||||
//
|
||||
result = m_Irp.Cancel();
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Request %p, PIRP %p, cancel result %d",
|
||||
this, m_Irp.GetIrp(), result);
|
||||
|
||||
//
|
||||
// If the count goes to zero, the completion routine ran, but deferred
|
||||
// completion ownership to this thread since we had the outstanding
|
||||
// refeference.
|
||||
//
|
||||
if (InterlockedDecrement(&m_IrpCompletionReferenceCount) == 0) {
|
||||
|
||||
//
|
||||
// Since completion ownership was claimed, m_Target will be valid
|
||||
// until m_Target->CompleteRequest executes because the target will
|
||||
// not delete while there is outstanding I/O.
|
||||
//
|
||||
ASSERT(m_Target != NULL);
|
||||
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Request %p, PIRP %p, completed synchronously in cancel call, "
|
||||
"completing request on target %p", this, m_Irp.GetIrp(), m_Target);
|
||||
|
||||
m_Target->CompleteCanceledRequest(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Could not cancel request %p, already completed", this);
|
||||
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestBase::_TimerDPC(
|
||||
__in PKDPC Dpc,
|
||||
__in_opt PVOID Context,
|
||||
__in_opt PVOID SystemArgument1,
|
||||
__in_opt PVOID SystemArgument2
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
DPC for the request timer. It lets the FxIoTarget associated with the
|
||||
request handle the cancellation synchronization with the PIRP's
|
||||
completion routine.
|
||||
|
||||
Arguments:
|
||||
Dpc - The DPC itself (part of FxRequestExtension)
|
||||
|
||||
Context - FxRequest* that has timed out
|
||||
|
||||
SystemArgument1 - Ignored
|
||||
|
||||
SystemArgument2 - Ignored
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
FxRequest* pRequest;
|
||||
FxIoTarget* pTarget;
|
||||
|
||||
UNREFERENCED_PARAMETER(Dpc);
|
||||
UNREFERENCED_PARAMETER(SystemArgument1);
|
||||
UNREFERENCED_PARAMETER(SystemArgument2);
|
||||
|
||||
//
|
||||
// No need to grab FxRequest::Lock b/c if there is a timer running, then the
|
||||
// request is guaranteed to be associated with a target.
|
||||
//
|
||||
pRequest = (FxRequest*) Context;
|
||||
pTarget = pRequest->m_Target;
|
||||
|
||||
ASSERT(pTarget != NULL);
|
||||
pTarget->TimerCallback(pRequest);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRequestBase::CreateTimer(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Late time initialization of timer related structures, we only init
|
||||
timer structures if we are going to use them.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Assumes:
|
||||
m_Target->Lock() is being held by the caller
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxRequestTimer* pTimer;
|
||||
PVOID pResult;
|
||||
NTSTATUS status;
|
||||
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
if (m_Timer != NULL) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pTimer = new (FxDriverGlobals) FxRequestTimer();
|
||||
|
||||
if(pTimer == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = pTimer->Timer.Initialize(this, _TimerDPC, 0);
|
||||
if(!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
|
||||
"Failed to initialize timer for request %p", this);
|
||||
delete pTimer;
|
||||
return status;
|
||||
}
|
||||
|
||||
pResult = InterlockedCompareExchangePointer((PVOID*)&m_Timer, pTimer, NULL);
|
||||
|
||||
if (pResult != NULL) {
|
||||
//
|
||||
// Another value was set before we could set it, free our timer now
|
||||
//
|
||||
delete pTimer;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestBase::StartTimer(
|
||||
__in LONGLONG Timeout
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Starts a timer for the request
|
||||
|
||||
Arguments:
|
||||
Timeout - How long the timeout should be
|
||||
|
||||
Assumes:
|
||||
m_Target->Lock() is being held by the caller.
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
LARGE_INTEGER timeout;
|
||||
timeout.QuadPart = Timeout;
|
||||
|
||||
m_TargetFlags |= FX_REQUEST_TIMER_SET;
|
||||
|
||||
m_Timer->Timer.Start(timeout);
|
||||
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
BOOLEAN
|
||||
FxRequestBase::CancelTimer(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Cancel a previously queued timer based on this request if one was set.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Assumes:
|
||||
Caller is providing synchronization around the call of this function with
|
||||
regard to m_TargetFlags.
|
||||
|
||||
Return Value:
|
||||
TRUE if the timer was cancelled successfully or if there was no timer set,
|
||||
otherwise FALSE if the timer was not cancelled and has fired.
|
||||
|
||||
--*/
|
||||
{
|
||||
if (m_TargetFlags & FX_REQUEST_TIMER_SET) {
|
||||
//
|
||||
// If we can successfully cancel the timer, release the reference
|
||||
// taken in StartTimer and mark the timer as not queued.
|
||||
//
|
||||
|
||||
if (m_Timer->Timer.Stop() == FALSE) {
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Request %p, did not cancel timer", this);
|
||||
|
||||
//
|
||||
// Leave FX_REQUEST_TIMER_SET set. The timer DPC will clear the it
|
||||
//
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Request %p, canceled timer successfully", this);
|
||||
|
||||
m_TargetFlags &= ~FX_REQUEST_TIMER_SET;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
__declspec(noreturn)
|
||||
VOID
|
||||
FxRequestBase::FatalError(
|
||||
__in NTSTATUS Status
|
||||
)
|
||||
{
|
||||
WDF_QUEUE_FATAL_ERROR_DATA data;
|
||||
|
||||
RtlZeroMemory(&data, sizeof(data));
|
||||
|
||||
data.Queue = NULL;
|
||||
data.Request = (WDFREQUEST) GetTraceObjectHandle();
|
||||
data.Status = Status;
|
||||
|
||||
FxVerifierBugCheck(GetDriverGlobals(),
|
||||
WDF_QUEUE_FATAL_ERROR,
|
||||
(ULONG_PTR) &data);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRequestContext.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements FxRequest object
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxRequestContext.tmh"
|
||||
}
|
||||
|
||||
FxRequestContext::FxRequestContext(
|
||||
__in FX_REQUEST_CONTEXT_TYPE Type
|
||||
) :
|
||||
m_RequestType(Type),
|
||||
m_RequestMemory(NULL)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructs an FxRequestContext and initialized the m_RequestType field
|
||||
|
||||
Arguments:
|
||||
Type - The type of this request.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
InitCompletionParams();
|
||||
}
|
||||
|
||||
FxRequestContext::~FxRequestContext()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destruct for an FxRequestContext. Releases all outstanding references.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
ASSERT(m_RequestMemory == NULL);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestContext::StoreAndReferenceMemory(
|
||||
__in FxRequestBuffer* Buffer
|
||||
)
|
||||
{
|
||||
_StoreAndReferenceMemoryWorker(this, &m_RequestMemory, Buffer);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestContext::ReleaseAndRestore(
|
||||
__in FxRequestBase* Request
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
This routine releases any outstanding references taken on the previous
|
||||
format call and restores any fields in the PIRP that were overwritten
|
||||
when the formatting occurred.
|
||||
|
||||
Arguments:
|
||||
Irp
|
||||
|
||||
Return Value:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
Request->FreeMdls();
|
||||
#else
|
||||
UNREFERENCED_PARAMETER(Request);
|
||||
#endif
|
||||
|
||||
if (m_RequestMemory != NULL) {
|
||||
m_RequestMemory->RELEASE(this);
|
||||
m_RequestMemory = NULL;
|
||||
}
|
||||
|
||||
InitCompletionParams();
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestContext::_StoreAndReferenceMemoryWorker(
|
||||
__in PVOID Tag,
|
||||
__deref_out_opt IFxMemory** PPMemory,
|
||||
__in FxRequestBuffer* Buffer
|
||||
)
|
||||
{
|
||||
ASSERT(*PPMemory == NULL);
|
||||
|
||||
switch (Buffer->DataType) {
|
||||
case FxRequestBufferMemory:
|
||||
Buffer->u.Memory.Memory->ADDREF(Tag);
|
||||
*PPMemory = Buffer->u.Memory.Memory;
|
||||
break;
|
||||
|
||||
case FxRequestBufferReferencedMdl:
|
||||
Buffer->u.RefMdl.Memory->ADDREF(Tag);
|
||||
*PPMemory = Buffer->u.RefMdl.Memory;
|
||||
break;
|
||||
|
||||
default:
|
||||
*PPMemory = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestContext::FormatWriteParams(
|
||||
__in_opt IFxMemory* WriteMemory,
|
||||
__in_opt PWDFMEMORY_OFFSET WriteOffsets
|
||||
)
|
||||
{
|
||||
m_CompletionParams.Type = WdfRequestTypeWrite;
|
||||
|
||||
if (WriteMemory != NULL) {
|
||||
m_CompletionParams.Parameters.Write.Buffer = WriteMemory->GetHandle();
|
||||
}
|
||||
|
||||
if (WriteOffsets != NULL) {
|
||||
m_CompletionParams.Parameters.Write.Offset =
|
||||
WriteOffsets->BufferOffset;
|
||||
}
|
||||
else {
|
||||
m_CompletionParams.Parameters.Write.Offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestContext::FormatReadParams(
|
||||
__in_opt IFxMemory* ReadMemory,
|
||||
__in_opt PWDFMEMORY_OFFSET ReadOffsets
|
||||
)
|
||||
{
|
||||
m_CompletionParams.Type = WdfRequestTypeRead;
|
||||
|
||||
if (ReadMemory != NULL) {
|
||||
m_CompletionParams.Parameters.Read.Buffer = ReadMemory->GetHandle();
|
||||
}
|
||||
|
||||
if (ReadOffsets != NULL) {
|
||||
m_CompletionParams.Parameters.Read.Offset =
|
||||
ReadOffsets->BufferOffset;
|
||||
}
|
||||
else {
|
||||
m_CompletionParams.Parameters.Read.Offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestContext::FormatOtherParams(
|
||||
__in FxInternalIoctlParams *InternalIoctlParams
|
||||
)
|
||||
{
|
||||
m_CompletionParams.Type = WdfRequestTypeOther;
|
||||
m_CompletionParams.Parameters.Others.Argument1.Ptr = InternalIoctlParams->Argument1;
|
||||
m_CompletionParams.Parameters.Others.Argument2.Ptr = InternalIoctlParams->Argument2;
|
||||
m_CompletionParams.Parameters.Others.Argument4.Ptr = InternalIoctlParams->Argument4;
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRequestMemory.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the memory object for FxRequest that is sized, and
|
||||
allows checking for read/write access.
|
||||
|
||||
Its lifetime reference is tied with IRP completion in
|
||||
FxRequest.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
//
|
||||
// FxRequestMemory can be an embedded object inside of FxRequest,
|
||||
// in which it represents the standard WDM IRP buffers.
|
||||
//
|
||||
// In addition, FxRequestMemory may be allocated by the device
|
||||
// driver by probing and locking pages for dealing with direct
|
||||
// and method_neither I/O types.
|
||||
//
|
||||
// In both cases, the lifetime of a WDFMEMORY handle returned from
|
||||
// FxRequestMemory becomes invalid once FxRequest::Complete is called.
|
||||
//
|
||||
// Code exists to assist FxRequest in verifying there are no out
|
||||
// standing references on the WDFMEMORY handles when a request is
|
||||
// completed.
|
||||
//
|
||||
// Rundown and disposing of FxRequestMemory occur during FxRequest::Complete,
|
||||
// and not when FxRequest is actually destroyed. This is because they represent
|
||||
// system buffers and MDLs which must be released before the IRP inside
|
||||
// the FxRequest is completed. Otherwise an I/O manager bugcheck will occur.
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
FxRequestMemory::Create(
|
||||
__in PFX_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__out FxRequestMemory** Object
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Class Factory for FxRequestMemory
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxRequestMemory* pMemory;
|
||||
|
||||
// Build an FxRequestMemory object now
|
||||
pMemory = new(DriverGlobals, Attributes) FxRequestMemory(DriverGlobals);
|
||||
|
||||
if (pMemory == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
*Object = pMemory;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
FxRequestMemory::FxRequestMemory(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxMemoryBufferPreallocated(sizeof(*this), FxDriverGlobals)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Default constructor for this object.
|
||||
|
||||
--*/
|
||||
{
|
||||
|
||||
//
|
||||
// Our constructor chain:
|
||||
//
|
||||
// FxRequestMemory(ObjectSize, PFX_DRIVER_GLOBALS),
|
||||
// : FxMemoryBufferPreallocated(ObjectSize, PFX_DRIVER_GLOBALS),
|
||||
// : FxMemoryObject(PFX_DRIVER_GLOBALS, ObjectSize, ObjectSize),
|
||||
// : FxObject(FX_TYPE_MEMORY, ObjectSize, PFX_DRIVER_GLOBALS)
|
||||
//
|
||||
m_Request = NULL;
|
||||
|
||||
m_Mdl = NULL;
|
||||
|
||||
m_Flags = 0;
|
||||
}
|
||||
|
||||
|
||||
FxRequestMemory::~FxRequestMemory(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for this object. Does nothing with the client memory since
|
||||
the client owns it.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Non-embedded case releases resources in the destructor
|
||||
// rather than Dispose to ensure all outstanding device driver
|
||||
// references are gone.
|
||||
//
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
if( m_Mdl != NULL ) {
|
||||
Mx::MxUnlockPages(m_Mdl);
|
||||
FxMdlFree(GetDriverGlobals(), m_Mdl);
|
||||
m_Mdl = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( m_Request != NULL ) {
|
||||
m_Request->ReleaseIrpReference();
|
||||
m_Request = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRequestMemory::QueryInterface(
|
||||
__in FxQueryInterfaceParams* Params
|
||||
)
|
||||
{
|
||||
if (Params->Type == FX_TYPE_REQUEST_MEMORY) {
|
||||
*Params->Object = (FxRequestMemory*) this;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return __super::QueryInterface(Params);
|
||||
}
|
||||
}
|
||||
|
||||
PVOID
|
||||
FxRequestMemory::GetBuffer(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
GetBuffer overload.
|
||||
|
||||
Returns pointer into buffer memory.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
Client supplied buffer from the constructor
|
||||
|
||||
--*/
|
||||
{
|
||||
return m_pBuffer;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PMDL
|
||||
FxRequestMemory::GetMdl(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
GetMdl overload. Returns the embedded MDL
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
valid MDL or NULL
|
||||
|
||||
--*/
|
||||
{
|
||||
return m_Mdl;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestMemory::SetBuffer(
|
||||
_In_ FxRequest* Request,
|
||||
_Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer,
|
||||
_In_ PMDL BackingMdl,
|
||||
_In_ size_t BufferSize,
|
||||
_In_ BOOLEAN ReadOnly
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Updates the internal pointer to a new value.
|
||||
|
||||
|
||||
Arguments:
|
||||
Request - new Request.
|
||||
|
||||
Buffer - new buffer
|
||||
|
||||
BackingMdl - associated MDL.
|
||||
|
||||
BufferSize - length of Buffer in bytes
|
||||
|
||||
ReadOnly - TRUE if read only buffer.
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
ASSERT(m_pBuffer == NULL);
|
||||
ASSERT(m_Request == NULL);
|
||||
ASSERT(m_Mdl == NULL);
|
||||
|
||||
ASSERT(Request != NULL);
|
||||
|
||||
m_pBuffer = Buffer;
|
||||
m_Mdl = BackingMdl;
|
||||
m_BufferSize = BufferSize;
|
||||
|
||||
m_Request = Request;
|
||||
|
||||
//
|
||||
// A single FxRequest IRP reference
|
||||
// is outstanding until destroy
|
||||
//
|
||||
m_Request->AddIrpReference();
|
||||
|
||||
// Set access checking if its a readonly buffer
|
||||
if (ReadOnly) {
|
||||
SetFlags(IFxMemoryFlagReadOnly);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestMemory::SetMdl(
|
||||
__in FxRequest* Request,
|
||||
__in PMDL Mdl,
|
||||
__in PVOID MdlBuffer,
|
||||
__in size_t BufferSize,
|
||||
__in BOOLEAN ReadOnly
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Sets an MDL on the WDFMEMORY object.
|
||||
|
||||
It can't already have a buffer set.
|
||||
|
||||
We are expected to free the MDL when Disposed.
|
||||
|
||||
This is not used by embedded WDFMEMORY objects whose
|
||||
MDL comes from the IRP.
|
||||
|
||||
Arguments:
|
||||
Request - new Request.
|
||||
|
||||
Mdl - new MDL.
|
||||
|
||||
MdlBuffer - associated buffer
|
||||
|
||||
BufferSize - length of Buffer in bytes
|
||||
|
||||
ReadOnly - TRUE if read only buffer.
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
|
||||
ASSERT(m_pBuffer == NULL);
|
||||
ASSERT(m_Mdl == NULL);
|
||||
ASSERT(m_Request == NULL);
|
||||
ASSERT(Request != NULL);
|
||||
|
||||
m_Mdl = Mdl;
|
||||
m_pBuffer = MdlBuffer;
|
||||
m_BufferSize = BufferSize;
|
||||
|
||||
m_Request = Request;
|
||||
|
||||
//
|
||||
// A single FxRequest IRP reference is outstanding until destroy
|
||||
//
|
||||
m_Request->AddIrpReference();
|
||||
|
||||
// Set access checking if it's a readonly buffer
|
||||
if (ReadOnly) {
|
||||
SetFlags(IFxMemoryFlagReadOnly);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRequestOutputBuffer.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements class representing the output buffer in an FxRequest
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxRequestOutputBuffer.tmh"
|
||||
}
|
||||
|
||||
PVOID
|
||||
FxRequestOutputBuffer::GetBuffer(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the output buffer that has been cached away by the call to SetBuffer()
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
Valid memory or NULL on error
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIrp* irp = GetRequest()->GetFxIrp();
|
||||
|
||||
ASSERT(irp->GetMajorFunction() == IRP_MJ_DEVICE_CONTROL ||
|
||||
irp->GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
||||
|
||||
switch (irp->GetParameterIoctlCodeBufferMethod()) {
|
||||
case METHOD_BUFFERED:
|
||||
//
|
||||
// For buffered ioctls, input and output buffer pointers are same.
|
||||
//
|
||||
return m_Buffer;
|
||||
|
||||
case METHOD_IN_DIRECT:
|
||||
case METHOD_OUT_DIRECT:
|
||||
//
|
||||
// FxRequest::GetDeviceControlOutputMemoryObject has already called
|
||||
// MmGetSystemAddressForMdlSafe and returned success, so we know that
|
||||
// we can safely call MmGetSystemAddressForMdlSafe again to get a
|
||||
// valid VA pointer.
|
||||
//
|
||||
return Mx::MxGetSystemAddressForMdlSafe(m_Mdl, NormalPagePriority);
|
||||
|
||||
case METHOD_NEITHER:
|
||||
return m_Buffer;
|
||||
|
||||
default:
|
||||
ASSERT(FALSE);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
FxRequestOutputBuffer::GetBufferSize(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the size of the buffer returned by GetBuffer()
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
Buffer length or 0 on error
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIrp* irp = GetRequest()->GetFxIrp();
|
||||
|
||||
ASSERT(irp->GetMajorFunction() == IRP_MJ_DEVICE_CONTROL ||
|
||||
irp->GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
||||
|
||||
return irp->GetParameterIoctlOutputBufferLength();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PMDL
|
||||
FxRequestOutputBuffer::GetMdl(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the PMDL from the irp if one exists, otherwise NULL
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
a valid PMDL or NULL (not an error condition)
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIrp* irp = GetRequest()->GetFxIrp();
|
||||
|
||||
ASSERT(irp->GetMajorFunction() == IRP_MJ_DEVICE_CONTROL ||
|
||||
irp->GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
||||
|
||||
switch (irp->GetParameterIoctlCodeBufferMethod()) {
|
||||
case METHOD_IN_DIRECT:
|
||||
case METHOD_OUT_DIRECT:
|
||||
return m_Mdl;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
WDFMEMORY
|
||||
FxRequestOutputBuffer::GetHandle(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the handle that will represent this object to the driver writer.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
Valid WDF handle
|
||||
|
||||
--*/
|
||||
{
|
||||
return GetRequest()->GetMemoryHandle(
|
||||
FIELD_OFFSET(FxRequest, m_OutputBufferOffset));
|
||||
}
|
||||
|
||||
USHORT
|
||||
FxRequestOutputBuffer::GetFlags(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the flags associated with this buffer. This currently only includes
|
||||
whether the buffer is read only or not
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
flags from IFxMemoryFlags
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIrp* irp = GetRequest()->GetFxIrp();
|
||||
|
||||
ASSERT(irp->GetMajorFunction() == IRP_MJ_DEVICE_CONTROL ||
|
||||
irp->GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
||||
|
||||
switch (irp->GetParameterIoctlCodeBufferMethod()) {
|
||||
case METHOD_IN_DIRECT:
|
||||
return IFxMemoryFlagReadOnly;
|
||||
|
||||
case METHOD_BUFFERED:
|
||||
case METHOD_OUT_DIRECT:
|
||||
case METHOD_NEITHER: // since it is neither, we can't tell, so leave it as 0
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PFX_DRIVER_GLOBALS
|
||||
FxRequestOutputBuffer::GetDriverGlobals(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the driver globals
|
||||
|
||||
Arguments:
|
||||
none
|
||||
|
||||
Return Value:
|
||||
Driver globals pointer
|
||||
|
||||
--*/
|
||||
{
|
||||
return GetRequest()->GetDriverGlobals();
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxRequestOutputBuffer::AddRef(
|
||||
__in PVOID Tag,
|
||||
__in LONG Line,
|
||||
__in_opt PSTR File
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Adds an irp reference to the owning FxRequest. This object does not maintain
|
||||
its own reference count. A request cannot be completed with outstanding
|
||||
irp references.
|
||||
|
||||
Arguments:
|
||||
Tag - the tag to use to track the reference
|
||||
|
||||
Line - The line number of the caller
|
||||
|
||||
File - the file name of the caller
|
||||
|
||||
Return Value:
|
||||
current reference count
|
||||
|
||||
--*/
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Tag);
|
||||
UNREFERENCED_PARAMETER(Line);
|
||||
UNREFERENCED_PARAMETER(File);
|
||||
|
||||
GetRequest()->AddIrpReference();
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxRequestOutputBuffer::Release(
|
||||
__in PVOID Tag,
|
||||
__in LONG Line,
|
||||
__in_opt PSTR File
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Removes an irp reference to the owning FxRequest. This object does not maintain
|
||||
its own reference count. A request cannot be completed with outstanding
|
||||
irp references.
|
||||
|
||||
Arguments:
|
||||
Tag - the tag to use to track the release
|
||||
|
||||
Line - The line number of the caller
|
||||
|
||||
File - the file name of the caller
|
||||
|
||||
Return Value:
|
||||
current reference count
|
||||
|
||||
--*/
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Tag);
|
||||
UNREFERENCED_PARAMETER(Line);
|
||||
UNREFERENCED_PARAMETER(File);
|
||||
|
||||
GetRequest()->ReleaseIrpReference();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
FxRequest*
|
||||
FxRequestOutputBuffer::GetRequest(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Return the owning FxRequest based on this object's address
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
owning FxRequest
|
||||
|
||||
--*/
|
||||
{
|
||||
return CONTAINING_RECORD(this, FxRequest, m_OutputBuffer);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestOutputBuffer::Delete(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Attempt to delete this interface. Since this is an embedded object, it
|
||||
cannot be deleted. Since this function is only called internally, the
|
||||
internal caller knows if the IFxMemory is deletable because the internal
|
||||
caller allocated the IFxMemory to begin with.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
// this function should never be called
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRequestSystemBuffer.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements class representing the system buffer in an FxRequest
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxRequestSystemBuffer.tmh"
|
||||
}
|
||||
|
||||
size_t
|
||||
FxRequestSystemBuffer::GetBufferSize(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the size of the buffer returned by GetBuffer()
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
Buffer length or 0 on error
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIrp* irp = GetRequest()->GetFxIrp();
|
||||
|
||||
switch (irp->GetMajorFunction()) {
|
||||
case IRP_MJ_READ:
|
||||
return irp->GetParameterReadLength();
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
return irp->GetParameterWriteLength();
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
||||
return irp->GetParameterIoctlInputBufferLength();
|
||||
|
||||
default:
|
||||
// should not get here
|
||||
ASSERT(FALSE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PMDL
|
||||
FxRequestSystemBuffer::GetMdl(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the PMDL from the irp if one exists, otherwise NULL
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
a valid PMDL or NULL (not an error condition)
|
||||
|
||||
--*/
|
||||
{
|
||||
FxDevice* pDevice;
|
||||
FxIrp* irp = GetRequest()->GetFxIrp();
|
||||
|
||||
switch (irp->GetMajorFunction()) {
|
||||
case IRP_MJ_READ:
|
||||
case IRP_MJ_WRITE:
|
||||
pDevice = FxDevice::GetFxDevice(irp->GetDeviceObject());
|
||||
|
||||
if (pDevice->GetIoType() == WdfDeviceIoDirect) {
|
||||
return m_Mdl;
|
||||
}
|
||||
// || || Fall through || ||
|
||||
// \/ \/ \/ \/
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
||||
//
|
||||
// For IOCLs, the outbuffer will return the PMDL
|
||||
//
|
||||
// || || Fall through || ||
|
||||
// \/ \/ \/ \/
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
WDFMEMORY
|
||||
FxRequestSystemBuffer::GetHandle(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the handle that will represent this object to the driver writer.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
Valid WDF handle
|
||||
|
||||
--*/
|
||||
{
|
||||
return GetRequest()->GetMemoryHandle(
|
||||
FIELD_OFFSET(FxRequest, m_SystemBufferOffset));
|
||||
}
|
||||
|
||||
USHORT
|
||||
FxRequestSystemBuffer::GetFlags(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the flags associated with this buffer. This currently only includes
|
||||
whether the buffer is read only or not
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
flags from IFxMemoryFlags
|
||||
|
||||
--*/
|
||||
{
|
||||
FxIrp* irp = GetRequest()->GetFxIrp();
|
||||
|
||||
switch (irp->GetMajorFunction()) {
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
||||
switch (irp->GetParameterIoctlCodeBufferMethod()) {
|
||||
case METHOD_BUFFERED:
|
||||
case METHOD_NEITHER:
|
||||
return 0;
|
||||
|
||||
case METHOD_IN_DIRECT:
|
||||
case METHOD_OUT_DIRECT:
|
||||
return IFxMemoryFlagReadOnly;
|
||||
}
|
||||
|
||||
case IRP_MJ_READ:
|
||||
return 0;
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
return IFxMemoryFlagReadOnly;
|
||||
|
||||
default:
|
||||
ASSERT(FALSE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PFX_DRIVER_GLOBALS
|
||||
FxRequestSystemBuffer::GetDriverGlobals(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the driver globals
|
||||
|
||||
Arguments:
|
||||
none
|
||||
|
||||
Return Value:
|
||||
Driver globals pointer
|
||||
|
||||
--*/
|
||||
{
|
||||
return GetRequest()->GetDriverGlobals();
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxRequestSystemBuffer::AddRef(
|
||||
__in PVOID Tag,
|
||||
__in LONG Line,
|
||||
__in_opt PSTR File
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Adds an irp reference to the owning FxRequest. This object does not maintain
|
||||
its own reference count. A request cannot be completed with outstanding
|
||||
irp references.
|
||||
|
||||
Arguments:
|
||||
Tag - the tag to use to track the reference
|
||||
|
||||
Line - The line number of the caller
|
||||
|
||||
File - the file name of the caller
|
||||
|
||||
Return Value:
|
||||
current reference count
|
||||
|
||||
--*/
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Tag);
|
||||
UNREFERENCED_PARAMETER(Line);
|
||||
UNREFERENCED_PARAMETER(File);
|
||||
|
||||
GetRequest()->AddIrpReference();
|
||||
|
||||
//
|
||||
// This value should never be used by the caller
|
||||
//
|
||||
return 2;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxRequestSystemBuffer::Release(
|
||||
__in PVOID Tag,
|
||||
__in LONG Line,
|
||||
__in_opt PSTR File
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Removes an irp reference to the owning FxRequest. This object does not maintain
|
||||
its own reference count. A request cannot be completed with outstanding
|
||||
irp references.
|
||||
|
||||
Arguments:
|
||||
Tag - the tag to use to track the release
|
||||
|
||||
Line - The line number of the caller
|
||||
|
||||
File - the file name of the caller
|
||||
|
||||
Return Value:
|
||||
current reference count
|
||||
|
||||
--*/
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Tag);
|
||||
UNREFERENCED_PARAMETER(Line);
|
||||
UNREFERENCED_PARAMETER(File);
|
||||
|
||||
GetRequest()->ReleaseIrpReference();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
FxRequest*
|
||||
FxRequestSystemBuffer::GetRequest(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Return the owning FxRequest based on this object's address
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
owning FxRequest
|
||||
|
||||
--*/
|
||||
{
|
||||
return CONTAINING_RECORD(this, FxRequest, m_SystemBuffer);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestSystemBuffer::Delete(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Attempt to delete this interface. Since this is an embedded object, it
|
||||
cannot be deleted. Since this function is only called internally, the
|
||||
internal caller knows if the IFxMemory is deletable because the internal
|
||||
caller allocated the IFxMemory to begin with.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
// this function should never be called
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxSyncRequest.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements FxSyncRequest object
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxSyncRequest.tmh"
|
||||
}
|
||||
|
||||
FxSyncRequest::FxSyncRequest(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in_opt FxRequestContext* Context,
|
||||
__in_opt WDFREQUEST Request
|
||||
) :
|
||||
FxRequestBase(FxDriverGlobals,
|
||||
0, // no handle for this object
|
||||
NULL, // No PIRP
|
||||
FxRequestDoesNotOwnIrp,
|
||||
FxRequestConstructorCallerIsFx,
|
||||
FxObjectTypeEmbedded)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructs an FxSyncRequest
|
||||
|
||||
Arguments:
|
||||
Context - Context to associate with this object
|
||||
|
||||
Request - (opt) real Request object.
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// If m_CleanContextOnDestroy is TRUE, m_RequestContext is cleared in the
|
||||
// destructor so that the base class destructor does not free the context.
|
||||
// This is useful if the context is also stack based.
|
||||
//
|
||||
if (Context != NULL) {
|
||||
m_ClearContextOnDestroy = TRUE;
|
||||
}
|
||||
|
||||
else {
|
||||
m_ClearContextOnDestroy = FALSE;
|
||||
}
|
||||
|
||||
m_RequestContext = Context;
|
||||
|
||||
if (Request == NULL) {
|
||||
m_TrueRequest = this;
|
||||
m_RequestBaseFlags |= FxRequestBaseSyncCleanupContext;
|
||||
}
|
||||
else {
|
||||
FxRequest* pRequest;
|
||||
|
||||
FxObjectHandleGetPtr(FxDriverGlobals,
|
||||
Request,
|
||||
FX_TYPE_REQUEST,
|
||||
(PVOID*) &pRequest);
|
||||
m_TrueRequest = pRequest;
|
||||
|
||||
//
|
||||
// pRequest could be currently formatted and the caller has not reused the request
|
||||
// in between the format and the sync. send. This will place pRequest into the
|
||||
// correct state.
|
||||
//
|
||||
if (pRequest->m_RequestContext != NULL) {
|
||||
pRequest->m_RequestContext->ReleaseAndRestore(pRequest);
|
||||
}
|
||||
pRequest->SetContext(Context);
|
||||
pRequest->m_RequestBaseFlags |= FxRequestBaseSyncCleanupContext;
|
||||
}
|
||||
|
||||
//
|
||||
// Indicate that there is no object header so when FxObject::Release is
|
||||
// called on the final ref count removal, it doesn't try to touch hyperspace.
|
||||
//
|
||||
SetNoContextHeader();
|
||||
}
|
||||
|
||||
FxSyncRequest::~FxSyncRequest(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destroys an FxSyncRequest. Releases the initial reference taken during the
|
||||
creation of this object. If there are any outstanding references to the
|
||||
object, the destructor will not exit they are released.
|
||||
|
||||
Arguments:
|
||||
None.
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
ULONG count;
|
||||
|
||||
//
|
||||
// Release the initial reference taken on create. Use the base release call
|
||||
// so that we don't unnecessarily set the event unless we have to.
|
||||
//
|
||||
count = __super::RELEASE(NULL);
|
||||
|
||||
//
|
||||
// For a driver supplied request(m_TrueRequest) the request context is
|
||||
// allocated on the stack so clear it.
|
||||
//
|
||||
if (m_TrueRequest != this && m_ClearContextOnDestroy) {
|
||||
m_TrueRequest->m_RequestContext = NULL;
|
||||
m_TrueRequest->m_RequestBaseFlags &= ~FxRequestBaseSyncCleanupContext;
|
||||
}
|
||||
|
||||
//
|
||||
// Clear the context so that it is not automatically deleted. Useful
|
||||
// if the caller's context is also allocated on the stack and does not
|
||||
// need to be freed (as does not have to rememeber to clear the context
|
||||
// before this object goes out of scope).
|
||||
//
|
||||
if (m_ClearContextOnDestroy) {
|
||||
m_RequestContext = NULL;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Request %p, waiting on event %p",
|
||||
this, m_DestroyedEvent.GetEvent());
|
||||
|
||||
m_DestroyedEvent.EnterCRAndWaitAndLeave();
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"Request %p, wait on event %p done",
|
||||
this, m_DestroyedEvent.GetEvent());
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxSyncRequest::SelfDestruct(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Override of base class SelfDestruct. Since this is a stack based object,
|
||||
we must delay the stack caused destruction until all outstanding references
|
||||
have been released. SelfDestruct is called when the last reference has been
|
||||
removed from the object.
|
||||
|
||||
Since this is a stack based object, do nothing to free our memory (going out
|
||||
of scope will do the trick).
|
||||
|
||||
Arguments:
|
||||
None.
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
|
||||
"SyncRequest %p, signaling event %p on SelfDestruct",
|
||||
this, m_DestroyedEvent.GetEvent());
|
||||
|
||||
m_DestroyedEvent.Set();
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxSystemWorkItem.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed WORKITEM that
|
||||
can synchrononize with driver frameworks object locks.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
#include "FxSystemWorkItem.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxSystemWorkItem.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Public constructors
|
||||
//
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxSystemWorkItem::_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PVOID WdmObject,
|
||||
__out FxSystemWorkItem** pObject
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
FxSystemWorkItem* wi;
|
||||
|
||||
wi = new(FxDriverGlobals) FxSystemWorkItem(FxDriverGlobals);
|
||||
if (wi == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = wi->Initialize(WdmObject);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
wi->Release();
|
||||
return status;
|
||||
}
|
||||
|
||||
*pObject = wi;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
FxSystemWorkItem::FxSystemWorkItem(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_SYSTEMWORKITEM, 0, FxDriverGlobals),
|
||||
m_WorkItemCompleted(NotificationEvent, TRUE),
|
||||
m_RemoveEvent(SynchronizationEvent, FALSE)
|
||||
{
|
||||
m_RunningDown = FALSE;
|
||||
m_Enqueued = FALSE;
|
||||
m_Callback = NULL;
|
||||
m_CallbackArg = NULL;
|
||||
m_WorkItemRunningCount = 0;
|
||||
m_OutStandingWorkItem = 1;
|
||||
}
|
||||
|
||||
FxSystemWorkItem::~FxSystemWorkItem()
|
||||
{
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
//
|
||||
// If this hits, it's because someone destroyed the WORKITEM by
|
||||
// removing too many references by mistake without calling WdfObjectDelete
|
||||
//
|
||||
if( !m_RunningDown && (m_WorkItem.GetWorkItem() != NULL)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WorkItem destroyed without calling "
|
||||
"FxSystemWorkItem::Delete, or by Framework "
|
||||
"processing DeviceRemove. "
|
||||
"Possible reference count problem?");
|
||||
FxVerifierDbgBreakPoint(FxDriverGlobals);
|
||||
}
|
||||
|
||||
// Free the workitem
|
||||
if( m_WorkItem.GetWorkItem() != NULL ) {
|
||||
m_WorkItem.Free();
|
||||
}
|
||||
|
||||
ASSERT(m_Enqueued == FALSE);
|
||||
ASSERT(m_WorkItemRunningCount == 0L);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxSystemWorkItem::Initialize(
|
||||
__in PVOID WdmObject
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
|
||||
NTSTATUS status;
|
||||
|
||||
//
|
||||
// Mark this object as passive level to ensure that Dispose() is passive
|
||||
//
|
||||
MarkPassiveCallbacks(ObjectDoNotLock);
|
||||
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
status = m_WorkItemCompleted.Initialize(NotificationEvent, TRUE);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not initialize m_WorkItemCompleted event "
|
||||
"status %!status!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = m_RemoveEvent.Initialize(SynchronizationEvent, FALSE);
|
||||
if(!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not initialize m_RemoveEvent event "
|
||||
"status %!status!", status);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Allocate the PIO_WORKITEM we will re-use
|
||||
//
|
||||
status = m_WorkItem.Allocate((MdDeviceObject) WdmObject);
|
||||
if(!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not allocate IoWorkItem, insufficient resources");
|
||||
return status;
|
||||
}
|
||||
|
||||
ASSERT(m_WorkItem.GetWorkItem() != NULL);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxSystemWorkItem::EnqueueWorker(
|
||||
__in PFN_WDF_SYSTEMWORKITEM Func,
|
||||
__in PVOID Parameter,
|
||||
__in BOOLEAN AssertIfAlreadyQueued
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Called to queue the workitem. This function, under verifier, will
|
||||
throw an assert if AssertIfAlreadyQueued parameter is set.
|
||||
|
||||
Arguments:
|
||||
Func - Callback function.
|
||||
|
||||
Parameter - Callback's context.
|
||||
|
||||
AssertIfAlreadyQueued - is used to make sure that caller doesn't
|
||||
miss any workitem callback.
|
||||
|
||||
Return Value:
|
||||
|
||||
FALSE
|
||||
- if the previously queued workitem hasn't run to completion.
|
||||
- if the object is running down.
|
||||
|
||||
TRUE - workitem is queued.
|
||||
--*/
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
KIRQL irql;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
if( m_Enqueued ) {
|
||||
if (AssertIfAlreadyQueued) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WorkItem 0x%p already enqueued IoWorkItem 0x%p",
|
||||
this, m_WorkItem.GetWorkItem());
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// If running down, fail
|
||||
//
|
||||
if( m_RunningDown ) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WorkItem 0x%p is already deleted", this);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
Unlock(irql);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_WorkItemCompleted.Clear();
|
||||
|
||||
m_Callback = Func;
|
||||
m_CallbackArg = Parameter;
|
||||
|
||||
m_Enqueued = TRUE;
|
||||
|
||||
// Add a reference while outstanding
|
||||
IncrementWorkItemQueued();
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
m_WorkItem.Enqueue(_WorkItemThunk, this);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxSystemWorkItem::WorkItemHandler()
|
||||
{
|
||||
PFN_WDF_SYSTEMWORKITEM Callback;
|
||||
PVOID CallbackArg;
|
||||
KIRQL irql;
|
||||
|
||||
FX_TRACK_DRIVER(GetDriverGlobals());
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
m_Enqueued = FALSE;
|
||||
|
||||
Callback = m_Callback;
|
||||
CallbackArg = m_CallbackArg;
|
||||
|
||||
m_Callback = NULL;
|
||||
|
||||
//
|
||||
// We should only see this count rise to a small number (like 10 or so).
|
||||
//
|
||||
ASSERT(m_WorkItemRunningCount < 0xFF);
|
||||
|
||||
m_WorkItemRunningCount++;
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
Callback(CallbackArg);
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
m_WorkItemRunningCount--;
|
||||
|
||||
//
|
||||
// The driver could re-enqueue a new callback from within the
|
||||
// callback handler, which could make m_Enqueued no longer false.
|
||||
//
|
||||
// We only set the event specifying the callback as completed when
|
||||
// we are ensured that no more workitems are enqueued.
|
||||
//
|
||||
if (m_WorkItemRunningCount == 0L && m_Enqueued == FALSE) {
|
||||
m_WorkItemCompleted.Set();
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxSystemWorkItem::_WorkItemThunk(
|
||||
__in MdDeviceObject DeviceObject,
|
||||
__in_opt PVOID Context
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the static routine called by the kernel's PIO_WORKITEM handler.
|
||||
|
||||
A reference count was taken by Enqueue, which this routine releases
|
||||
on return.
|
||||
|
||||
Arguments:
|
||||
|
||||
Return Value:
|
||||
|
||||
Nothing.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxSystemWorkItem* pWorkItem = (FxSystemWorkItem*)Context;
|
||||
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
|
||||
pWorkItem->WorkItemHandler();
|
||||
|
||||
// Release the reference taken when enqueued
|
||||
pWorkItem->DecrementWorkItemQueued();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Invoked when DeleteObject is called on the object, or its parent.
|
||||
//
|
||||
BOOLEAN
|
||||
FxSystemWorkItem::Dispose(
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
ASSERT(!m_RunningDown);
|
||||
|
||||
m_RunningDown = TRUE;
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
ReleaseWorkItemQueuedCountAndWait();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Wait until any outstanding WorkItem has completed safely
|
||||
//
|
||||
// Can only be called after Delete
|
||||
//
|
||||
// The caller must call AddRef() and Release() around this call
|
||||
// to ensure the FxSystemWorkItem remains valid while it is doing the
|
||||
// wait.
|
||||
//
|
||||
VOID
|
||||
FxSystemWorkItem::WaitForExit(
|
||||
)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
//
|
||||
// Wait for current workitem to complete processing
|
||||
//
|
||||
Status = m_WorkItemCompleted.EnterCRAndWaitAndLeave();
|
||||
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
UNREFERENCED_PARAMETER(Status);
|
||||
|
||||
//
|
||||
// This assert is not under a lock, but the code in WorkItemHandler()
|
||||
// clears m_Enqueued under the lock, thus releasing it with a memory
|
||||
// barrier. Since we have ensured above that no one can re-queue a request
|
||||
// due to m_RunningDown, we should not hit this assert unless there
|
||||
// is a code problem with wakeup occuring while an outstanding
|
||||
// workitem is running.
|
||||
//
|
||||
ASSERT(m_Enqueued == FALSE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,779 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxTimer.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed TIMER that
|
||||
can synchrononize with driver frameworks object locks.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
#include "FxTimer.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxTimer.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Public constructors
|
||||
//
|
||||
|
||||
FxTimer::FxTimer(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_TIMER, sizeof(FxTimer), FxDriverGlobals)
|
||||
{
|
||||
m_Object = NULL;
|
||||
m_Period = 0;
|
||||
m_TolerableDelay = 0;
|
||||
m_CallbackLock = NULL;
|
||||
m_CallbackLockObject = NULL;
|
||||
m_Callback = NULL;
|
||||
m_RunningDown = FALSE;
|
||||
m_SystemWorkItem = NULL;
|
||||
m_CallbackThread = NULL;
|
||||
m_StopThread = NULL;
|
||||
m_StopAgain = FALSE;
|
||||
m_StartAborted = FALSE;
|
||||
|
||||
//
|
||||
// Mark the object has having passive level dispose so that KeFlushQueuedDpcs
|
||||
// can be called in Dispose().
|
||||
//
|
||||
MarkPassiveDispose(ObjectDoNotLock);
|
||||
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
}
|
||||
|
||||
FxTimer::~FxTimer()
|
||||
{
|
||||
//
|
||||
// If this hits, its because someone destroyed the TIMER by
|
||||
// removing too many references by mistake without calling WdfObjectDelete
|
||||
//
|
||||
if (m_Object != NULL) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFTIMER %p destroyed without calling WdfObjectDelete, "
|
||||
"or by Framework processing DeviceRemove. Possible reference count "
|
||||
"problem?", GetObjectHandleUnchecked());
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
}
|
||||
|
||||
ASSERT(m_SystemWorkItem == NULL);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxTimer::_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PWDF_TIMER_CONFIG Config,
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in FxObject* ParentObject,
|
||||
__out WDFTIMER* Timer
|
||||
)
|
||||
{
|
||||
FxTimer* pFxTimer;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxTimer = new(FxDriverGlobals, Attributes) FxTimer(FxDriverGlobals);
|
||||
|
||||
if (pFxTimer == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = pFxTimer->Initialize(
|
||||
Attributes,
|
||||
Config,
|
||||
ParentObject,
|
||||
Timer
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pFxTimer->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxTimer::Initialize(
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in PWDF_TIMER_CONFIG Config,
|
||||
__in FxObject* ParentObject,
|
||||
__out WDFTIMER* Timer
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
IFxHasCallbacks* pCallbacks;
|
||||
NTSTATUS status;
|
||||
BOOLEAN isPassiveTimer;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
pCallbacks = NULL;
|
||||
isPassiveTimer = FALSE;
|
||||
|
||||
m_Period = Config->Period;
|
||||
|
||||
// Set tolerable delay.
|
||||
if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_7)) {
|
||||
m_TolerableDelay = Config->TolerableDelay;
|
||||
}
|
||||
|
||||
if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_11)) {
|
||||
m_UseHighResolutionTimer = Config->UseHighResolutionTimer;
|
||||
}
|
||||
|
||||
// Set users callback function
|
||||
m_Callback = Config->EvtTimerFunc;
|
||||
|
||||
//
|
||||
// Decide whether to use the legacy KTimer or the new Ktimer2/ExTimer
|
||||
// and call the appropriate initialization routine.
|
||||
// The new ExTimers expose two kind of timers:no wake timers and the
|
||||
// high resolution timers. For kernel mode, these timers are only exposed
|
||||
// to new clients.
|
||||
// For user mode,the underlying Threadpool APIs internally were upgraded
|
||||
// to using the no wake timers and we don't expose the High
|
||||
// resolution timers. Therefore the user mode code does not need to use
|
||||
// the ex initialization.
|
||||
//
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13)) {
|
||||
status = m_Timer.InitializeEx(this, FxTimer::_FxTimerExtCallbackThunk, m_Period,
|
||||
m_TolerableDelay, m_UseHighResolutionTimer);
|
||||
} else {
|
||||
status = m_Timer.Initialize(this, FxTimer::_FxTimerDpcThunk, m_Period);
|
||||
}
|
||||
#else
|
||||
status = m_Timer.Initialize(this, FxTimer::_FxTimerDpcThunk, m_Period);
|
||||
#endif
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Failed to initialize timer %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// As long as we are associated, the parent object holds a reference
|
||||
// count on the TIMER.
|
||||
//
|
||||
// We keep an extra reference count since on Dispose, we wait until
|
||||
// all outstanding DPCs complete before allowing finalization.
|
||||
//
|
||||
// This reference must be taken early before we return any failure,
|
||||
// since Dispose() expects this extra reference, and Dispose() will
|
||||
// be called even if we return a failure status right now.
|
||||
//
|
||||
ADDREF(this);
|
||||
|
||||
m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks);
|
||||
if (m_DeviceBase == NULL) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
if (Attributes->ExecutionLevel == WdfExecutionLevelPassive) {
|
||||
isPassiveTimer = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Configure Serialization for the callbacks on the supplied object.
|
||||
//
|
||||
status = _GetEffectiveLock(
|
||||
ParentObject,
|
||||
pCallbacks,
|
||||
Config->AutomaticSerialization,
|
||||
isPassiveTimer,
|
||||
&m_CallbackLock,
|
||||
&m_CallbackLockObject
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (status == STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"ParentObject %p cannot automatically synchronize callbacks "
|
||||
"with a Timer since it is configured for passive level callback "
|
||||
"constraints. Set AutomaticSerialization to FALSE. %!STATUS!",
|
||||
Attributes->ParentObject, status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// If the caller wants passive callback then create a workitem.
|
||||
//
|
||||
if (isPassiveTimer) {
|
||||
status = FxSystemWorkItem::_Create(pFxDriverGlobals,
|
||||
m_Device->GetDeviceObject(),
|
||||
&m_SystemWorkItem
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not allocate workitem: %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We automatically synchronize with and reference count
|
||||
// the lifetime of the framework object to prevent any TIMER races
|
||||
// that can access the object while it is going away.
|
||||
//
|
||||
|
||||
//
|
||||
// The caller supplied object is the object the caller wants the
|
||||
// TIMER to be associated with, and the framework must ensure this
|
||||
// object remains live until the TIMER object is destroyed. Otherwise,
|
||||
// it could access either object context memory, or an object API
|
||||
// on a freed object.
|
||||
//
|
||||
// Due to the locking model of the framework, the lock may actually
|
||||
// be owned by a higher level object as well. This is the lockObject
|
||||
// returned. As long was we are a child of this object, the lockObject
|
||||
// does not need to be dereferenced since it will notify us of Cleanup
|
||||
// before it goes away.
|
||||
//
|
||||
|
||||
//
|
||||
// Associate the FxTimer with the object. When this object Cleans up, it
|
||||
// will notify our Dispose function as well.
|
||||
//
|
||||
|
||||
//
|
||||
// Add a reference to the parent object we are associated with.
|
||||
// We will be notified of Cleanup to release this reference.
|
||||
//
|
||||
ParentObject->ADDREF(this);
|
||||
|
||||
//
|
||||
// Save the ptr to the object the TIMER is associated with
|
||||
//
|
||||
m_Object = ParentObject;
|
||||
|
||||
//
|
||||
// Attributes->ParentObject is the same as ParentObject. Since we already
|
||||
// converted it to an object, use that.
|
||||
//
|
||||
status = Commit(Attributes, (WDFOBJECT*)Timer, ParentObject);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTimer::TimerHandler(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
FX_TRACK_DRIVER(GetDriverGlobals());
|
||||
|
||||
if (m_Callback != NULL) {
|
||||
|
||||
//
|
||||
// Save the current thread object pointer. We will use this avoid
|
||||
// deadlock if the driver tries to delete or stop the timer from within
|
||||
// the callback.
|
||||
//
|
||||
m_CallbackThread = Mx::MxGetCurrentThread();
|
||||
|
||||
if (m_CallbackLock != NULL) {
|
||||
KIRQL irql = 0;
|
||||
|
||||
m_CallbackLock->Lock(&irql);
|
||||
m_Callback(GetHandle());
|
||||
m_CallbackLock->Unlock(irql);
|
||||
}
|
||||
else {
|
||||
m_Callback(GetHandle());
|
||||
}
|
||||
|
||||
m_CallbackThread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTimer::_FxTimerDpcThunk(
|
||||
__in PKDPC TimerDpc,
|
||||
__in PVOID DeferredContext,
|
||||
__in PVOID SystemArgument1,
|
||||
__in PVOID SystemArgument2
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the C routine called by the kernel's TIMER DPC handler
|
||||
|
||||
Arguments:
|
||||
|
||||
TimerDpc - our DPC object associated with our Timer
|
||||
DeferredContext - Context for the TIMER that we setup in DriverEntry
|
||||
SystemArgument1 -
|
||||
SystemArgument2 -
|
||||
|
||||
Return Value:
|
||||
|
||||
Nothing.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxTimer* pTimer = (FxTimer*)DeferredContext;
|
||||
|
||||
UNREFERENCED_PARAMETER(TimerDpc);
|
||||
UNREFERENCED_PARAMETER(SystemArgument1);
|
||||
UNREFERENCED_PARAMETER(SystemArgument2);
|
||||
|
||||
if (pTimer->m_SystemWorkItem == NULL) {
|
||||
|
||||
#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
|
||||
FxPerfTraceDpc(&pTimer->m_Callback);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Dispatch-level timer callback
|
||||
//
|
||||
pTimer->TimerHandler();
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Passive timer callback.Queue only if the previous one is completed.
|
||||
//
|
||||
pTimer->m_SystemWorkItem->TryToEnqueue(_FxTimerWorkItemCallback, pTimer);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTimer::_FxTimerExtCallbackThunk(
|
||||
__in PEX_TIMER Timer,
|
||||
__in PVOID Context
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the C routine called by the kernel's ex timer
|
||||
|
||||
Arguments:
|
||||
|
||||
Timer - Ex timer
|
||||
Context - Context for the TIMER that we passed while creating it
|
||||
|
||||
Return Value:
|
||||
|
||||
Nothing.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxTimer* pTimer = (FxTimer*)Context;
|
||||
|
||||
UNREFERENCED_PARAMETER(Timer);
|
||||
|
||||
if (pTimer->m_SystemWorkItem == NULL) {
|
||||
|
||||
#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
|
||||
FxPerfTraceDpc(&pTimer->m_Callback);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Dispatch-level timer callback
|
||||
//
|
||||
pTimer->TimerHandler();
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Passive timer callback.Queue only if the previous one is completed.
|
||||
//
|
||||
pTimer->m_SystemWorkItem->TryToEnqueue(_FxTimerWorkItemCallback, pTimer);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTimer::_FxTimerWorkItemCallback(
|
||||
__in PVOID Parameter
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Thunk used when callback must be made at passive-level
|
||||
|
||||
--*/
|
||||
{
|
||||
FxTimer* pTimer = (FxTimer*)Parameter;
|
||||
|
||||
pTimer->TimerHandler();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Called when DeleteObject is called, or when the parent
|
||||
// is being deleted or Disposed.
|
||||
//
|
||||
// Also invoked directly by the cleanup list at our request after
|
||||
// a Dispose occurs and must be deferred if not at passive level.
|
||||
//
|
||||
BOOLEAN
|
||||
FxTimer::Dispose()
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
// MarkPassiveDispose() in Initialize ensures this
|
||||
ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
//
|
||||
// Signal that we are running down.
|
||||
//
|
||||
Lock(&irql);
|
||||
m_RunningDown = TRUE;
|
||||
Unlock(irql);
|
||||
|
||||
//
|
||||
// Cancel the timer, wait for its callback, then cleanup.
|
||||
//
|
||||
FlushAndRundown();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTimer::FlushAndRundown(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Called by the system work item to finish the rundown.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
FxObject* pObject;
|
||||
|
||||
if (m_CallbackThread == Mx::MxGetCurrentThread()) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Deleting WDFTIMER %p from with in the callback will "
|
||||
"lead to deadlock, PRKTHREAD %p",
|
||||
GetHandle(), m_CallbackThread);
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
}
|
||||
|
||||
//
|
||||
// Cancel the timer, wait for its callback.
|
||||
//
|
||||
Stop(TRUE);
|
||||
|
||||
//
|
||||
// Delete will also wait for the workitem to exit.
|
||||
//
|
||||
if (m_SystemWorkItem != NULL) {
|
||||
m_SystemWorkItem->DeleteObject();
|
||||
m_SystemWorkItem = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Release our reference count to the associated parent object if present
|
||||
//
|
||||
if (m_Object != NULL) {
|
||||
pObject = m_Object;
|
||||
m_Object = NULL;
|
||||
|
||||
pObject->RELEASE(this);
|
||||
}
|
||||
|
||||
//
|
||||
// Perform our final release to ourselves, destroying the FxTimer
|
||||
//
|
||||
RELEASE(this);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxTimer::Start(
|
||||
__in LARGE_INTEGER DueTime
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Start or restart the timer
|
||||
|
||||
Arguments:
|
||||
|
||||
DueTime - Time when the timer will be scheduled
|
||||
|
||||
Returns:
|
||||
|
||||
TRUE if a previous timer was reset to the new duetime.
|
||||
FALSE otherwise.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
KIRQL irql;
|
||||
BOOLEAN result = FALSE;
|
||||
BOOLEAN startTimer = FALSE;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
//
|
||||
// Basic check to make sure timer object is not deleted. Note that this
|
||||
// logic is not foolproof b/c someone may dispose the timer just after this
|
||||
// validation and before the start routine queues the timer; but at least it
|
||||
// is better than nothing.
|
||||
//
|
||||
if (m_RunningDown) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Calling WdfTimerStart when the timer object %p is"
|
||||
" running down will lead to a crash",
|
||||
GetHandle());
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
}
|
||||
else if (m_StopThread != NULL) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFTIMER 0x%p is been stopped by PRKTHREAD 0x%p. "
|
||||
"Ignoring the request to start timer",
|
||||
GetHandle(), m_StopThread);
|
||||
|
||||
//
|
||||
// Let the stop thread know that we aborted this start operation.
|
||||
//
|
||||
m_StartAborted = TRUE;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Yes, the timer can be started.
|
||||
//
|
||||
startTimer = TRUE;
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
if (startTimer) {
|
||||
//
|
||||
// It may be possible for the timer to fire before the call from
|
||||
// KeSetTimerEx completes. If this happens and if the timer callback
|
||||
// disposes the timer object, a dispose work-item is queued.
|
||||
// This work-item in turn may also run before KeSetTimerEx completes,
|
||||
// making the object invalid by the time we try to take its Lock()
|
||||
// below. This ADDREF() prevents the object from going away and it is
|
||||
// matched by a RELEASE() when we are done.
|
||||
//
|
||||
ADDREF(this);
|
||||
|
||||
//
|
||||
// Call the tolerable timer API only if OS supports it and driver
|
||||
// requested it.
|
||||
//
|
||||
result = m_Timer.StartWithReturn(DueTime, m_TolerableDelay);
|
||||
|
||||
Lock(&irql);
|
||||
if (m_StopThread != NULL) {
|
||||
m_StopAgain = TRUE;
|
||||
}
|
||||
Unlock(irql);
|
||||
|
||||
//
|
||||
// See ADDREF() comment above.
|
||||
//
|
||||
RELEASE(this);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxTimer::Stop(
|
||||
__in BOOLEAN Wait
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
BOOLEAN result;
|
||||
#ifdef DBG
|
||||
ULONG retryCount = 0;
|
||||
#endif
|
||||
|
||||
if (Wait) {
|
||||
//
|
||||
// If the caller specified wait, we will flush the queued DPC's
|
||||
// to ensure any outstanding timer DPC has finished executing.
|
||||
//
|
||||
// The return value of timers is ambiguous in the case of periodic
|
||||
// timers, so we flush whenever the caller desires to ensure all
|
||||
// callbacks are complete.
|
||||
//
|
||||
|
||||
//
|
||||
// Make sure the stop is not called from within the callback
|
||||
// because it's semantically incorrect and can lead to deadlock
|
||||
// if the wait parameter is set.
|
||||
//
|
||||
if (m_CallbackThread == Mx::MxGetCurrentThread()) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Calling WdfTimerStop from within the WDFTIMER "
|
||||
"%p callback will lead to deadlock, PRKTHREAD %p",
|
||||
GetHandle(), m_CallbackThread);
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GetDriverGlobals()->FxVerifierOn) {
|
||||
if (Mx::MxGetCurrentIrql() != PASSIVE_LEVEL) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WdfTimerStop(Wait==TRUE) called at IRQL > PASSIVE_LEVEL, "
|
||||
"current IRQL = 0x%x", Mx::MxGetCurrentIrql());
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Prevent the callback from restarting the timer.
|
||||
//
|
||||
Lock(&irql);
|
||||
|
||||
//
|
||||
// Driver issue.
|
||||
//
|
||||
if (GetDriverGlobals()->IsVerificationEnabled(1, 9, OkForDownLevel) &&
|
||||
m_StopThread != NULL) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Detected multiple calls to WdfTimerStop for "
|
||||
"WDFTIMER 0x%p, stop in progress on PRKTHREAD 0x%p, "
|
||||
"current PRKTHREAD 0x%p",
|
||||
GetHandle(), m_StopThread, Mx::MxGetCurrentThread());
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
}
|
||||
|
||||
//
|
||||
// Reset the flag to find out if the timer's start logic aborts
|
||||
// b/c of this stop operation.
|
||||
//
|
||||
m_StartAborted = FALSE;
|
||||
|
||||
//
|
||||
// This field is used for the following purposes:
|
||||
// (a) Let the start thread know not to restart the timer while stop
|
||||
// is running.
|
||||
// (b) Detect concurrent calls to stop the timer.
|
||||
// (c) To remember the thread id of the stopping thread.
|
||||
//
|
||||
m_StopThread = Mx::MxGetCurrentThread();
|
||||
|
||||
do {
|
||||
#ifdef DBG
|
||||
retryCount++;
|
||||
#endif
|
||||
//
|
||||
// Reset flag to catch when timer callback is restarting the
|
||||
// timer.
|
||||
//
|
||||
m_StopAgain = FALSE;
|
||||
Unlock(irql);
|
||||
|
||||
//
|
||||
// Cancel the timer
|
||||
//
|
||||
result = m_Timer.Stop();
|
||||
|
||||
//
|
||||
// Wait for the timer's DPC.
|
||||
//
|
||||
m_Timer.FlushQueuedDpcs();
|
||||
|
||||
//
|
||||
// Wait for the timer's passive work item.
|
||||
//
|
||||
if (m_SystemWorkItem != NULL) {
|
||||
m_SystemWorkItem->WaitForExit();
|
||||
}
|
||||
|
||||
Lock(&irql);
|
||||
#ifdef DBG
|
||||
//
|
||||
// This loop is run for a max of 2 times.
|
||||
//
|
||||
ASSERT(retryCount < 3);
|
||||
#endif
|
||||
//
|
||||
// Re-stop timer if timer was not in queue and
|
||||
// it got restarted in callback.
|
||||
//
|
||||
}while (result == FALSE && m_StopAgain);
|
||||
|
||||
//
|
||||
// Stop completed.
|
||||
//
|
||||
m_StopThread = NULL;
|
||||
m_StopAgain = FALSE;
|
||||
|
||||
//
|
||||
// Return TRUE (i.e., timer in queue) if
|
||||
// (a) stop logic successfully cancelled the timer or
|
||||
// (b) the start logic aborted b/c of this stop.
|
||||
//
|
||||
if (m_StartAborted) {
|
||||
result = TRUE;
|
||||
m_StartAborted = FALSE;
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Caller doesn't want any synchronization.
|
||||
// Cancel the timer.
|
||||
//
|
||||
result = m_Timer.Stop();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxTimerApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This implements the WDFTIMER API's
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
#include "FxTimer.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxTimerApi.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfTimerCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PWDF_TIMER_CONFIG Config,
|
||||
__in
|
||||
PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__out
|
||||
WDFTIMER * Timer
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Create a TIMER object that will call the supplied function
|
||||
when it fires. It returns a handle to the WDFTIMER object.
|
||||
|
||||
Arguments:
|
||||
|
||||
Config - WDF_TIMER_CONFIG structure.
|
||||
|
||||
Attributes - WDF_OBJECT_ATTRIBUTES to set the parent object, to request
|
||||
a context memory allocation and a DestroyCallback.
|
||||
|
||||
Timer - Pointer to location to return the resulting WDFTIMER handle.
|
||||
|
||||
Returns:
|
||||
|
||||
STATUS_SUCCESS - A WDFTIMER handle has been created.
|
||||
|
||||
Notes:
|
||||
|
||||
The WDFTIMER object is deleted either when the DEVICE or QUEUE it is
|
||||
associated with is deleted, or WdfObjectDelete is called.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxObject* pParent;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
|
||||
Attributes,
|
||||
FX_VALIDATE_OPTION_PARENT_REQUIRED);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
Attributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Config);
|
||||
FxPointerNotNull(pFxDriverGlobals, Timer);
|
||||
|
||||
if (Config->Size != sizeof(WDF_TIMER_CONFIG) &&
|
||||
Config->Size != sizeof(WDF_TIMER_CONFIG_V1_7) &&
|
||||
Config->Size != sizeof(WDF_TIMER_CONFIG_V1_11)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"PWDF_TIMER_CONFIG Size %d, expected %d, %!STATUS!",
|
||||
Config->Size, sizeof(WDF_TIMER_CONFIG), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Config->Period > MAXLONG) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Period value %u for a periodic timer cannot be greater than "
|
||||
"MAXLONG, %!STATUS!", Config->Period, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// For version 1.13 and higher, the tolerable delay could
|
||||
// go upto MAXULONG
|
||||
//
|
||||
if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_7) &&
|
||||
(pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13) == FALSE)) {
|
||||
if (Config->TolerableDelay > MAXLONG) {
|
||||
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"TolerableDelay value %u cannot be greater than MAXLONG, "
|
||||
"%!STATUS!", Config->TolerableDelay, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_11)) {
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
if (Config->UseHighResolutionTimer) {
|
||||
|
||||
status = STATUS_NOT_IMPLEMENTED;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"UseHighResolutionTimer option is not supported for UMDF "
|
||||
"%!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((Config->TolerableDelay > 0) &&
|
||||
(Config->UseHighResolutionTimer)) {
|
||||
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"UseHighResolutionTimer option sepcified with non zero tolerable delay %u "
|
||||
"%!STATUS!", Config->TolerableDelay, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals,
|
||||
Attributes,
|
||||
FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Config->Period > 0 &&
|
||||
Attributes->ExecutionLevel == WdfExecutionLevelPassive) {
|
||||
status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Passive level periodic timer is not supported. "
|
||||
"Use one shot timer and queue the next timer from the callback "
|
||||
"or use a dedicated thread, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
return FxTimer::_Create(pFxDriverGlobals, Config, Attributes, pParent, Timer);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
WDFEXPORT(WdfTimerStart)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFTIMER Timer,
|
||||
__in
|
||||
LONGLONG DueTime
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Enqueue the TIMER to run at the specified time.
|
||||
|
||||
Arguments:
|
||||
|
||||
WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate.
|
||||
|
||||
DueTime - Time to execute
|
||||
|
||||
Returns:
|
||||
|
||||
TRUE if the timer object was in the system's timer queue
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxTimer* pFxTimer;
|
||||
LARGE_INTEGER li;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Timer,
|
||||
FX_TYPE_TIMER,
|
||||
(PVOID*)&pFxTimer);
|
||||
|
||||
li.QuadPart = DueTime;
|
||||
|
||||
return pFxTimer->Start(li);
|
||||
}
|
||||
|
||||
__drv_when(Wait == __true, __drv_maxIRQL(PASSIVE_LEVEL))
|
||||
__drv_when(Wait == __false, __drv_maxIRQL(DISPATCH_LEVEL))
|
||||
BOOLEAN
|
||||
WDFEXPORT(WdfTimerStop)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFTIMER Timer,
|
||||
__in
|
||||
BOOLEAN Wait
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Stop the TIMER
|
||||
|
||||
Arguments:
|
||||
|
||||
WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate.
|
||||
|
||||
Returns:
|
||||
|
||||
TRUE if the timer object was in the system's timer queue
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxTimer* pFxTimer;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Timer,
|
||||
FX_TYPE_TIMER,
|
||||
(PVOID*)&pFxTimer,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
if (Wait) {
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return pFxTimer->Stop(Wait);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFOBJECT
|
||||
WDFEXPORT(WdfTimerGetParentObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFTIMER Timer
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Return the Parent Object handle supplied to WdfTimerCreate
|
||||
|
||||
Arguments:
|
||||
|
||||
WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate.
|
||||
|
||||
Returns:
|
||||
|
||||
Handle to the framework object that is the specified timer object's
|
||||
parent object
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxTimer* pFxTimer;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Timer,
|
||||
FX_TYPE_TIMER,
|
||||
(PVOID*)&pFxTimer);
|
||||
|
||||
return pFxTimer->GetObject();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,561 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxWorkItem.hpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a frameworks managed WORKITEM that
|
||||
can synchrononize with driver frameworks object locks.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
#include "FxWorkItem.hpp"
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
//
|
||||
// For DRIVER_OBJECT_UM definition
|
||||
//
|
||||
#include "fxldrum.h"
|
||||
#endif
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxWorkItem.tmh"
|
||||
}
|
||||
|
||||
FxWorkItem::FxWorkItem(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_WORKITEM, sizeof(FxWorkItem), FxDriverGlobals),
|
||||
m_WorkItemCompleted(NotificationEvent, TRUE)
|
||||
{
|
||||
m_Object = NULL;
|
||||
m_Callback = NULL;
|
||||
m_CallbackLock = NULL;
|
||||
m_CallbackLockObject = NULL;
|
||||
m_RunningDown = FALSE;
|
||||
m_Enqueued = FALSE;
|
||||
m_WorkItemThread = NULL;
|
||||
m_WorkItemRunningCount = 0;
|
||||
|
||||
//
|
||||
// All operations on a workitem are PASSIVE_LEVEL so ensure that any Dispose
|
||||
// and Destroy callbacks to the driver are as well.
|
||||
//
|
||||
MarkPassiveCallbacks(ObjectDoNotLock);
|
||||
|
||||
MarkDisposeOverride(ObjectDoNotLock);
|
||||
}
|
||||
|
||||
|
||||
FxWorkItem::~FxWorkItem(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
//
|
||||
// If this hits, it's because someone destroyed the WORKITEM by
|
||||
// removing too many references by mistake without calling WdfObjectDelete
|
||||
//
|
||||
if (m_RunningDown == FALSE && m_Callback != NULL) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFWORKITEM %p destroyed without calling WdfObjectDelete, or by "
|
||||
"Framework processing DeviceRemove. Possible reference count "
|
||||
"problem?", GetObjectHandleUnchecked());
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
|
||||
// Release our parent object reference
|
||||
if (m_Object != NULL) {
|
||||
m_Object->RELEASE(this);
|
||||
m_Object = NULL;
|
||||
}
|
||||
|
||||
// Free the workitem
|
||||
if (m_WorkItem.GetWorkItem() != NULL) {
|
||||
m_WorkItem.Free();
|
||||
//m_WorkItem = NULL;
|
||||
}
|
||||
|
||||
ASSERT(m_Enqueued == FALSE);
|
||||
ASSERT(m_WorkItemRunningCount == 0L);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWorkItem::_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PWDF_WORKITEM_CONFIG Config,
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in FxObject* ParentObject,
|
||||
__out WDFWORKITEM* WorkItem
|
||||
)
|
||||
{
|
||||
FxWorkItem* pFxWorkItem;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxWorkItem = new(FxDriverGlobals, Attributes) FxWorkItem(FxDriverGlobals);
|
||||
|
||||
if (pFxWorkItem == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = pFxWorkItem->Initialize(
|
||||
Attributes,
|
||||
Config,
|
||||
ParentObject,
|
||||
WorkItem
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pFxWorkItem->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWorkItem::Initialize(
|
||||
__in PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in PWDF_WORKITEM_CONFIG Config,
|
||||
__in FxObject* ParentObject,
|
||||
__out WDFWORKITEM* WorkItem
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
IFxHasCallbacks* pCallbacks;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
status = m_WorkItemCompleted.Initialize(NotificationEvent, TRUE);
|
||||
if(!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not initialize m_WorkItemCompleted event "
|
||||
"%!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT(Config->EvtWorkItemFunc != NULL);
|
||||
|
||||
// Set users callback function
|
||||
m_Callback = Config->EvtWorkItemFunc;
|
||||
|
||||
//
|
||||
// As long as we are associated, the parent object holds a reference
|
||||
// count on the WDFWORKITEM.
|
||||
//
|
||||
// This reference must be taken early before we return any failure,
|
||||
// since Dispose() expects this extra reference, and Dispose() will
|
||||
// be called even if we return a failure status right now.
|
||||
//
|
||||
ADDREF(this);
|
||||
|
||||
//
|
||||
// WorkItems can be parented by, and optionally serialize with an FxDevice or an FxQueue
|
||||
//
|
||||
m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks);
|
||||
|
||||
if (m_DeviceBase == NULL) {
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine if it's an FxDevice, or FxIoQueue and get the
|
||||
// CallbackSpinLock pointer for it.
|
||||
//
|
||||
status = _GetEffectiveLock(
|
||||
ParentObject,
|
||||
pCallbacks,
|
||||
Config->AutomaticSerialization,
|
||||
TRUE,
|
||||
&m_CallbackLock,
|
||||
&m_CallbackLockObject
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (status == STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"ParentObject %p cannot automatically synchronize callbacks "
|
||||
"with a WorkItem since it is not configured for passive level "
|
||||
"callback constraints. Use a WDFDPC instead or set "
|
||||
"AutomaticSerialization to FALSE."
|
||||
"%!STATUS!", Attributes->ParentObject, status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate the PIO_WORKITEM we will re-use
|
||||
//
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
m_WorkItem.Allocate(m_Device->GetDeviceObject());
|
||||
#elif (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
m_WorkItem.Allocate(
|
||||
m_Device->GetDeviceObject(),
|
||||
(PVOID)&m_Device->GetDriver()->GetDriverObject()->ThreadPoolEnv);
|
||||
#endif
|
||||
if (m_WorkItem.GetWorkItem() == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not allocate IoWorkItem, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// We automatically synchronize with and reference count
|
||||
// the lifetime of the framework object to prevent any WORKITEM races
|
||||
// that can access the object while it is going away.
|
||||
//
|
||||
|
||||
//
|
||||
// The caller supplied object is the object the caller wants the
|
||||
// WorkItem to be associated with, and the framework must ensure this
|
||||
// object remains live until the WorkItem object is destroyed. Otherwise,
|
||||
// it could access either object context memory, or an object API
|
||||
// on a freed object.
|
||||
//
|
||||
// Due to the locking model of the framework, the lock may actually
|
||||
// be owned by a higher level object as well. This is the lockObject
|
||||
// returned. As long as we are a child of this object, the lockObject
|
||||
// does not need to be dereferenced since it will notify us of Cleanup
|
||||
// before it goes away.
|
||||
//
|
||||
|
||||
//
|
||||
// Associate the FxWorkItem with the object. When this object Cleans up, it
|
||||
// will notify our Cleanup function as well.
|
||||
//
|
||||
|
||||
//
|
||||
// Add a reference to the parent object we are associated with.
|
||||
// We will be notified of Cleanup to release this reference.
|
||||
//
|
||||
ParentObject->ADDREF(this);
|
||||
|
||||
// Save the ptr to the object the WorkItem is associated with
|
||||
m_Object = ParentObject;
|
||||
|
||||
//
|
||||
// Attributes->ParentObject is the same as ParentObject. Since we already
|
||||
// converted it to an object, use that.
|
||||
//
|
||||
status = Commit(Attributes, (WDFOBJECT*)WorkItem, ParentObject);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxWorkItem::Enqueue(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
KIRQL irql;
|
||||
BOOLEAN enqueue;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
enqueue = FALSE;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
if (m_Enqueued) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE,
|
||||
"Previously queued WDFWORKITEM 0x%p is already pending. "
|
||||
"Ignoring the request to queue again", GetHandle());
|
||||
}
|
||||
else if (m_RunningDown) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFWORKITEM 0x%p is already deleted", GetHandle());
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
else {
|
||||
m_WorkItemCompleted.Clear();
|
||||
|
||||
m_Enqueued = TRUE;
|
||||
|
||||
//
|
||||
// We are going to enqueue the work item. Reference this FxWorkItem
|
||||
// object and Globals while they are outstanding.
|
||||
// These will be released when the workitem completes.
|
||||
//
|
||||
ADDREF(WorkItemThunk);
|
||||
pFxDriverGlobals->ADDREF(WorkItemThunk);
|
||||
|
||||
enqueue = TRUE;
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
if (enqueue) {
|
||||
m_WorkItem. Enqueue(FxWorkItem::WorkItemThunk, this);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxWorkItem::WorkItemHandler(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
FX_TRACK_DRIVER(GetDriverGlobals());
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
//
|
||||
// Mark the workitem as no longer enqueued and completed
|
||||
//
|
||||
// The handler is allowed to re-enqueue, so mark it before the callback
|
||||
//
|
||||
m_Enqueued = FALSE;
|
||||
|
||||
m_WorkItemRunningCount++;
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
if (m_CallbackLock != NULL) {
|
||||
m_CallbackLock->Lock(&irql);
|
||||
#if FX_IS_KERNEL_MODE
|
||||
FxPerfTraceWorkItem(&m_Callback);
|
||||
#endif
|
||||
m_Callback(GetHandle());
|
||||
m_CallbackLock->Unlock(irql);
|
||||
}
|
||||
else {
|
||||
#if FX_IS_KERNEL_MODE
|
||||
FxPerfTraceWorkItem(&m_Callback);
|
||||
#endif
|
||||
m_Callback(GetHandle());
|
||||
}
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
m_WorkItemRunningCount--;
|
||||
|
||||
//
|
||||
// The workitem can be re-enqueued by the drivers
|
||||
// work item handler routine. We can't set the work
|
||||
// item completed event until we are sure there are
|
||||
// no outstanding work items.
|
||||
//
|
||||
|
||||
if (m_WorkItemRunningCount == 0L && m_Enqueued == FALSE) {
|
||||
m_WorkItemCompleted.Set();
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxWorkItem::WorkItemThunk(
|
||||
__in MdDeviceObject DeviceObject,
|
||||
__in_opt PVOID Context
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the static routine called by the kernels PIO_WORKITEM handler.
|
||||
|
||||
A reference count was taken by Enqueue, which this routine releases
|
||||
on return.
|
||||
|
||||
Arguments:
|
||||
DeviceObject - the devobj we passed to IoCreateWorkItem
|
||||
|
||||
Context - the internal Fx object
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
FxWorkItem* pWorkItem;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
|
||||
pWorkItem = (FxWorkItem*)Context;
|
||||
pFxDriverGlobals = pWorkItem->GetDriverGlobals();
|
||||
|
||||
//
|
||||
// Save the current worker thread object pointer. We will use this avoid
|
||||
// deadlock if the driver tries to delete or flush the workitem from within
|
||||
// the callback.
|
||||
//
|
||||
pWorkItem->m_WorkItemThread = Mx::MxGetCurrentThread();
|
||||
|
||||
pWorkItem->WorkItemHandler();
|
||||
|
||||
pWorkItem->m_WorkItemThread = NULL;
|
||||
|
||||
//
|
||||
// Release the reference on the FxWorkItem and Globals taken when Enqueue
|
||||
// was done. This may release the FxWorkItem if it is running down.
|
||||
//
|
||||
pWorkItem->RELEASE(WorkItemThunk);
|
||||
|
||||
//
|
||||
// This may release the driver if it is running down.
|
||||
//
|
||||
pFxDriverGlobals->RELEASE(WorkItemThunk);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxWorkItem::FlushAndRundown(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
FxObject* pObject;
|
||||
|
||||
//
|
||||
// Wait for any outstanding workitem to complete if the workitem is not
|
||||
// deleted from within the workitem callback to avoid deadlock.
|
||||
//
|
||||
if (m_WorkItemThread != Mx::MxGetCurrentThread()) {
|
||||
WaitForSignal();
|
||||
}
|
||||
|
||||
//
|
||||
// Release our reference count to the associated parent object if present
|
||||
//
|
||||
if (m_Object != NULL) {
|
||||
pObject = m_Object;
|
||||
m_Object = NULL;
|
||||
|
||||
pObject->RELEASE(this);
|
||||
}
|
||||
|
||||
//
|
||||
// Perform our final release to ourselves, destroying the FxWorkItem
|
||||
//
|
||||
RELEASE(this);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxWorkItem::Dispose(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Called when DeleteObject is called, or when the parent is being deleted or
|
||||
Disposed.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
TRUE if the cleanup routines should be invoked, FALSE otherwise
|
||||
|
||||
--*/
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
Lock(&irql);
|
||||
m_RunningDown = TRUE;
|
||||
Unlock(irql);
|
||||
|
||||
FlushAndRundown();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxWorkItem::FlushAndWait()
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
if (m_WorkItemThread == Mx::MxGetCurrentThread()) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Calling WdfWorkItemFlush from within the WDFWORKITEM "
|
||||
"%p callback will lead to deadlock, PRKTHREAD %p",
|
||||
GetHandle(), m_WorkItemThread);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Wait for any outstanding workitem to complete.
|
||||
// The event is only set upon return from the callback
|
||||
// into the driver *and* the driver did not re-queue
|
||||
// the workitem. See similar comment in WorkItemHandler().
|
||||
//
|
||||
WaitForSignal();
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxWorkItem::WaitForSignal(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER timeOut;
|
||||
NTSTATUS status;
|
||||
|
||||
ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
timeOut.QuadPart = WDF_REL_TIMEOUT_IN_SEC(60);
|
||||
|
||||
do {
|
||||
status = m_WorkItemCompleted.EnterCRAndWaitAndLeave(&timeOut.QuadPart);
|
||||
if (status == STATUS_TIMEOUT) {
|
||||
DbgPrint("Thread 0x%p is waiting on WDFWORKITEM 0x%p\n",
|
||||
Mx::GetCurrentEThread(),
|
||||
GetHandle());
|
||||
}
|
||||
else {
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
break;
|
||||
}
|
||||
} WHILE(TRUE);
|
||||
|
||||
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxWorkItemApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This implements the WDFWORKITEM API's
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
#include "FxWorkItem.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxWorkItemApi.tmh"
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfWorkItemCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PWDF_WORKITEM_CONFIG Config,
|
||||
__in
|
||||
PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__out
|
||||
WDFWORKITEM* WorkItem
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Create a WorkItem object that will call the supplied function with
|
||||
context when it fires. It returns a handle to the WDFWORKITEM object.
|
||||
|
||||
Arguments:
|
||||
|
||||
Config - Pointer to WDF_WORKITEM_CONFIG structure
|
||||
|
||||
Attributes - WDF_OBJECT_ATTRIBUTES to set the parent object and to request
|
||||
a context memory allocation, and a DestroyCallback.
|
||||
|
||||
WorkItem - Pointer to the created WDFWORKITEM handle.
|
||||
|
||||
Returns:
|
||||
|
||||
STATUS_SUCCESS - A WDFWORKITEM handle has been created.
|
||||
|
||||
The WDFWORKITEM will be automatically deleted when the object it is
|
||||
associated with is deleted.
|
||||
|
||||
Notes:
|
||||
|
||||
The WDFWORKITEM object is deleted either when the DEVICE or QUEUE it is
|
||||
associated with is deleted, or WdfObjectDelete is called.
|
||||
|
||||
If the WDFWORKITEM is used to access WDM objects, a Cleanup callback should
|
||||
be registered to allow references to be released.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxObject* pParent;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
|
||||
Attributes,
|
||||
FX_VALIDATE_OPTION_PARENT_REQUIRED);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
Attributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Config);
|
||||
FxPointerNotNull(pFxDriverGlobals, WorkItem);
|
||||
|
||||
if (Config->Size != sizeof(WDF_WORKITEM_CONFIG)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDF_WORKITEM_CONFIG Size got %d, expected %d, %!STATUS!",
|
||||
Config->Size, sizeof(WDF_WORKITEM_CONFIG), status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (Config->EvtWorkItemFunc == NULL) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Supplied EvtWorkItemFunc == NULL, %!STATUS!",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// The parent for FxWorkItem is explicitly part of the API, and ties
|
||||
// synchronization and lifetime.
|
||||
//
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return FxWorkItem::_Create(
|
||||
pFxDriverGlobals, Config, Attributes, pParent, WorkItem);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfWorkItemEnqueue)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWORKITEM WorkItem
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Enqueue a WorkItem to execute.
|
||||
|
||||
Arguments:
|
||||
|
||||
WorkItem - Handle to WDFWORKITEM
|
||||
|
||||
Returns:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxWorkItem* pFxWorkItem;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WorkItem,
|
||||
FX_TYPE_WORKITEM,
|
||||
(PVOID*)&pFxWorkItem);
|
||||
|
||||
pFxWorkItem->Enqueue();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFOBJECT
|
||||
WDFEXPORT(WdfWorkItemGetParentObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWORKITEM WorkItem
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Return the Object handle supplied to WdfWorkItemCreate
|
||||
|
||||
Arguments:
|
||||
|
||||
WDFWORKITEM - Handle to WDFWORKITEM object created with WdfWorkItemCreate.
|
||||
|
||||
Returns:
|
||||
|
||||
Handle to the framework object that is the specified work-item object's
|
||||
parent object.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxWorkItem* pFxWorkItem;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WorkItem,
|
||||
FX_TYPE_WORKITEM,
|
||||
(PVOID*)&pFxWorkItem);
|
||||
|
||||
return pFxWorkItem->GetAssociatedObject();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfWorkItemFlush)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWORKITEM WorkItem
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Wait until any outstanding workitems have completed
|
||||
|
||||
Arguments:
|
||||
|
||||
WorkItem - Handle to WDFWORKITEM
|
||||
|
||||
Returns:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxWorkItem* pFxWorkItem;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
WorkItem,
|
||||
FX_TYPE_WORKITEM,
|
||||
(PVOID*)&pFxWorkItem);
|
||||
|
||||
//
|
||||
// Use the object's globals, not the caller's
|
||||
//
|
||||
if (!NT_SUCCESS(FxVerifierCheckIrqlLevel(pFxWorkItem->GetDriverGlobals(),
|
||||
PASSIVE_LEVEL))) {
|
||||
return;
|
||||
}
|
||||
|
||||
pFxWorkItem->FlushAndWait();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,959 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceApiKm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module exposes the "C" interface to the FxDevice object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "fxiotarget.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceApiKm.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
//
|
||||
// Verifier Functions
|
||||
//
|
||||
// Do not specify argument names
|
||||
FX_DECLARE_VF_FUNCTION_P3(
|
||||
VOID,
|
||||
VerifyWdfDeviceWdmDispatchIrp,
|
||||
_In_ PWDF_DRIVER_GLOBALS,
|
||||
_In_ FxDevice*,
|
||||
_In_ WDFCONTEXT
|
||||
);
|
||||
|
||||
// Do not specify argument names
|
||||
FX_DECLARE_VF_FUNCTION_P4(
|
||||
NTSTATUS,
|
||||
VerifyWdfDeviceWdmDispatchIrpToIoQueue,
|
||||
_In_ FxDevice*,
|
||||
_In_ MdIrp,
|
||||
_In_ FxIoQueue*,
|
||||
_In_ ULONG
|
||||
);
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDEVICE
|
||||
WDFEXPORT(WdfWdmDeviceGetWdfDeviceHandle)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PDEVICE_OBJECT DeviceObject
|
||||
)
|
||||
{
|
||||
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceObject);
|
||||
|
||||
return FxDevice::GetFxDevice(DeviceObject)->GetHandle();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PDEVICE_OBJECT
|
||||
WDFEXPORT(WdfDeviceWdmGetDeviceObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
{
|
||||
FxDeviceBase *pDevice;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE_BASE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
return pDevice->GetDeviceObject();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PDEVICE_OBJECT
|
||||
WDFEXPORT(WdfDeviceWdmGetAttachedDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
{
|
||||
FxDeviceBase *pDevice;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE_BASE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
return pDevice->GetAttachedDevice();
|
||||
}
|
||||
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PDEVICE_OBJECT
|
||||
WDFEXPORT(WdfDeviceWdmGetPhysicalDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
{
|
||||
FxDeviceBase *pDevice;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE_BASE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
return pDevice->GetPhysicalDevice();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFFILEOBJECT
|
||||
WDFEXPORT(WdfDeviceGetFileObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
MdFileObject FileObject
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This functions returns the WDFFILEOBJECT corresponding to the WDM fileobject.
|
||||
|
||||
Arguments:
|
||||
|
||||
Device - Handle to the device to which the WDM fileobject is related to.
|
||||
|
||||
FileObject - WDM FILE_OBJECT structure.
|
||||
|
||||
Return Value:
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxFileObject* pFxFO;
|
||||
FxDevice *pDevice;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pFxFO = NULL;
|
||||
|
||||
//
|
||||
// Validate the Device object handle, and get its FxDevice*
|
||||
//
|
||||
FxObjectHandleGetPtr(pFxDriverGlobals,
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*)&pDevice);
|
||||
|
||||
//
|
||||
// Call the static GetFileObjectFromWdm function. This will return an error if the
|
||||
// WDM fileObject is NULL and the device is not exclusive or the device is
|
||||
// configured to have a WDFFILEOBJECT for every open handle.
|
||||
//
|
||||
status = FxFileObject::_GetFileObjectFromWdm(
|
||||
pDevice,
|
||||
pDevice->GetFileObjectClass(),
|
||||
FileObject,
|
||||
&pFxFO
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"FxFileObject::_GetFileObjectFromWdm returned an error %!STATUS!",
|
||||
status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// pFxFO can be NULL if the device is configured with FileObjectClass WdfFileObjectNotRequired.
|
||||
//
|
||||
return pFxFO != NULL ? pFxFO->GetHandle() : NULL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceWdmDispatchPreprocessedIrp)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
MdIrp Irp
|
||||
)
|
||||
{
|
||||
FxDevice *device;
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &device,
|
||||
&fxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(fxDriverGlobals, Irp);
|
||||
|
||||
//
|
||||
// Verifier checks.
|
||||
// This API can only be called by the client driver, Cx must call
|
||||
// WdfDeviceWdmDispatchIrp from its preprocess callback.
|
||||
// Also, Cx must register for a Preprocessor routine using
|
||||
// WdfCxDeviceInitAssignWdmIrpPreprocessCallback.
|
||||
//
|
||||
if (fxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) {
|
||||
if (device->IsCxInIoPath()) {
|
||||
FxDriver* driver = GetFxDriverGlobals(DriverGlobals)->Driver;
|
||||
|
||||
if (IsListEmpty(&device->m_PreprocessInfoListHead) ||
|
||||
device->IsCxDriverInIoPath(driver)) {
|
||||
|
||||
DoTraceLevelMessage(
|
||||
fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
|
||||
"This API can only be called by client driver from its "
|
||||
"pre-process IRP callback, STATUS_INVALID_DEVICE_REQUEST");
|
||||
FxVerifierDbgBreakPoint(fxDriverGlobals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// OK, ready to dispatch IRP.
|
||||
//
|
||||
return device->DispatchPreprocessedIrp(
|
||||
Irp,
|
||||
device->m_PreprocessInfoListHead.Flink->Flink);
|
||||
}
|
||||
|
||||
VOID
|
||||
FX_VF_FUNCTION(VerifyWdfDeviceWdmDispatchIrp) (
|
||||
_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
_In_ PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
_In_ FxDevice* device,
|
||||
_In_ WDFCONTEXT DispatchContext
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(FxDriverGlobals);
|
||||
FxDriver* driver;
|
||||
BOOLEAN ctxValid;
|
||||
PLIST_ENTRY next;
|
||||
NTSTATUS status;
|
||||
|
||||
PAGED_CODE_LOCKED();
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
driver = GetFxDriverGlobals(DriverGlobals)->Driver;
|
||||
ctxValid = (PLIST_ENTRY)DispatchContext ==
|
||||
&device->m_PreprocessInfoListHead ? TRUE : FALSE;
|
||||
//
|
||||
// Driver should be a cx.
|
||||
//
|
||||
if (device->IsCxDriverInIoPath(driver) == FALSE) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DoTraceLevelMessage(
|
||||
device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO,
|
||||
"This API can only be called by wdf extension driver "
|
||||
"from its pre-process IRP callback, %!STATUS!",
|
||||
status);
|
||||
FxVerifierDbgBreakPoint(device->GetDriverGlobals());
|
||||
}
|
||||
|
||||
//
|
||||
// Validate DispatchContext.
|
||||
//
|
||||
|
||||
for (next = device->m_PreprocessInfoListHead.Flink;
|
||||
next != &device->m_PreprocessInfoListHead;
|
||||
next = next->Flink) {
|
||||
if ((PLIST_ENTRY)DispatchContext == next) {
|
||||
ctxValid = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FALSE == ctxValid) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO,
|
||||
"DispatchContext 0x%p is invalid, %!STATUS!",
|
||||
DispatchContext, status);
|
||||
FxVerifierDbgBreakPoint(device->GetDriverGlobals());
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceWdmDispatchIrp)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
MdIrp Irp,
|
||||
__in
|
||||
WDFCONTEXT DispatchContext
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Client driver calls this API from its dispatch callback when it decides to hand the IRP
|
||||
back to framework.
|
||||
|
||||
Cx calls this API from (a) its pre-process callback or (b) its dispatch callback when
|
||||
it decides to hand the IRP back to the framework.
|
||||
|
||||
Arguments:
|
||||
Device - WDF Device handle.
|
||||
|
||||
IRP - WDM request.
|
||||
|
||||
DispatchContext - WDF's context (input arg to callback).
|
||||
|
||||
Returns:
|
||||
IRP's status.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxDevice *device;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &device);
|
||||
|
||||
FxPointerNotNull(device->GetDriverGlobals(), Irp);
|
||||
FxPointerNotNull(device->GetDriverGlobals(), DispatchContext);
|
||||
|
||||
if ((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) {
|
||||
//
|
||||
// Called from a dispach irp callback.
|
||||
//
|
||||
DispatchContext =
|
||||
(WDFCONTEXT)((ULONG_PTR)DispatchContext & ~FX_IN_DISPATCH_CALLBACK);
|
||||
|
||||
//
|
||||
// DispatchContext is validated by DispatchStep1.
|
||||
//
|
||||
status = device->m_PkgIo->DispatchStep1(Irp, DispatchContext);
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Called from a pre-process irp callback.
|
||||
//
|
||||
|
||||
//
|
||||
// Verifier checks.
|
||||
//
|
||||
VerifyWdfDeviceWdmDispatchIrp(device->GetDriverGlobals(),
|
||||
DriverGlobals,
|
||||
device,
|
||||
DispatchContext);
|
||||
|
||||
status = device->DispatchPreprocessedIrp(Irp, DispatchContext);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
MdIrp Irp,
|
||||
__in
|
||||
WDFQUEUE Queue,
|
||||
__in
|
||||
ULONG Flags
|
||||
)
|
||||
{
|
||||
FxIoQueue *queue;
|
||||
FxDevice *device;
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
PIO_STACK_LOCATION stack;
|
||||
NTSTATUS status;
|
||||
FxIoInCallerContext* ioInCallerCtx;
|
||||
|
||||
queue = NULL;
|
||||
ioInCallerCtx = NULL;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &device);
|
||||
|
||||
fxDriverGlobals = device->GetDriverGlobals();
|
||||
FX_TRACK_DRIVER(fxDriverGlobals);
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Queue,
|
||||
FX_TYPE_QUEUE,
|
||||
(PVOID*)&queue);
|
||||
|
||||
FxPointerNotNull(fxDriverGlobals, Irp);
|
||||
|
||||
//
|
||||
// If the caller is a preprocess routine, the contract for this DDI is just like IoCallDriver.
|
||||
// The caller sets up their stack location and then the DDI advances to the next stack
|
||||
// location. This means that the caller either has to call IoSkipCurrentIrpStackLocation
|
||||
// or IoCopyCurrentIrpStackLocationToNext before calling this DDI.
|
||||
//
|
||||
if (Flags & WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP) {
|
||||
IoSetNextIrpStackLocation(Irp);
|
||||
}
|
||||
|
||||
//
|
||||
// Verifier checks.
|
||||
//
|
||||
status = VerifyWdfDeviceWdmDispatchIrpToIoQueue(fxDriverGlobals,
|
||||
device,
|
||||
Irp,
|
||||
queue,
|
||||
Flags);
|
||||
if(!NT_SUCCESS(status)) {
|
||||
Irp->IoStatus.Status = status;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Adjust stack if IRP needs to be forwarded to parent device.
|
||||
//
|
||||
if (device->m_ParentDevice == queue->GetDevice()) {
|
||||
IoCopyCurrentIrpStackLocationToNext(Irp);
|
||||
IoSetNextIrpStackLocation(Irp);
|
||||
|
||||
//
|
||||
// From now on use new device.
|
||||
//
|
||||
device = device->m_ParentDevice;
|
||||
|
||||
//
|
||||
// Save a pointer to the device object for this request so that it can
|
||||
// be used later in completion.
|
||||
//
|
||||
stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
stack->DeviceObject = device->GetDeviceObject();
|
||||
}
|
||||
|
||||
//
|
||||
// Get in-context caller callback if required.
|
||||
//
|
||||
if (Flags & WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK) {
|
||||
ioInCallerCtx = device->m_PkgIo->GetIoInCallerContextCallback(
|
||||
queue->GetCxDeviceInfo());
|
||||
}
|
||||
|
||||
//
|
||||
// DispatchStep2 will convert the IRP into a WDFREQUEST, queue it and if
|
||||
// possible dispatch the request to the driver.
|
||||
//
|
||||
return device->m_PkgIo->DispatchStep2(Irp, ioInCallerCtx, queue);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceAddDependentUsageDeviceObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PDEVICE_OBJECT DependentDevice
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice *pDevice;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID *) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, DependentDevice);
|
||||
|
||||
return pDevice->m_PkgPnp->AddUsageDevice(DependentDevice);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfDeviceRemoveDependentUsageDeviceObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PDEVICE_OBJECT DependentDevice
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice *pDevice;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID *) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, DependentDevice);
|
||||
|
||||
return pDevice->m_PkgPnp->RemoveUsageDevice(DependentDevice);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceAssignMofResourceName)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PCUNICODE_STRING MofResourceName
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice *pDevice;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID *) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, MofResourceName);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateUnicodeString(pFxDriverGlobals, MofResourceName);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pDevice->m_MofResourceName.Buffer != NULL) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p MofResourceName already assigned, %!STATUS!",
|
||||
Device, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxDuplicateUnicodeString(pFxDriverGlobals,
|
||||
MofResourceName,
|
||||
&pDevice->m_MofResourceName);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE %p couldn't creat duplicate buffer, %!STATUS!",
|
||||
Device, status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfDeviceSetSpecialFileSupport)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
WDF_SPECIAL_FILE_TYPE FileType,
|
||||
__in
|
||||
BOOLEAN Supported
|
||||
)
|
||||
{
|
||||
FxDevice* pDevice;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID *) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
if (FileType < WdfSpecialFilePaging || FileType >= WdfSpecialFileMax) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p FileType %d specified is not in valid range",
|
||||
Device, FileType);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtr(pFxDriverGlobals,
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
pDevice->m_PkgPnp->SetSpecialFileSupport(FileType, Supported);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceIndicateWakeStatus)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
NTSTATUS WaitWakeStatus
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
FxDevice *pDevice;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID *) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
if (Device == NULL ||
|
||||
WaitWakeStatus == STATUS_PENDING || WaitWakeStatus == STATUS_CANCELLED) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"NULL WDFDEVICE handle %p or invalid %!STATUS!",
|
||||
Device, WaitWakeStatus);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (pDevice->m_PkgPnp->m_SharedPower.m_WaitWakeOwner) {
|
||||
if (pDevice->m_PkgPnp->PowerIndicateWaitWakeStatus(WaitWakeStatus)) {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// There was no request to complete
|
||||
//
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p No request to complete"
|
||||
" STATUS_INVALID_DEVICE_REQUEST",
|
||||
Device);
|
||||
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// We cannot complete what we do not own
|
||||
//
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p Not the waitwake owner"
|
||||
" STATUS_INVALID_DEVICE_STATE",
|
||||
Device);
|
||||
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfDeviceSetBusInformationForChildren)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PPNP_BUS_INFORMATION BusInformation
|
||||
)
|
||||
{
|
||||
FxDevice* pDevice;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
FxPointerNotNull(pDevice->GetDriverGlobals(), BusInformation);
|
||||
|
||||
pDevice->m_PkgPnp->SetChildBusInformation(BusInformation);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceAddRemovalRelationsPhysicalDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PDEVICE_OBJECT PhysicalDevice
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Registers a PDO from another non descendant (not verifiable though) pnp
|
||||
stack to be reported as also requiring removal when this PDO is removed.
|
||||
|
||||
The PDO could be another device enumerated by this driver.
|
||||
|
||||
Arguments:
|
||||
Device - this driver's PDO
|
||||
|
||||
PhysicalDevice - PDO for another stack
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
FxDevice* pDevice;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
FxPointerNotNull(pDevice->GetDriverGlobals(), PhysicalDevice);
|
||||
|
||||
return pDevice->m_PkgPnp->AddRemovalDevice(PhysicalDevice);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfDeviceRemoveRemovalRelationsPhysicalDevice)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PDEVICE_OBJECT PhysicalDevice
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Deregisters a PDO from another non descendant (not verifiable though) pnp
|
||||
stack to not be reported as also requiring removal when this PDO is removed.
|
||||
|
||||
The PDO could be another device enumerated by this driver.
|
||||
|
||||
Arguments:
|
||||
Device - this driver's PDO
|
||||
|
||||
PhysicalDevice - PDO for another stack
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
FxDevice* pDevice;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
FxPointerNotNull(pDevice->GetDriverGlobals(), PhysicalDevice);
|
||||
|
||||
pDevice->m_PkgPnp->RemoveRemovalDevice(PhysicalDevice);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfDeviceClearRemovalRelationsDevices)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Deregisters all PDOs to not be reported as also requiring removal when this
|
||||
PDO is removed.
|
||||
|
||||
Arguments:
|
||||
Device - this driver's PDO
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
FxDevice* pDevice;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice);
|
||||
|
||||
pDevice->m_PkgPnp->ClearRemovalDevicesList();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceWdmAssignPowerFrameworkSettings)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
The DDI is invoked by KMDF client drivers for single-component devices to
|
||||
specify their power framework settings to KMDF. KMDF uses these settings on
|
||||
Win8+ when registering with the power framework.
|
||||
|
||||
On Win7 and older operating systems the power framework is not available, so
|
||||
KMDF does nothing.
|
||||
|
||||
Arguments:
|
||||
|
||||
Device - Handle to the framework device object for which power framework
|
||||
settings are being specified.
|
||||
|
||||
PowerFrameworkSettings - Pointer to a WDF_POWER_FRAMEWORK_SETTINGS structure
|
||||
that contains the client driver's power framework settings.
|
||||
|
||||
Return Value:
|
||||
An NTSTATUS value that denotes success or failure of the DDI
|
||||
|
||||
--*/
|
||||
{
|
||||
NTSTATUS status;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice *pDevice;
|
||||
|
||||
//
|
||||
// Validate the Device object handle and get its FxDevice. Also get the
|
||||
// driver globals pointer.
|
||||
//
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID *) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, PowerFrameworkSettings);
|
||||
|
||||
//
|
||||
// Only power policy owners should call this DDI
|
||||
//
|
||||
if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p is not the power policy owner, so the caller cannot"
|
||||
" assign power framework settings %!STATUS!", Device, status);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate the Settings parameter
|
||||
//
|
||||
if (PowerFrameworkSettings->Size != sizeof(WDF_POWER_FRAMEWORK_SETTINGS)) {
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p Expected PowerFrameworkSettings size %d, actual %d,"
|
||||
" %!STATUS!",
|
||||
Device,
|
||||
sizeof(WDF_POWER_FRAMEWORK_SETTINGS),
|
||||
PowerFrameworkSettings->Size,
|
||||
status);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// If settings for component 0 are specified, make sure it contains at least
|
||||
// one F-state.
|
||||
//
|
||||
if (NULL != PowerFrameworkSettings->Component) {
|
||||
|
||||
if (0 == PowerFrameworkSettings->Component->IdleStateCount) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p Component settings are specified but "
|
||||
"IdleStateCount is 0. %!STATUS!", Device, status);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (NULL == PowerFrameworkSettings->Component->IdleStates) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"WDFDEVICE 0x%p Component settings are specified but IdleStates"
|
||||
" is NULL. %!STATUS!", Device, status);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Assign the driver's settings
|
||||
//
|
||||
status = pDevice->m_PkgPnp->AssignPowerFrameworkSettings(
|
||||
PowerFrameworkSettings);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,101 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceBaseKm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the class implementation for the base device class.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceBaseKm.tmh"
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceBase::QueryForInterface(
|
||||
__in const GUID* InterfaceType,
|
||||
__out PINTERFACE Interface,
|
||||
__in USHORT Size,
|
||||
__in USHORT Version,
|
||||
__in PVOID InterfaceSpecificData,
|
||||
__in_opt MdDeviceObject TargetDevice
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Send an IRP_MJPNP/IRP_MN_QUERY_INTERFACE irp to a device object and its
|
||||
attached stack.
|
||||
|
||||
Arguments:
|
||||
InterfaceType - The type of interface to query for
|
||||
|
||||
Interface - The interface to fill out
|
||||
|
||||
Size - Size of Interface in bytes
|
||||
|
||||
Version - Version of the interface to be queried
|
||||
|
||||
InterfaceSpecificData - Addtional interface data to be queried
|
||||
|
||||
TargetDevice - device in the stack to send the query to. If NULL, the top
|
||||
of the stack will receive the query.
|
||||
|
||||
Return Value:
|
||||
NTSTATUS as indicated by the handler of the QI with in the device stack,
|
||||
STATUS_NOT_SUPPORTED if the QI is not handled.
|
||||
|
||||
--*/
|
||||
{
|
||||
PDEVICE_OBJECT pTopOfStack;
|
||||
NTSTATUS status;
|
||||
|
||||
//
|
||||
// PnP rules dictate you send the QI through the entire stack and not just
|
||||
// the stack below you...but we let the caller override this. There are
|
||||
// some stacks which are not PnP reentrant, so sending a QI from a lower
|
||||
// filter might cause the stack to stop responding if the FDO is synchronously
|
||||
// sending a PnP irp down the stack already.
|
||||
//
|
||||
if (TargetDevice == NULL) {
|
||||
pTopOfStack = GetAttachedDeviceReference();
|
||||
}
|
||||
else {
|
||||
//
|
||||
// To make the exit logic simpler below, just add our own reference.
|
||||
//
|
||||
Mx::MxReferenceObject(TargetDevice);
|
||||
pTopOfStack = TargetDevice;
|
||||
}
|
||||
|
||||
status = FxQueryInterface::_QueryForInterface(
|
||||
pTopOfStack,
|
||||
InterfaceType,
|
||||
Interface,
|
||||
Size,
|
||||
Version,
|
||||
InterfaceSpecificData
|
||||
);
|
||||
|
||||
Mx::MxDereferenceObject(pTopOfStack);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceInitKm.cpp
|
||||
|
||||
Abstract:
|
||||
Internals for WDFDEVICE_INIT
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceInitKm.tmh"
|
||||
}
|
||||
|
||||
VOID
|
||||
WDFDEVICE_INIT::SetPdo(
|
||||
__in FxDevice* Parent
|
||||
)
|
||||
{
|
||||
InitType = FxDeviceInitTypePdo;
|
||||
|
||||
//
|
||||
// Remember the parent so we can store it later in WdfDeviceCreate
|
||||
//
|
||||
Pdo.Parent = Parent;
|
||||
|
||||
//
|
||||
// PDOs *must* have a name. By setting this flag, the driver writer
|
||||
// does not need to know this
|
||||
//
|
||||
Characteristics |= FILE_AUTOGENERATED_DEVICE_NAME;
|
||||
|
||||
//
|
||||
// By default, PDOs are not power pageable b/c they do not know how the
|
||||
// stack above them will work. For a "closed" system where the bus driver
|
||||
// knows the stack be loaded on its PDO, this may not be true and it
|
||||
// can use WdfDeviceInitSetPowerPageable to set it back.
|
||||
//
|
||||
// In all current shipping OS's, if the parent is power pageable, the
|
||||
// child must be power pagable as well.
|
||||
//
|
||||
if (Parent->IsPowerPageableCapable() == FALSE) {
|
||||
PowerPageable = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
WDFDEVICE_INIT::AssignIoType(
|
||||
_In_ PWDF_IO_TYPE_CONFIG IoTypeConfig
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
if (IoTypeConfig->ReadWriteIoType == WdfDeviceIoUndefined ||
|
||||
IoTypeConfig->ReadWriteIoType > WdfDeviceIoDirect) {
|
||||
status= STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(
|
||||
DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Out of range Read/Write IoType %d, %!status!",
|
||||
IoTypeConfig->ReadWriteIoType, status);
|
||||
FxVerifierDbgBreakPoint(DriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
ReadWriteIoType = IoTypeConfig->ReadWriteIoType;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,263 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDriverApiKm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains the "C" interface for the FxDriver object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include <ntverp.h>
|
||||
#include "FxDriverApiKm.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// extern the whole file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDriverOpenParametersRegistryKey)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDRIVER Driver,
|
||||
__in
|
||||
ACCESS_MASK DesiredAccess,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES KeyAttributes,
|
||||
__out
|
||||
WDFKEY* Key
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxDriver* pDriver;
|
||||
FxRegKey* pKey;
|
||||
FxAutoRegKey hKey;
|
||||
WDFKEY keyHandle;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Key);
|
||||
|
||||
*Key = NULL;
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtr(pFxDriverGlobals,
|
||||
Driver,
|
||||
FX_TYPE_DRIVER,
|
||||
(PVOID*) &pDriver);
|
||||
|
||||
pKey = new(pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals);
|
||||
|
||||
if (pKey == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Static worker function (no object assignment for opened handled)
|
||||
//
|
||||
status = FxRegKey::_OpenKey(
|
||||
NULL, pDriver->GetRegistryPathUnicodeString(), &hKey.m_Key);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
DECLARE_CONST_UNICODE_STRING(parameters, L"Parameters");
|
||||
|
||||
//
|
||||
// This will store the resulting handle in pKey
|
||||
//
|
||||
status = pKey->Create(hKey.m_Key, ¶meters, DesiredAccess);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*Key = keyHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pKey->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PDRIVER_OBJECT
|
||||
WDFEXPORT(WdfDriverWdmGetDriverObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDRIVER Driver
|
||||
)
|
||||
{
|
||||
FxDriver *pDriver;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Driver,
|
||||
FX_TYPE_DRIVER,
|
||||
(PVOID*) &pDriver);
|
||||
|
||||
return pDriver->GetDriverObject();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFDRIVER
|
||||
WDFEXPORT(WdfWdmDriverGetWdfDriverHandle)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
PDRIVER_OBJECT DriverObject
|
||||
)
|
||||
{
|
||||
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DriverObject);
|
||||
|
||||
return FxDriver::GetFxDriver(DriverObject)->GetHandle();
|
||||
}
|
||||
|
||||
VOID
|
||||
WDFEXPORT(WdfDriverMiniportUnload)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDRIVER Driver
|
||||
)
|
||||
{
|
||||
FxDriver *pDriver;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Driver,
|
||||
FX_TYPE_DRIVER,
|
||||
(PVOID *)&pDriver);
|
||||
|
||||
FxDriver::Unload(pDriver->GetDriverObject());
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceMiniportCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDRIVER Driver,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
__in_opt
|
||||
PDEVICE_OBJECT AttachedDeviceObject,
|
||||
__in_opt
|
||||
PDEVICE_OBJECT Pdo,
|
||||
__out
|
||||
WDFDEVICE* Device
|
||||
)
|
||||
{
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDriver* pDriver;
|
||||
FxMpDevice* pMpDevice;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Driver,
|
||||
FX_TYPE_DRIVER,
|
||||
(PVOID *)&pDriver,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, DeviceObject);
|
||||
|
||||
if (AttachedDeviceObject == NULL && Pdo != NULL) {
|
||||
FxPointerNotNull(pFxDriverGlobals, AttachedDeviceObject);
|
||||
}
|
||||
else if (AttachedDeviceObject != NULL && Pdo == NULL) {
|
||||
FxPointerNotNull(pFxDriverGlobals, Pdo);
|
||||
}
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
pMpDevice = new(pFxDriverGlobals, Attributes)
|
||||
FxMpDevice(pFxDriverGlobals,
|
||||
pDriver,
|
||||
DeviceObject,
|
||||
AttachedDeviceObject,
|
||||
Pdo);
|
||||
|
||||
if (pMpDevice == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (AttachedDeviceObject != NULL) {
|
||||
status = pMpDevice->AllocateTarget(&pMpDevice->m_DefaultTarget,
|
||||
FALSE /*SelfTarget=FALSE*/);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
status = FxDisposeList::_Create(pFxDriverGlobals,
|
||||
pMpDevice->GetDeviceObject(),
|
||||
&pMpDevice->m_DisposeList);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = pMpDevice->ConfigureConstraints(Attributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = pMpDevice->Commit(Attributes, (PVOID*)Device);
|
||||
if (!NT_SUCCESS(status)) { // follow the same error pattern as above.
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pMpDevice->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,170 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDriverKm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the main driver framework.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "fxiotarget.hpp"
|
||||
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxDriverKm.tmh"
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDriver::AddDevice(
|
||||
__in MdDriverObject DriverObject,
|
||||
__in MdDeviceObject PhysicalDeviceObject
|
||||
)
|
||||
{
|
||||
FxDriver *pDriver;
|
||||
|
||||
pDriver = FxDriver::GetFxDriver(DriverObject);
|
||||
|
||||
if (pDriver != NULL) {
|
||||
return pDriver->AddDevice(PhysicalDeviceObject);
|
||||
}
|
||||
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDriver::AddDevice(
|
||||
_In_ MdDeviceObject PhysicalDeviceObject
|
||||
)
|
||||
{
|
||||
WDFDEVICE_INIT init(this);
|
||||
FxDevice* pDevice;
|
||||
NTSTATUS status;
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Enter AddDevice PDO %p", PhysicalDeviceObject);
|
||||
|
||||
pDevice = NULL;
|
||||
init.CreatedOnStack = TRUE;
|
||||
|
||||
init.InitType = FxDeviceInitTypeFdo;
|
||||
init.Fdo.PhysicalDevice = PhysicalDeviceObject;
|
||||
|
||||
status = m_DriverDeviceAdd.Invoke(GetHandle(), &init);
|
||||
|
||||
//
|
||||
// Caller returned w/out creating a device, we are done. Returning
|
||||
// STATUS_SUCCESS w/out creating a device and attaching to the stack is OK,
|
||||
// especially for filter drivers which selectively attach to devices.
|
||||
//
|
||||
if (init.CreatedDevice == NULL) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
|
||||
"Driver did not create a device in "
|
||||
"EvtDriverAddDevice, status %!STATUS!", status);
|
||||
|
||||
//
|
||||
// We do not let filters affect the building of the rest of the stack.
|
||||
// If they return error, we convert it to STATUS_SUCCESS.
|
||||
//
|
||||
if (init.Fdo.Filter && !NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
|
||||
"Filter returned %!STATUS! without creating a WDFDEVICE, "
|
||||
"converting to STATUS_SUCCESS", status);
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
pDevice = init.CreatedDevice;
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Make sure that DO_DEVICE_INITIALIZING is cleared.
|
||||
// FxDevice::FdoInitialize does not do this b/c the driver writer may
|
||||
// want the bit set until sometime after WdfDeviceCreate returns
|
||||
//
|
||||
pDevice->FinishInitializing();
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Created a device, but returned error.
|
||||
//
|
||||
ASSERT(pDevice->IsPnp());
|
||||
ASSERT(pDevice->m_CurrentPnpState == WdfDevStatePnpInit);
|
||||
|
||||
status = pDevice->DeleteDeviceFromFailedCreate(status, TRUE);
|
||||
pDevice = NULL;
|
||||
}
|
||||
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
|
||||
"Exit, status %!STATUS!", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDriver::AllocateDriverObjectExtensionAndStoreFxDriver(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
FxDriver** ppDriver;
|
||||
|
||||
//
|
||||
// Prefast is much happier if we take the size of the type rather then
|
||||
// the size of the variable.
|
||||
//
|
||||
status = Mx::MxAllocateDriverObjectExtension( m_DriverObject.GetObject(),
|
||||
FX_DRIVER_ID,
|
||||
sizeof(FxDriver**),
|
||||
(PVOID*)&ppDriver);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// If we succeeded in creating the driver object extension,
|
||||
// then store our FxDriver pointer in the DriverObjectExtension.
|
||||
//
|
||||
*ppDriver = this;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
FxDriver*
|
||||
FxDriver::GetFxDriver(
|
||||
__in MdDriverObject DriverObject
|
||||
)
|
||||
{
|
||||
FxDriver* objExt;
|
||||
objExt = *(FxDriver **)Mx::MxGetDriverObjectExtension(DriverObject,
|
||||
FX_DRIVER_ID);
|
||||
ASSERT(objExt != NULL);
|
||||
|
||||
return objExt;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxFileObjectApiUm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This modules implements the C API's for the FxFileObject.
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel Mode mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "coreprivshared.hpp"
|
||||
#include "FxFileObject.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxFileObjectApiKm.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
PFILE_OBJECT
|
||||
WDFEXPORT(WdfFileObjectWdmGetFileObject)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFFILEOBJECT FileObject
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This functions returns the corresponding WDM fileobject. If the device is opened
|
||||
by a kernel-mode componenet by sending a IRP_MJ_CREATE irp
|
||||
directly without a fileobject, this call can return a NULL pointer.
|
||||
|
||||
Creating a WDFFILEOBJECT without an underlying WDM fileobject
|
||||
is done only for 'exclusive' devices.
|
||||
|
||||
Serenum sends such a create-irp to the serial driver.
|
||||
|
||||
Arguments:
|
||||
|
||||
FileObject - WDFFILEOBJECT
|
||||
|
||||
Return Value:
|
||||
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxFileObject* pFO;
|
||||
|
||||
//
|
||||
// Validate the FileObject object handle, and get its FxFileObject*
|
||||
//
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
FileObject,
|
||||
FX_TYPE_FILEOBJECT,
|
||||
(PVOID*)&pFO);
|
||||
|
||||
return pFO->GetWdmFileObject();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user