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