[WDF] Add Windows Driver Framework files

Takern from Microsoft GitHub repo:
d9c6040fe9

Licensed under MIT
This commit is contained in:
Victor Perevertkin 2020-09-24 23:51:15 +03:00
parent 545df81502
commit 8a978a179f
No known key found for this signature in database
GPG key ID: C750B7222E9C7830
475 changed files with 285099 additions and 0 deletions

View file

@ -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

View file

@ -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__

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"
}

View file

@ -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__

View file

@ -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__

View file

@ -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

View file

@ -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

View file

@ -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

View 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__

View file

@ -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(&params))) {
//
// 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"

View file

@ -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"

View file

@ -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);
}

View file

@ -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"

View file

@ -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();
}

View file

@ -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)&parametersPath,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
service.m_Key,
NULL);
status = ZwOpenKey(&parameters.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;
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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(&parametersPath, 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,
&parametersPath,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
driverKey,
NULL);
//
// Open or create key and get a handle
//
status = ZwCreateKey(&parametersKey,
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(&parametersPath, 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,
&parametersPath,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
driverKey,
NULL);
//
// Open the key for deletion
//
status = ZwOpenKey(&parametersKey,
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;
}

View file

@ -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"

View file

@ -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__

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -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__

View file

@ -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;
}

View file

@ -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,
&parametersPath,
&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;
}

View file

@ -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));
}

View file

@ -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"

View file

@ -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);
}

View file

@ -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++;
}
}

View file

@ -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__

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View 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

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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"

View file

@ -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);
}

View file

@ -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"

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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"

View file

@ -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));
}

View file

@ -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"

View file

@ -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
);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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"

View file

@ -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;
}

View file

@ -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

View file

@ -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(&params.IoStatus);
RtlZeroMemory(&params.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(),
&params,
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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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"

View file

@ -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;
}

View file

@ -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"

View file

@ -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"

View file

@ -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;
}

View file

@ -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

View file

@ -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, &parameters, 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"

View file

@ -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;
}

View file

@ -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