[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,130 @@
/*++
Copyright (c) Microsoft Corporation
ModuleName:
DbgTrace.cpp
Abstract:
Temporary file to be used until ETW can be used
for UM
Author:
Revision History:
--*/
#include "fxobjectpch.hpp"
#if FX_CORE_MODE==FX_CORE_USER_MODE
#include "strsafe.h"
#endif
#if !defined(EVENT_TRACING)
VOID
__cdecl
DoTraceLevelMessage(
__in PVOID FxDriverGlobals,
__in ULONG DebugPrintLevel,
__in ULONG DebugPrintFlag,
__drv_formatString(FormatMessage)
__in PCSTR DebugMessage,
...
)
/*++
Routine Description:
Print the trace message to debugger.
Arguments:
TraceEventsLevel - print level between 0 and 3, with 3 the most verbose
Return Value:
None.
--*/
{
#if DBG
UNREFERENCED_PARAMETER(FxDriverGlobals);
#define TEMP_BUFFER_SIZE 1024
va_list list;
CHAR debugMessageBuffer[TEMP_BUFFER_SIZE];
NTSTATUS status;
va_start(list, DebugMessage);
if (DebugMessage) {
//
// Using new safe string functions instead of _vsnprintf.
// This function takes care of NULL terminating if the message
// is longer than the buffer.
//
#if FX_CORE_MODE==FX_CORE_KERNEL_MODE
status = RtlStringCbVPrintfA( debugMessageBuffer,
sizeof(debugMessageBuffer),
DebugMessage,
list );
#else
HRESULT hr;
hr = StringCbVPrintfA( debugMessageBuffer,
sizeof(debugMessageBuffer),
DebugMessage,
list );
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
{
status = WinErrorToNtStatus(HRESULT_CODE(hr));
}
else
{
status = SUCCEEDED(hr) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
#endif
if(!NT_SUCCESS(status)) {
#if FX_CORE_MODE==FX_CORE_KERNEL_MODE
DbgPrint ("WDFTrace: RtlStringCbVPrintfA failed 0x%x\n", status);
#else
OutputDebugString("WDFTrace: Unable to expand: ");
OutputDebugString(DebugMessage);
#endif
return;
}
if (DebugPrintLevel <= TRACE_LEVEL_ERROR ||
(DebugPrintLevel <= DebugLevel &&
((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) {
#if FX_CORE_MODE==FX_CORE_KERNEL_MODE
DbgPrint("WDFTrace: %s", debugMessageBuffer);
#else
OutputDebugString("WDFTrace: ");
OutputDebugString(DebugMessage);
#endif
}
}
va_end(list);
return;
#else
UNREFERENCED_PARAMETER(FxDriverGlobals);
UNREFERENCED_PARAMETER(DebugPrintLevel);
UNREFERENCED_PARAMETER(DebugPrintFlag);
UNREFERENCED_PARAMETER(DebugMessage);
#endif
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,383 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxObjectApi.cpp
Abstract:
Author:
Environment:
kernel mode only
Revision History:
--*/
#include "fxobjectpch.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "FxObjectAPI.tmh"
#endif
}
extern "C" {
__drv_maxIRQL(DISPATCH_LEVEL)
WDFAPI
VOID
WDFEXPORT(WdfObjectReferenceActual)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFOBJECT Object,
__in_opt
PVOID Tag,
__in
LONG Line,
__in
PSTR File
)
/*++
Routine Description:
Adds an explicit reference that was taken on an object.
Arguments:
Object - the object to reference
Tag - The tag used to track this reference. If not matched on dereference,
a breakpoint is hit. Tags are only tracked when enabled via the
registry or WDF verifier.
Line - the caller's line number making the call
File - the caller's file name making the call
Return Value:
None. We do not return the current reference count.
--*/
{
DDI_ENTRY();
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Object);
FxObject::_ReferenceActual(
Object,
Tag,
Line,
File
);
}
__drv_maxIRQL(DISPATCH_LEVEL)
WDFAPI
VOID
WDFEXPORT(WdfObjectDereferenceActual)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFOBJECT Object,
__in_opt
PVOID Tag,
__in
LONG Line,
__in
PSTR File
)
/*++
Routine Description:
Removes an explicit reference that was taken on an object.
Arguments:
Object - the object to dereference
Tag - The tag used when referencing the Object, if not matched, a breakpoint
is hit. Tags are only tracked when enabled via the registry or
WDF verifier.
Line - the caller's line number making the call
File - the caller's file name making the call
Return Value:
None. We do not return the current reference count.
--*/
{
DDI_ENTRY();
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Object);
FxObject::_DereferenceActual(
Object,
Tag,
Line,
File
);
}
FxCallbackLock*
FxGetCallbackLock(
FxObject* Object
)
/*++
Routine Description:
This returns the proper FxCallbackLock pointer
for the object.
It returns NULL if an FxCallbackLock is not valid
for the object.
Arguments:
Object - Pointer to object to retrieve the callback lock pointer for
Returns:
FxCallbackLock*
--*/
{
NTSTATUS status;
IFxHasCallbacks* ihcb;
FxQueryInterfaceParams params = { (PVOID*) &ihcb, FX_TYPE_IHASCALLBACKS, 0 };
ihcb = NULL;
//
// Query the object for the IFxHasCallbacks interface. Objects that
// have callback locks must support this interface.
//
status = Object->QueryInterface(&params);
if (!NT_SUCCESS(status)) {
return NULL;
}
return ihcb->GetCallbackLockPtr(NULL);
}
__drv_maxIRQL(DISPATCH_LEVEL)
WDFAPI
VOID
WDFEXPORT(WdfObjectAcquireLock)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
_Requires_lock_not_held_(_Curr_)
_Acquires_lock_(_Curr_)
WDFOBJECT Object
)
{
DDI_ENTRY();
FxObject* pObject;
FxCallbackLock* pLock;
PFX_DRIVER_GLOBALS pFxDriverGlobals;
KIRQL irql;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
Object,
FX_TYPE_OBJECT,
(PVOID*)&pObject,
&pFxDriverGlobals);
//
// If Lock Verifier on, validate whether its correct to
// make this call
//
if (pFxDriverGlobals->FxVerifierLock) {
//
// Check IRQL Level, etc.
//
}
//
// Get the CallbackLock for the object
//
pLock = FxGetCallbackLock(pObject);
if (pLock == NULL) {
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Invalid to call on WDFOBJECT 0x%p", Object);
FxVerifierDbgBreakPoint(pFxDriverGlobals);
FxVerifierBugCheck(pFxDriverGlobals,
WDF_INVALID_LOCK_OPERATION,
(ULONG_PTR)Object,
(ULONG_PTR)NULL
);
return;
}
pLock->Lock(&irql);
pLock->m_PreviousIrql = irql;
return;
}
__drv_maxIRQL(DISPATCH_LEVEL)
WDFAPI
VOID
WDFEXPORT(WdfObjectReleaseLock)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
_Requires_lock_held_(_Curr_)
_Releases_lock_(_Curr_)
WDFOBJECT Object
)
{
DDI_ENTRY();
PFX_DRIVER_GLOBALS pFxDriverGlobals;
FxObject* pObject;
FxCallbackLock* pLock;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
Object,
FX_TYPE_OBJECT,
(PVOID*)&pObject,
&pFxDriverGlobals);
//
// If Lock Verifier on, validate whether its correct to
// make this call
//
if (pFxDriverGlobals->FxVerifierLock) {
//
// Check IRQL Level, etc.
//
}
//
// Get the CallbackLock for the object
//
pLock = FxGetCallbackLock(pObject);
if (pLock == NULL) {
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Invalid to call on WDFOBJECT 0x%p",Object);
FxVerifierDbgBreakPoint(pFxDriverGlobals);
FxVerifierBugCheck(pFxDriverGlobals,
WDF_INVALID_LOCK_OPERATION,
(ULONG_PTR)Object,
(ULONG_PTR)NULL
);
return;
}
pLock->Unlock(pLock->m_PreviousIrql);
return;
}
__drv_maxIRQL(DISPATCH_LEVEL)
WDFAPI
VOID
WDFEXPORT(WdfObjectDelete)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFOBJECT Object
)
{
DDI_ENTRY();
PFX_DRIVER_GLOBALS pFxDriverGlobals;
FxObject* pObject;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
Object,
FX_TYPE_OBJECT,
(PVOID*)&pObject,
&pFxDriverGlobals);
//
// The object may not allow the Delete DDI
//
if (pObject->IsNoDeleteDDI()) {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Attempt to Delete an Object Which does not allow WdfDeleteObject "
"Handle 0x%p, %!STATUS!",
Object, STATUS_CANNOT_DELETE);
FxVerifierDbgBreakPoint(pFxDriverGlobals);
}
else {
pObject->DeleteObject();
}
}
_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
WDFAPI
NTSTATUS
WDFEXPORT(WdfObjectQuery)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFOBJECT Object,
__in
CONST GUID* Guid,
__in
ULONG QueryBufferLength,
__out_bcount(QueryBufferLength)
PVOID QueryBuffer
)
/*++
Routine Description:
Query the object handle for specific information
This allows dynamic extensions to DDI's.
Currently, it is used to allow test hooks for verification
which are not available in a production release.
Arguments:
Object - Handle to object for the query
Guid - GUID to represent the information/DDI to query for
QueryBufferLength - Length of QueryBuffer to return data in
QueryBuffer - Pointer to QueryBuffer
Returns:
NTSTATUS
--*/
{
DDI_ENTRY();
FxObject* p;
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
Object,
FX_TYPE_OBJECT,
(PVOID*)&p);
return FxObject::_ObjectQuery(p,
Guid,
QueryBufferLength,
QueryBuffer);
}
} // extern "C" for all functions

View file

@ -0,0 +1,30 @@
/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
fxobjectpch.h
Abstract:
This module contains header definitions and include files needed by all
modules in shared\object
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#ifndef __FX_CORE_PCH_H__
#define __FX_CORE_PCH_H__
#include "objectpriv.hpp"
#include "fxmin.hpp"
#include "FxToObjectItf.hpp"
#endif // __FX_CORE_PCH_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,382 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxTagTracker.cpp
Abstract:
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxobjectpch.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "fxtagtracker.tmh"
#endif
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
//
// rtlsupportapi.h causes problems in AMD64 and ARM builds.
//
extern
_Success_(return != 0)
USHORT
RtlCaptureStackBackTrace(
_In_ ULONG FramesToSkip,
_In_ ULONG FramesToCapture,
_Out_writes_to_(FramesToCapture, return) PVOID * BackTrace,
_Out_opt_ PULONG BackTraceHash
);
#endif
}
FxTagTracker::~FxTagTracker()
/*++
Routine Description:
Destructor for this object. Will verify that the object is being freed
without any outstanding tags.
Arguments:
None
Return Value:
None
--*/
{
KIRQL irql;
FxTagTrackingBlock *current, *next;
if (m_TrackerType == FxTagTrackerTypeHandle) {
FxDriverGlobalsDebugExtension* pExtension;
CheckForAbandondedTags();
pExtension = GetDriverGlobals()->DebugExtension;
//
// Remove this tracker from the list of allocated trackers
//
pExtension->AllocatedTagTrackersLock.Acquire(&irql);
RemoveEntryList(&m_TrackerEntry);
pExtension->AllocatedTagTrackersLock.Release(irql);
} else {
ASSERT(m_TrackerType == FxTagTrackerTypePower);
}
//
// Delete any outstanding tracking blocks.
//
m_SpinLock.Acquire(&irql);
current = m_Next;
m_Next = NULL;
while (current != NULL) {
next = current->Next;
delete current;
current = next;
}
m_SpinLock.Release(irql);
}
VOID
FxTagTracker::CopyStackFrames(
_Inout_ FxTagTrackingStackFrames** StackFrames,
_In_ USHORT NumFrames,
_In_reads_(NumFrames) PVOID* Frames
)
{
PFX_DRIVER_GLOBALS pFxDriverGlobals;
FxTagTrackingStackFrames* stackFrames;
//
// FxTagHistory structs are stored in a circular buffer and reused,
// so we also reuse the FxTagTrackingStackFrames that each allocates.
//
stackFrames = *StackFrames;
if (stackFrames == NULL) {
pFxDriverGlobals = GetDriverGlobals();
stackFrames = new(pFxDriverGlobals) FxTagTrackingStackFrames;
if (stackFrames == NULL) {
return;
}
*StackFrames = stackFrames;
}
stackFrames->NumFrames = NumFrames;
for (int i = 0; i < NumFrames; i++) {
stackFrames->Frames[i] = (ULONG64)Frames[i];
}
}
VOID
FxTagTracker::UpdateTagHistory(
__in PVOID Tag,
__in LONG Line,
__in_opt PSTR File,
__in FxTagRefType RefType,
__in ULONG RefCount
)
/*++
Routine Description:
Update tag history and either create or free an existing tag tracking block.
Arguments:
Tag - Unique tag associated with the reference
Line - Line where the reference is referenced/released
File - Buffer containing the file name
RefType - Enumerated type ( AddRef or Release )
RefCount - Approximate current reference count (see FxTagHistory.RefCount comment)
Return Value:
VOID
--*/
{
PFX_DRIVER_GLOBALS pFxDriverGlobals;
FxTagHistory* pTagHistory;
FxTagTrackingBlock* pBlock;
LONG pos;
KIRQL irql;
USHORT numFrames = 0;
PVOID frames[FRAMES_TO_CAPTURE];
pFxDriverGlobals = GetDriverGlobals();
pos = InterlockedIncrement(&m_CurRefHistory) - 1;
pos %= TAG_HISTORY_DEPTH;
//
// Prefast reports that m_CurRefHistory can be negative which can lead to
// underflow. But we know that m_CurRefHistory would never be negative.
// Hence we assert for the condition below and assume that it would be true.
//
FX_ASSERT_AND_ASSUME_FOR_PREFAST(pos >= 0 && pos < TAG_HISTORY_DEPTH);
pTagHistory = m_TagHistory + pos;
pTagHistory->RefType = RefType;
pTagHistory->RefCount = RefCount;
pTagHistory->Line = Line;
pTagHistory->Tag = Tag;
pTagHistory->File = File;
if (m_CaptureStack) {
numFrames = RtlCaptureStackBackTrace(FRAMES_TO_SKIP,
FRAMES_TO_CAPTURE,
frames,
NULL);
if (numFrames > 0) {
CopyStackFrames(&pTagHistory->StackFrames, numFrames, frames);
}
}
//
// We use the perf counter here and the tick count in the tracking block.
// Use the tick count here as well until we decide that correlating the
// perf counter to system time is not important.
//
// pTagHistory->Time = KeQueryPerformanceCounter(NULL);
Mx::MxQueryTickCount(&pTagHistory->Time);
if (RefType == TagAddRef) {
//
// Try to allocate some memory for the new block. If unsuccessful,
// fallback to a failed count increment.
//
pBlock = new(pFxDriverGlobals) FxTagTrackingBlock(Tag, Line, File);
if (pBlock == NULL) {
InterlockedIncrement(&m_FailedCount);
}
else {
m_SpinLock.Acquire(&irql);
pBlock->Next = m_Next;
m_Next = pBlock;
m_SpinLock.Release(irql);
if (m_CaptureStack && numFrames > 0) {
CopyStackFrames(&pBlock->StackFrames, numFrames, frames);
}
}
}
else {
FxTagTrackingBlock **prev;
//
// Walk the list of current blocks and attempt to find the tag being
// released. If not found, decrement the failed count. If no failed
// tags exists, ASSERT immediately.
//
m_SpinLock.Acquire(&irql);
prev = &m_Next;
pBlock = *prev;
while (pBlock != NULL) {
if (pBlock->Tag == Tag) {
*prev = pBlock->Next;
break;
}
prev = &pBlock->Next;
pBlock = pBlock->Next;
}
m_SpinLock.Release(irql);
if (pBlock == NULL) {
//
// Check to see if we have any credits in our Low Memory Count.
// In this fassion we can tell if we have acquired any locks without
// the memory for adding tracking blocks.
//
if (InterlockedDecrement(&m_FailedCount) < 0) {
//
// We have just released a lock that neither had a corresponding
// tracking block, nor a credit in LowMemoryCount.
//
InterlockedIncrement(&m_FailedCount);
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"releasing %s %p on object %p that was not acquired, !wdftagtracker %p",
m_TrackerType == FxTagTrackerTypePower ? "power tag" : "tag",
Tag,
m_OwningObject,
this);
FxVerifierDbgBreakPoint(pFxDriverGlobals);
}
}
else {
delete pBlock;
pBlock = NULL;
}
}
}
VOID
FxTagTracker::CheckForAbandondedTags(
VOID
)
/*++
Routine Description:
Iterates over any existing tags, dumping any existing tags to the debugger.
Will assert if there any outstanding tags (assumes that the caller wants
no current tags).
Arguments:
None
Return Value:
None
--*/
{
PFX_DRIVER_GLOBALS pFxDriverGlobals;
FxTagTrackingBlock *current, *next;
LONG abandoned;
KIRQL irql;
BOOLEAN committed;
pFxDriverGlobals = GetDriverGlobals();
committed = m_OwningObject->IsCommitted();
//
// If the object was not committed, then it was an FxObject derived
// class that was *embedded* as a field in another structure or class.
// As such, we are allowing one outstanding reference at this time. We will
// catch > 1 outstanding references below in the while loop.
//
if (committed) {
if (m_Next != NULL || m_FailedCount != 0) {
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Dropped references on a tag tracker, "
"show references with: !wdftagtracker %p", this);
//
// If this ASSERT fails, look in the history .. you'll
// likely find that you released more references than you had
//
ASSERT(m_Next == NULL && m_FailedCount == 0);
}
}
m_SpinLock.Acquire(&irql);
current = m_Next;
abandoned = 0;
while (current != NULL) {
next = current->Next;
if (committed) {
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Abandonded ref on object %p tag %p (%s @ %d)",
m_OwningObject, current->Tag, current->File, current->Line);
abandoned++;
}
if (committed == FALSE) {
//
// The next time we encounter an abandoned reference, we will complain
// about it...we have used up our allowance of one leaked reference
// because the object is an embedded object.
//
// NOTE: we might be eating the real outstanding reference here
// and not tracing it and then tracing the initial creation
// reference as the leaked reference which will be confusing.
// This is b/c there is no way to distinguish what is the
// tracking block used to track the creatio of the object.
//
committed = TRUE;
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE,
"Possibly Abandonded ref on object %p tag %p (%s @ %d). "
"Is benign unless there are other outstanding leaked references.",
m_OwningObject, current->Tag, current->File, current->Line);
}
current = next;
}
m_SpinLock.Release(irql);
ASSERTMSG("Abandoned tags on ref\n", abandoned == 0);
}

View file

@ -0,0 +1,106 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxUserObject.cpp
Abstract:
This module implements the user object that device
driver writers can use to take advantage of the
driver frameworks infrastructure.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxobjectpch.hpp"
#include "FxUserObject.hpp"
// Tracing support
extern "C" {
#if defined(EVENT_TRACING)
#include "FxUserObject.tmh"
#endif
}
_Must_inspect_result_
NTSTATUS
FxUserObject::_Create(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
__out FxUserObject** pUserObject
)
{
FxUserObject* pObject = NULL;
NTSTATUS status;
USHORT wrapperSize = 0;
WDFOBJECT handle;
#ifdef INLINE_WRAPPER_ALLOCATION
#if FX_CORE_MODE==FX_CORE_USER_MODE
wrapperSize = FxUserObject::GetWrapperSize();
#endif
#endif
pObject = new(FxDriverGlobals, Attributes, wrapperSize)
FxUserObject(FxDriverGlobals);
if (pObject == NULL) {
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGOBJECT,
"Memory allocation failed");
return STATUS_INSUFFICIENT_RESOURCES;
}
status = pObject->Commit(Attributes, &handle);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR,
TRACINGOBJECT,
"FxObject::Commit failed %!STATUS!", status);
}
if (NT_SUCCESS(status)) {
*pUserObject = pObject;
}
else {
pObject->DeleteFromFailedCreate();
}
return status;
}
//
// Public constructors
//
FxUserObject::FxUserObject(
__in PFX_DRIVER_GLOBALS FxDriverGlobals
) :
#ifdef INLINE_WRAPPER_ALLOCATION
FxNonPagedObject(FX_TYPE_USEROBJECT, sizeof(FxUserObject) + GetWrapperSize(), FxDriverGlobals)
#else
FxNonPagedObject(FX_TYPE_USEROBJECT, sizeof(FxUserObject), FxDriverGlobals)
#endif
{
return;
}

View file

@ -0,0 +1,145 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxUserObjectApi.cpp
Abstract:
This modules implements the C API's for the FxUserObject.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxobjectpch.hpp"
#include "FxUserObject.hpp"
// Tracing support
extern "C" {
#if defined(EVENT_TRACING)
#include "FxUserObjectApi.tmh"
#endif
}
extern "C" {
_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
WDFEXPORT(WdfObjectCreate)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in_opt
PWDF_OBJECT_ATTRIBUTES Attributes,
__out
WDFOBJECT* Object
)
/*++
Routine Description:
This creates a general WDF object for use by the device driver.
It participates in general framework object contracts in that it:
- Has a handle and a reference count
- Has Cleanup and Destroy callbacks
- Supports driver context memory and type
- Can have child objects
- Can optionally have a parent object and automatically delete with it
It is intended to allow a WDF device driver to use this object to
create its own structures that can participate in frameworks lifetime
management.
The device driver can use the objects context memory and type to
represent its own internal data structures, and can further assign
device driver specific resources and release them by registering
for EvtObjectCleanup, and EvtObjectDestroy callbacks.
The object may be deleted by using the WdfObjectDelete API.
Since the object is represented by a frameworks handle, it can be
reference counted, and validated.
Class drivers may use this object to define framework object handles
for their types.
Arguments:
Attributes - WDF_OBJECT_ATTRIBUTES to define a parent object, context memory,
Cleanup and Destroy handlers.
Return Value:
NTSTATUS
--*/
{
DDI_ENTRY();
NTSTATUS status;
WDFOBJECT handle;
FxUserObject* pUserObject;
PFX_DRIVER_GLOBALS pFxDriverGlobals;
pUserObject = NULL;
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
//
// Get the parent's globals if it is present
//
if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
Attributes))) {
FxObject* pParent;
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
Attributes->ParentObject,
FX_TYPE_OBJECT,
(PVOID*)&pParent,
&pFxDriverGlobals);
}
FxPointerNotNull(pFxDriverGlobals, Object);
status = FxValidateObjectAttributes(pFxDriverGlobals,
Attributes,
FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED
);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Create the FxObject.
//
status = FxUserObject::_Create(pFxDriverGlobals, Attributes, &pUserObject);
if (NT_SUCCESS(status)) {
handle = pUserObject->GetHandle();
*Object = handle;
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE,
TRACINGUSEROBJECT,
"Created UserObject Handle 0x%p",
handle);
}
return status;
}
} // extern "C" the entire file

View file

@ -0,0 +1,220 @@
/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
FxValidateFunctions.cpp
Abstract:
Functions which validate external WDF data structures
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxobjectpch.hpp"
// We use DoTraceMessage
extern "C" {
#if defined(EVENT_TRACING)
#include "FxValidateFunctions.tmh"
#endif
}
_Must_inspect_result_
NTSTATUS
FxValidateObjectAttributes(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PWDF_OBJECT_ATTRIBUTES Attributes,
__in ULONG Flags
)
{
if (Attributes == NULL) {
if (Flags & FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"WDF_OBJECT_ATTRIBUTES required, %!STATUS!",
(ULONG) STATUS_WDF_PARENT_NOT_SPECIFIED);
return STATUS_WDF_PARENT_NOT_SPECIFIED;
}
else {
return STATUS_SUCCESS;
}
}
if (Attributes->Size != sizeof(WDF_OBJECT_ATTRIBUTES)) {
//
// Size is wrong, bail out
//
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p Size incorrect, expected %d, got %d, %!STATUS!",
Attributes, sizeof(WDF_OBJECT_ATTRIBUTES),
Attributes->Size, STATUS_INFO_LENGTH_MISMATCH);
return STATUS_INFO_LENGTH_MISMATCH;
}
if (Attributes->ContextTypeInfo != NULL) {
#pragma prefast(suppress:__WARNING_REDUNDANTTEST, "different structs of the same size")
if (Attributes->ContextTypeInfo->Size !=
sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO) &&
Attributes->ContextTypeInfo->Size !=
sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0)) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p ContextTypeInfo %p Size %d incorrect, expected %d, %!STATUS!",
Attributes, Attributes->ContextTypeInfo,
Attributes->ContextTypeInfo->Size,
sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO), STATUS_INFO_LENGTH_MISMATCH);
return STATUS_INFO_LENGTH_MISMATCH;
}
//
// A ContextName != NULL and a ContextSize of 0 is allowed
//
if (Attributes->ContextTypeInfo->ContextSize > 0 &&
Attributes->ContextTypeInfo->ContextName == NULL) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p ContextTypeInfo %p ContextSize %I64d is not zero, "
"but ContextName is NULL, %!STATUS!",
Attributes, Attributes->ContextTypeInfo,
Attributes->ContextTypeInfo->ContextSize,
STATUS_WDF_OBJECT_ATTRIBUTES_INVALID);
return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
}
}
if (Attributes->ContextSizeOverride > 0) {
if (Attributes->ContextTypeInfo == NULL) {
//
// Can't specify additional size without a type
//
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p ContextSizeOverride of %I64d specified, but no type "
"information, %!STATUS!",
Attributes, Attributes->ContextSizeOverride,
STATUS_WDF_OBJECT_ATTRIBUTES_INVALID);
return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
}
else if (Attributes->ContextSizeOverride <
Attributes->ContextTypeInfo->ContextSize) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p ContextSizeOverride %I64d < "
"ContextTypeInfo->ContextSize %I64d, %!STATUS!",
Attributes, Attributes->ContextSizeOverride,
Attributes->ContextTypeInfo->ContextSize,
STATUS_WDF_OBJECT_ATTRIBUTES_INVALID);
return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
}
}
if (Flags & FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED) {
if (Attributes->ParentObject != NULL) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p does not allow a parent object to be set, set to "
"%p, %!STATUS!", Attributes, Attributes->ParentObject,
STATUS_WDF_PARENT_ASSIGNMENT_NOT_ALLOWED);
return STATUS_WDF_PARENT_ASSIGNMENT_NOT_ALLOWED;
}
}
else if ((Flags & FX_VALIDATE_OPTION_PARENT_REQUIRED_FLAG) &&
Attributes->ParentObject == NULL) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"ParentObject required in WDF_OBJECT_ATTRIBUTES %p, %!STATUS!",
Attributes, STATUS_WDF_PARENT_NOT_SPECIFIED);
return STATUS_WDF_PARENT_NOT_SPECIFIED;
}
// Enum range checks
if ((Attributes->ExecutionLevel == WdfExecutionLevelInvalid) ||
(Attributes->ExecutionLevel > WdfExecutionLevelDispatch)) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p execution level set to %d, out of range, %!STATUS!",
Attributes, Attributes->ExecutionLevel,
STATUS_WDF_OBJECT_ATTRIBUTES_INVALID);
return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
}
if ((Attributes->SynchronizationScope == WdfSynchronizationScopeInvalid) ||
(Attributes->SynchronizationScope > WdfSynchronizationScopeNone)) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p synchronization scope set to %d, out of range, %!STATUS!",
Attributes, Attributes->SynchronizationScope,
STATUS_WDF_OBJECT_ATTRIBUTES_INVALID);
return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID;
}
if ((Flags & FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED) == 0) {
//
// If synchronization is not allowed for this object,
// check the requested level to ensure none was specified.
//
if ((Attributes->SynchronizationScope != WdfSynchronizationScopeInheritFromParent) &&
(Attributes->SynchronizationScope != WdfSynchronizationScopeNone)) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p does not allow synchronization scope too be set, "
"but was set to %!WDF_SYNCHRONIZATION_SCOPE!, %!STATUS!",
Attributes, Attributes->SynchronizationScope,
STATUS_WDF_SYNCHRONIZATION_SCOPE_INVALID);
return STATUS_WDF_SYNCHRONIZATION_SCOPE_INVALID;
}
}
if ((Flags & FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED) == 0) {
//
// If execution level restrictions are not allowed for this object,
// check the requested level to ensure none was specified.
//
if (Attributes->ExecutionLevel != WdfExecutionLevelInheritFromParent) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
"Attributes %p does not allow execution level to be set, but was"
" set to %!WDF_EXECUTION_LEVEL!, %!STATUS!",
Attributes, Attributes->ExecutionLevel,
STATUS_WDF_EXECUTION_LEVEL_INVALID);
return STATUS_WDF_EXECUTION_LEVEL_INVALID;
}
}
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,107 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxVerifierBugcheck.cpp
Abstract:
This file contains definitions of verifier bugcheck functions
These definitions are split from tracing.cpp in kmdf\src\core
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxobjectpch.hpp"
// We use DoTraceMessage
extern "C" {
#if defined(EVENT_TRACING)
#include "FxVerifierBugcheck.tmh"
#endif
}
//=============================================================================
//
//=============================================================================
VOID
__declspec(noreturn)
FxVerifierBugCheckWorker(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in WDF_BUGCHECK_CODES WdfBugCheckCode,
__in_opt ULONG_PTR BugCheckParameter2,
__in_opt ULONG_PTR BugCheckParameter3
)
/*++
Routine Description:
Wrapper for system BugCheck.
Note this functions is marked "__declspec(noreturn)"
Arguments:
Returns:
--*/
{
//
// Indicate to the BugCheck callback filter which IFR to dump.
//
FxDriverGlobals->FxForceLogsInMiniDump = TRUE;
Mx::MxBugCheckEx(WDF_VIOLATION,
WdfBugCheckCode,
BugCheckParameter2,
BugCheckParameter3,
(ULONG_PTR) FxDriverGlobals );
}
VOID
__declspec(noreturn)
FxVerifierNullBugCheck(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PVOID ReturnAddress
)
/*++
Routine Description:
Calls KeBugCheckEx indicating a WDF DDI was passed a NULL parameter.
Note this functions is marked "__declspec(noreturn)"
Arguments:
Returns:
--*/
{
DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGERROR,
"NULL Required Parameter Passed to a DDI\n"
"FxDriverGlobals 0x%p",
FxDriverGlobals
);
FxVerifierBugCheck(FxDriverGlobals,
WDF_REQUIRED_PARAMETER_IS_NULL, // Bugcheck code.
0, // Parameter 2
(ULONG_PTR)ReturnAddress // Parameter 3
);
}

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,702 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
HandleApi.cpp
Abstract:
This module implements the driver frameworks handle functions.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxobjectpch.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "HandleAPI.tmh"
#endif
}
size_t
FxGetContextSize(
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes
)
/*++
Routine Description:
Get a context size from an object's attributes settings.
Arguments:
Attributes - attributes which will describe the size requirements for the
associated context.
Return Value:
Size requirements for the associated context.
--*/
{
size_t contextSize = 0;
if (Attributes != NULL) {
if (Attributes->ContextTypeInfo != NULL) {
if (Attributes->ContextSizeOverride != 0) {
contextSize = Attributes->ContextSizeOverride;
}
else {
contextSize = Attributes->ContextTypeInfo->ContextSize;
}
}
}
return contextSize;
}
_Must_inspect_result_
NTSTATUS
FxCalculateObjectTotalSize2(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in USHORT RawObjectSize,
__in USHORT ExtraSize,
__in size_t ContextSize,
__out size_t* Total
)
/*++
Routine Description:
Calculates the size of an allocation for an FxObject that will contain the
object, its initial context and any addtional headers.
Arguments:
FxDriverGlobals - driver's globals
RawObjectSize - the size of the FxObject derived object
ExtraSize - additional size required by the derived object
ContextSize - Size requirements for the associated context (see FxGetContextSize() above).
Total - pointer which will receive the final size requirement
Return Value:
NT_SUCCESS on success, !NT_SUCCESS on failure
--*/
{
NTSTATUS status;
*Total = 0;
status = RtlSizeTAdd(
WDF_ALIGN_SIZE_UP(COMPUTE_OBJECT_SIZE(RawObjectSize, ExtraSize), MEMORY_ALLOCATION_ALIGNMENT),
FX_CONTEXT_HEADER_SIZE,
Total
);
if (NT_SUCCESS(status)) {
if (ContextSize != 0) {
size_t alignUp;
alignUp = ALIGN_UP(ContextSize, PVOID);
//
// overflow after aligning up to a pointer boundary;
//
if (alignUp < ContextSize) {
return STATUS_INTEGER_OVERFLOW;
}
status = RtlSizeTAdd(*Total, alignUp, Total);
}
}
if (NT_SUCCESS(status) && FxDriverGlobals->IsObjectDebugOn()) {
//
// Attempt to add in the debug extension
//
status = RtlSizeTAdd(*Total,
FxObjectDebugExtensionSize,
Total);
}
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGOBJECT,
"Size overflow, object size 0x%x, extra object size 0x%x, "
"context size 0x%I64x, %!STATUS!",
RawObjectSize, ExtraSize, ContextSize, status);
}
return status;
}
_Must_inspect_result_
NTSTATUS
FxCalculateObjectTotalSize(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in USHORT RawObjectSize,
__in USHORT ExtraSize,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
__out size_t* Total
)
{
return FxCalculateObjectTotalSize2(FxDriverGlobals,
RawObjectSize,
ExtraSize,
FxGetContextSize(Attributes),
Total);
}
PVOID
FxObjectHandleAlloc(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in POOL_TYPE PoolType,
__in size_t Size,
__in ULONG Tag,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
__in USHORT ExtraSize,
__in FxObjectType ObjectType
)
/*++
Routine Description:
Allocates an FxObject derived object, it's associated context, and any
framework required headers and footers.
Arguments:
FxDriverGlobals - caller's globals
PoolType - type of pool to be used in allocating the object's memory
Size - size of the object (as passed to operator new() by the compiler)
Tag - tag to use when allocating the object's memory
Attributes - attributes which describe the context to be associated with the
object
ExtraSize - any addtional storage required by the object itself
ObjectType - the type (internal or external) of object being allocated. An
internal object is a worker object which will never have an associated
type or be Commit()'ed into an external object handle that the client
driver will see.
Return Value:
A valid pointer on success, NULL otherwise
--*/
{
PVOID blob;
size_t totalSize;
NTSTATUS status;
if (Tag == 0) {
Tag = FxDriverGlobals->Tag;
ASSERT(Tag != 0);
}
if (ObjectType == FxObjectTypeInternal) {
//
// An internal object might need the debug extension size added to it,
// but that's it. No extra size, no FxContextHeader.
//
if (FxDriverGlobals->IsObjectDebugOn()) {
status = RtlSizeTAdd(Size,
FxObjectDebugExtensionSize,
&totalSize);
}
else {
totalSize = Size;
status = STATUS_SUCCESS;
}
}
else {
status = FxCalculateObjectTotalSize(FxDriverGlobals,
(USHORT) Size,
ExtraSize,
Attributes,
&totalSize);
}
if (!NT_SUCCESS(status)) {
return NULL;
}
blob = FxPoolAllocateWithTag(FxDriverGlobals, PoolType, totalSize, Tag);
if (blob != NULL) {
blob = FxObjectAndHandleHeaderInit(
FxDriverGlobals,
blob,
COMPUTE_OBJECT_SIZE((USHORT) Size, ExtraSize),
Attributes,
ObjectType
);
}
return blob;
}
VOID
FxContextHeaderInit(
__in FxContextHeader* Header,
__in FxObject* Object,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes
)
/*++
Routine Description:
Initializes a context header which describes a typed context.
Arguments:
Header - the header to initialize
Object - the object on which the context is being associated with
Attributes - description of the typed context
--*/
{
RtlZeroMemory(Header, FX_CONTEXT_HEADER_SIZE);
Header->Object = Object;
if (Attributes != NULL) {
if (Attributes->ContextTypeInfo != NULL) {
size_t contextSize;
if (Attributes->ContextSizeOverride != 0) {
contextSize = Attributes->ContextSizeOverride;
}
else {
contextSize = Attributes->ContextTypeInfo->ContextSize;
}
//
// Zero initialize the entire context
//
RtlZeroMemory(&Header->Context[0], ALIGN_UP(contextSize, PVOID));
}
Header->ContextTypeInfo = Attributes->ContextTypeInfo;
}
}
PVOID
FxObjectAndHandleHeaderInit(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PVOID AllocationStart,
__in USHORT ObjectSize,
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
__in FxObjectType ObjectType
)
/*++
Routine Description:
Initialize the object and its associated context.
Arguments:
FxDriverGlobals - caller's globals
AllocationStart - start of the memory block allocated to represent the object.
This will not be the same as the pointer which represents the address of
the object itself in memory
ObjectSize - size of the object
Attributes - description of its context
ObjectType - type (internal or external) of object being initialized
Return Value:
The address of the object withing AllocationStart
--*/
{
FxObject* pObject;
if (FxDriverGlobals->IsObjectDebugOn()) {
FxObjectDebugExtension* pExtension;
pExtension = (FxObjectDebugExtension*) AllocationStart;
RtlZeroMemory(pExtension, FxObjectDebugExtensionSize);
pExtension->Signature = FxObjectDebugExtensionSignature;
pObject = (FxObject*) &pExtension->AllocationStart[0];
}
else {
pObject = (FxObject*) AllocationStart;
}
if (ObjectType == FxObjectTypeExternal) {
FxContextHeaderInit(
(FxContextHeader*) WDF_PTR_ADD_OFFSET(pObject, ObjectSize),
pObject,
Attributes
);
}
return pObject;
}
VOID
FxObjectHandleGetPtrQI(
__in FxObject* Object,
__out PVOID* PPObject,
__in WDFOBJECT Handle,
__in WDFTYPE Type,
__in WDFOBJECT_OFFSET Offset
)
/*++
Routine Description:
Worker function for FxObjectHandleGetPtrXxx which will call
FxObject::QueryInterface when the Type does not match the object's built in
Type.
Arguments:
Object - object to query
PPObject - pointer which will recieve the queried for object
Handle - handle which the caller passed to the framework
Type - required object type
Offset - offset of the handle within the object. Nearly all handles will have
a zero object.
--*/
{
FxQueryInterfaceParams params = { PPObject, Type, Offset };
NTSTATUS status;
*PPObject = NULL;
status = Object->QueryInterface(&params);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
Object->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Object Type Mismatch, Handle 0x%p, Type 0x%x, "
"Obj 0x%p, SB 0x%x",
Handle, Type, Object, Object->GetType());
FxVerifierBugCheck(Object->GetDriverGlobals(),
WDF_INVALID_HANDLE,
(ULONG_PTR) Handle,
Type);
/* NOTREACHED */
return;
}
}
_Must_inspect_result_
NTSTATUS
FxObjectAllocateContext(
__in FxObject* Object,
__in PWDF_OBJECT_ATTRIBUTES Attributes,
__in BOOLEAN AllowCallbacksOnly,
__deref_opt_out PVOID* Context
)
/*++
Routine Description:
Allocates an additional context on the object if it is in the correct state.
Arguments:
Object - object on which to add a context
Attributes - attributes which describe the type and size of the new context
AllowEmptyContext -TRUE to allow logic to allocate the context's header only.
Context - optional pointer which will recieve the new context
Return Value:
STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type
is already attached to the handle, and !NT_SUCCESS on failure
--*/
{
PFX_DRIVER_GLOBALS fxDriverGlobals;
NTSTATUS status;
FxContextHeader * header;
size_t size;
BOOLEAN relRef;
ULONG flags;
fxDriverGlobals = Object->GetDriverGlobals();
header = NULL;
relRef = FALSE;
//
// Init validation flags.
//
flags = FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED;
if (fxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
flags |= FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED;
}
//
// Basic validations.
//
status = FxValidateObjectAttributes(fxDriverGlobals, Attributes, flags);
if (!NT_SUCCESS(status)) {
goto Done;
}
//
// Check for context type!
//
if (Attributes->ContextTypeInfo == NULL && AllowCallbacksOnly == FALSE) {
status = STATUS_OBJECT_NAME_INVALID;
DoTraceLevelMessage(
fxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE,
"Attributes %p ContextTypeInfo is NULL, %!STATUS!",
Attributes, status);
goto Done;
}
Object->ADDREF(&status);
relRef = TRUE;
//
// By passing 0's for raw object size and extra size, we can compute the
// size of only the header and its contents.
//
status = FxCalculateObjectTotalSize(fxDriverGlobals, 0, 0, Attributes, &size);
if (!NT_SUCCESS(status)) {
goto Done;
}
header = (FxContextHeader*)
FxPoolAllocate(fxDriverGlobals, NonPagedPool, size);
if (header == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
FxContextHeaderInit(header, Object, Attributes);
status = Object->AddContext(header, Context, Attributes);
//
// STATUS_OBJECT_NAME_EXISTS will not fail NT_SUCCESS, so check
// explicitly for STATUS_SUCCESS.
//
if (status != STATUS_SUCCESS) {
FxPoolFree(header);
}
Done:
if (relRef) {
Object->RELEASE(&status);
}
return status;
}
// extern "C" all APIs
extern "C" {
_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
WDFAPI
NTSTATUS
WDFEXPORT(WdfObjectAllocateContext)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFOBJECT Handle,
__in
PWDF_OBJECT_ATTRIBUTES Attributes,
__deref_opt_out
PVOID* Context
)
/*++
Routine Description:
Allocates an additional context on the handle if the object is in the
correct state
Arguments:
Handle - handle on which to add a context
Attributes - attributes which describe the type and size of the new context
Context - optional pointer which will recieve the new context
Return Value:
STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type
is already attached to the handle, and !NT_SUCCESS on failure
--*/
{
DDI_ENTRY_IMPERSONATION_OK();
NTSTATUS status;
FxObject* object;
WDFOBJECT_OFFSET offset;
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Handle);
//
// No need to call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because
// we assume that the object handle will point back to an FxObject. (The
// call to FxObjectHandleGetPtr will just make needless virtual call into
// FxObject anyways).
//
offset = 0;
object = FxObject::_GetObjectFromHandle(Handle, &offset);
if (offset != 0) {
status = STATUS_OBJECT_PATH_INVALID;
DoTraceLevelMessage(
object->GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGHANDLE,
"WDFHANDLE %p cannot have contexts added to it, %!STATUS!",
Handle, status);
goto Done;
}
//
// Internal helper function does the rest of the work.
//
status = FxObjectAllocateContext(object, Attributes, FALSE, Context);
Done:
return status;
}
__drv_maxIRQL(DISPATCH_LEVEL+1)
WDFAPI
PVOID
FASTCALL
WDFEXPORT(WdfObjectGetTypedContextWorker)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFOBJECT Handle,
__in
PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo
)
/*++
Routine Description:
Retrieves the requested type from a handle
Arguments:
Handle - the handle to retrieve the context from
TypeInfo - global constant pointer which describes the type. Since the pointer
value is unique in all of kernel space, we will perform a pointer compare
instead of a deep structure compare
Return Value:
A valid context pointere or NULL. NULL is not a failure, querying for a type
not associated with the handle is a legitimate operation.
--*/
{
DDI_ENTRY_IMPERSONATION_OK();
FxContextHeader* pHeader;
FxObject* pObject;
PFX_DRIVER_GLOBALS pFxDriverGlobals;
WDFOBJECT_OFFSET offset;
FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Handle);
//
// Do not call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because this is a
// hot spot / workhorse function that should be as efficient as possible.
//
// A call to FxObjectHandleGetPtr would :
// 1) invoke a virtual call to QueryInterface
//
// 2) ASSERT that the ref count of the object is > zero. Since this is one
// of the few functions that can be called in EvtObjectDestroy where the
// ref count is zero, that is not a good side affect.
//
offset = 0;
pObject = FxObject::_GetObjectFromHandle(Handle, &offset);
//
// Use the object's globals, not the caller's
//
pFxDriverGlobals = pObject->GetDriverGlobals();
FxPointerNotNull(pFxDriverGlobals, TypeInfo);
pHeader = pObject->GetContextHeader();
for ( ; pHeader != NULL; pHeader = pHeader->NextHeader) {
if (pHeader->ContextTypeInfo == TypeInfo) {
return &pHeader->Context[0];
}
}
PCHAR pGivenName;
if (TypeInfo->ContextName != NULL) {
pGivenName = TypeInfo->ContextName;
}
else {
pGivenName = "<no typename given>";
}
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE,
"Attempting to get context type %s from WDFOBJECT 0x%p",
pGivenName, Handle);
return NULL;
}
__drv_maxIRQL(DISPATCH_LEVEL+1)
WDFAPI
WDFOBJECT
FASTCALL
WDFEXPORT(WdfObjectContextGetObject)(
__in
PWDF_DRIVER_GLOBALS,
__in
PVOID ContextPointer
)
/*++
Routine Description:
Reverse of WdfObjectGetTypedContextWorker. Function will return the handle
associated with the provided context pointer.
Arguments:
ContextPointer - context pointer from which to retrieve the owning handle
Return Value:
A valid WDF handle
--*/
{
DDI_ENTRY_IMPERSONATION_OK();
FxContextHeader* pHeader;
FxObject* pObject;
//
// The context could be one of the chained contexts on the object and not
// the first one, so it is easiest to go back to the object and build the
// handle value from the FxObject*.
//
#pragma prefast(push);
#pragma prefast(disable:__WARNING_BUFFER_UNDERFLOW, "No way to express that passed in ptr is at an offset");
pHeader = CONTAINING_RECORD(ContextPointer, FxContextHeader, Context);
pObject = pHeader->Object;
#pragma prefast(pop);
return (WDFOBJECT) pObject->GetObjectHandle();
}
} // extern "C"

View file

@ -0,0 +1,120 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxObjectKm.cpp
Abstract:
Kernel mode implementations of FxObject APIs
Author:
Environment:
kernel mode only
Revision History:
--*/
#include "fxobjectpch.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "FxObjectKm.tmh"
#endif
}
extern "C" {
_Must_inspect_result_
NTSTATUS
FxObject::_ObjectQuery(
_In_ FxObject* Object,
_In_ CONST GUID* Guid,
_In_ ULONG QueryBufferLength,
_Out_writes_bytes_(QueryBufferLength)
PVOID QueryBuffer
)
/*++
Routine Description:
Query the object handle for specific information
This allows dynamic extensions to DDI's.
Currently, it is used to allow test hooks for verification
which are not available in a production release.
Arguments:
Object - Object to query
Guid - GUID to represent the information/DDI to query for
QueryBufferLength - Length of QueryBuffer to return data in
QueryBuffer - Pointer to QueryBuffer
Returns:
NTSTATUS
--*/
{
// PFX_DRIVER_GLOBALS pFxDriverGlobals = Object->GetDriverGlobals();
//
// Design Note: This interface does not look strongly typed
// but it is. The GUID defines a specific strongly typed
// contract for QueryBuffer and QueryBufferLength.
//
#if DBG
//
// These operations are only available on checked builds for deep unit
// testing, code coverage analysis, and model verification.
//
// Add code based on the GUID
// IsEqualGUID(guid1, guid2), DEFINE_GUID, INITGUID, inc\wnet\guiddef.h
UNREFERENCED_PARAMETER(Object);
UNREFERENCED_PARAMETER(Guid);
UNREFERENCED_PARAMETER(QueryBufferLength);
UNREFERENCED_PARAMETER(QueryBuffer);
#else
UNREFERENCED_PARAMETER(Object);
UNREFERENCED_PARAMETER(Guid);
UNREFERENCED_PARAMETER(QueryBufferLength);
UNREFERENCED_PARAMETER(QueryBuffer);
#endif
return STATUS_NOT_FOUND;
}
} // extern "C"

View file

@ -0,0 +1,254 @@
//
// Copyright (C) Microsoft. All rights reserved.
//
#include "fxobjectpch.hpp"
// Tracing support
extern "C" {
#if defined(EVENT_TRACING)
#include "GlobalsKm.tmh"
#endif
#include <wdfcxbase.h>
#include <fxldr.h>
}
extern "C" {
VOID
FxFreeAllocatedMdlsDebugInfo(
__in FxDriverGlobalsDebugExtension* DebugExtension
)
{
FxAllocatedMdls* pNext, *pCur;
pNext = DebugExtension->AllocatedMdls.Next;
//
// MDL leaks were already checked for in FxPoolDestroy, just free all
// the tables here.
//
while (pNext != NULL) {
pCur = pNext;
pNext = pCur->Next;
ExFreePool(pCur);
}
}
KDEFERRED_ROUTINE FxFlushDpc;
__drv_functionClass(KDEFERRED_ROUTINE)
__drv_maxIRQL(DISPATCH_LEVEL)
__drv_minIRQL(DISPATCH_LEVEL)
__drv_requiresIRQL(DISPATCH_LEVEL)
__drv_sameIRQL
VOID
FxFlushDpc (
__in struct _KDPC *Dpc,
__in_opt PVOID DeferredContext,
__in_opt PVOID SystemArgument1,
__in_opt PVOID SystemArgument2
)
/*++
Routine Description:
This DPC is called on a processor to assist in flushing previous DPC's
Arguments:
Dpc - Supplies a pointer to DPC object.
DeferredContext - Supplies the deferred context (event object address).
SystemArgument1 - Supplies the first system context parameter (not used).
SystemArgument2 - Supplies the second system context parameter (not used).
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
//
// Signal that this routine has been called.
//
((FxCREvent*)DeferredContext)->Set();
}
_Must_inspect_result_
BOOLEAN
FX_DRIVER_GLOBALS::IsVersionGreaterThanOrEqualTo(
__in ULONG Major,
__in ULONG Minor
)
{
if ((WdfBindInfo->Version.Major > Major) ||
(WdfBindInfo->Version.Major == Major &&
WdfBindInfo->Version.Minor >= Minor)) {
return TRUE;
}
else {
return FALSE;
}
}
#define WDF_MAJOR_VERSION_VALUE L"WdfMajorVersion"
#define WDF_MINOR_VERSION_VALUE L"WdfMinorVersion"
_Must_inspect_result_
BOOLEAN
FX_DRIVER_GLOBALS::IsCorrectVersionRegistered(
_In_ PCUNICODE_STRING ServiceKeyName
)
{
FxAutoRegKey hDriver, hWdf;
DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf");
DECLARE_CONST_UNICODE_STRING(wdfMajorValue, WDF_MAJOR_VERSION_VALUE);
DECLARE_CONST_UNICODE_STRING(wdfMinorValue, WDF_MINOR_VERSION_VALUE);
ULONG registeredMajor = 0, registeredMinor = 0;
NTSTATUS status;
status = FxRegKey::_OpenKey(NULL,
ServiceKeyName,
&hDriver.m_Key,
KEY_READ
);
if (!NT_SUCCESS(status)) {
return FALSE;
}
status = FxRegKey::_OpenKey(hDriver.m_Key,
&parametersPath,
&hWdf.m_Key,
KEY_READ
);
if (!NT_SUCCESS(status)) {
return FALSE;
}
status = FxRegKey::_QueryULong(hWdf.m_Key,
&wdfMajorValue,
&registeredMajor);
if (!NT_SUCCESS(status) || registeredMajor != WdfBindInfo->Version.Major) {
return FALSE;
}
status = FxRegKey::_QueryULong(hWdf.m_Key,
&wdfMinorValue,
&registeredMinor);
if (!NT_SUCCESS(status) || registeredMinor != WdfBindInfo->Version.Minor){
return FALSE;
}
else {
return TRUE;
}
}
VOID
FX_DRIVER_GLOBALS::RegisterClientVersion(
_In_ PCUNICODE_STRING ServiceKeyName
)
{
FxAutoRegKey hDriver, hParameters, hWdf;
DECLARE_CONST_UNICODE_STRING(parametersPart, L"Parameters");
DECLARE_CONST_UNICODE_STRING(wdfPart, L"Wdf");
//
// Not defined with the macro because ZwSetValue doesn't use PCUNICODE_STRING
//
UNICODE_STRING wdfMajorValue;
UNICODE_STRING wdfMinorValue;
NTSTATUS status;
RtlInitUnicodeString(&wdfMajorValue, WDF_MAJOR_VERSION_VALUE);
RtlInitUnicodeString(&wdfMinorValue, WDF_MINOR_VERSION_VALUE);
status = FxRegKey::_OpenKey(NULL,
ServiceKeyName,
&hDriver.m_Key,
KEY_WRITE | KEY_READ
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
"Unable to open driver's service key, status %!STATUS!", status);
return;
}
//
// Key creation, unlike user mode, must happen one level at a time, since
// create will also open take both steps instead of trying open first
//
status = FxRegKey::_Create(hDriver.m_Key,
&parametersPart,
&hParameters.m_Key,
KEY_WRITE | KEY_READ
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
"Unable to write Parameters key, status %!STATUS!", status);
return;
}
status = FxRegKey::_Create(hParameters.m_Key,
&wdfPart,
&hWdf.m_Key,
KEY_WRITE | KEY_READ
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
"Unable to write Parameters key, status %!STATUS!", status);
return;
}
//
// Using ZwSetValueKey here to avoid having to change the implementation
// in FxRegKey of SetValue to a static / thiscall pair
//
status = ZwSetValueKey(hWdf.m_Key,
&wdfMajorValue,
0,
REG_DWORD,
&WdfBindInfo->Version.Major,
sizeof(WdfBindInfo->Version.Major)
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
"Failed to record driver major version value, status %!STATUS!", status);
}
status = ZwSetValueKey(hWdf.m_Key,
&wdfMinorValue,
0,
REG_DWORD,
&WdfBindInfo->Version.Minor,
sizeof(WdfBindInfo->Version.Minor)
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
"Failed to record driver version value, status %!STATUS!", status);
}
}
} // extern "C"
_Must_inspect_result_
BOOLEAN
FX_DRIVER_GLOBALS::IsDebuggerAttached(
VOID
)
{
return (FALSE == KdRefreshDebuggerNotPresent());
}

View file

@ -0,0 +1,272 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
wdfpoolkm.cpp
Abstract:
This module implements the driver frameworks pool routines
functionality only applicable in kernel mode
Author:
Environment:
Kernel mode only
Revision History:
--*/
#include "fxobjectpch.hpp"
// We use DoTraceMessage
extern "C" {
#if defined(EVENT_TRACING)
#include "wdfpoolkm.tmh"
#endif
}
// undo the previous masking
#undef IoAllocateMdl
#undef IoFreeMdl
__drv_maxIRQL(DISPATCH_LEVEL)
NTKERNELAPI
PMDL
IoAllocateMdl(
__in_opt __drv_aliasesMem PVOID VirtualAddress,
__in ULONG Length,
__in BOOLEAN SecondaryBuffer,
__in BOOLEAN ChargeQuota,
__inout_opt PIRP Irp
);
__drv_maxIRQL(DISPATCH_LEVEL)
NTKERNELAPI
VOID
IoFreeMdl(
PMDL Mdl
);
//
// Windows Driver Framework Pool Tracking
//
// This module implements a generic pool tracking mechanism
// if pool verifier mode is enabled.
//
// There can be multiple pools, each represented by a FX_POOL header.
//
// When the framework is supplied as a DLL, there is a global
// pool that represents allocations for the framework DLL itself. These
// allocations are pool allocations and object allocations.
//
// The driver's pool allocations are not currently tracked. If the driver needs
// to use pool outside of the framework objects, it calls the WDM
// ExAllocatePoolWithTag and ExFreePool(WithTag) APIs.
//
PMDL
FxMdlAllocateDebug(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in FxObject* Owner,
__in PVOID VirtualAddress,
__in ULONG Length,
__in BOOLEAN SecondaryBuffer,
__in BOOLEAN ChargeQuota,
__in PVOID CallersAddress
)
{
FxDriverGlobalsDebugExtension* pExtension;
FxAllocatedMdls* pAllocated, **ppNext;
ULONG i;
PMDL pMdl;
KIRQL irql;
pExtension = FxDriverGlobals->DebugExtension;
if (pExtension == NULL) {
return IoAllocateMdl(VirtualAddress,
Length,
SecondaryBuffer,
ChargeQuota,
NULL);
}
pAllocated = &pExtension->AllocatedMdls;
ppNext = NULL;
pMdl = NULL;
KeAcquireSpinLock(&pExtension->AllocatedMdlsLock, &irql);
while (pAllocated != NULL && pAllocated->Count == NUM_MDLS_IN_INFO) {
ppNext = &pAllocated->Next;
pAllocated = pAllocated->Next;
}
if (pAllocated == NULL) {
//
// No more entries, allocate a new table
//
pAllocated = (FxAllocatedMdls*) ExAllocatePoolWithTag(
NonPagedPool, sizeof(FxAllocatedMdls), FxDriverGlobals->Tag);
if (pAllocated != NULL) {
//
// Zero out the new buffer and link it in to the list
//
RtlZeroMemory(pAllocated, sizeof(*pAllocated));
*ppNext = pAllocated;
}
else {
//
// Could not allocate a new table, return error
//
KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql);
return NULL;
}
}
for (i = 0; i < NUM_MDLS_IN_INFO; i++) {
if (pAllocated->Info[i].Mdl != NULL) {
continue;
}
pMdl = IoAllocateMdl(VirtualAddress,
Length,
SecondaryBuffer,
ChargeQuota,
NULL);
if (pMdl != NULL) {
pAllocated->Info[i].Mdl = pMdl;
pAllocated->Info[i].Owner = Owner;
pAllocated->Info[i].Caller = CallersAddress;
pAllocated->Count++;
}
break;
}
KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql);
return pMdl;
}
VOID
FxMdlFreeDebug(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PMDL Mdl
)
{
FxDriverGlobalsDebugExtension* pExtension;
FxAllocatedMdls* pAllocated, **ppNext;
ULONG i;
KIRQL irql;
BOOLEAN found;
pExtension = FxDriverGlobals->DebugExtension;
if (pExtension == NULL) {
IoFreeMdl(Mdl);
return;
}
found = FALSE;
pAllocated = &pExtension->AllocatedMdls;
ppNext = NULL;
KeAcquireSpinLock(&pExtension->AllocatedMdlsLock, &irql);
while (pAllocated != NULL) {
for (i = 0; i < NUM_MDLS_IN_INFO; i++) {
if (pAllocated->Info[i].Mdl != Mdl) {
continue;
}
RtlZeroMemory(&pAllocated->Info[i],
sizeof(pAllocated->Info[i]));
pAllocated->Count--;
if (pAllocated->Count == 0 &&
pAllocated != &pExtension->AllocatedMdls) {
//
// Remove the current table from the chain
//
*ppNext = pAllocated->Next;
//
// And free it
//
ExFreePool(pAllocated);
}
IoFreeMdl(Mdl);
found = TRUE;
break;
}
if (found) {
break;
}
ppNext = &pAllocated->Next;
pAllocated = pAllocated->Next;
}
KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql);
if (found == FALSE) {
FxVerifierDbgBreakPoint(FxDriverGlobals);
}
}
VOID
FxMdlDump(
__in PFX_DRIVER_GLOBALS FxDriverGlobals
)
{
FxAllocatedMdls *pCur;
BOOLEAN leak;
if (FxDriverGlobals->DebugExtension == NULL) {
return;
}
leak = FALSE;
for (pCur = &FxDriverGlobals->DebugExtension->AllocatedMdls;
pCur != NULL;
pCur = pCur->Next) {
ULONG i;
for (i = 0; i < NUM_MDLS_IN_INFO; i++) {
if (pCur->Info[i].Mdl != NULL) {
leak = TRUE;
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"PMDL 0x%p leaked, FxObject owner %p, Callers Address %p",
pCur->Info[i].Mdl, pCur->Info[i].Owner,
pCur->Info[i].Caller);
}
}
}
if (leak) {
FxVerifierDbgBreakPoint(FxDriverGlobals);
}
}

View file

@ -0,0 +1,37 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
objectpriv.hpp
Abstract:
Private header file for shared\object directory
It is then included in objectpch.hpp
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
extern "C" {
#include "mx.h"
}
//
// Root WDF key, for both UMDF and KMDF settings.
//
#define WDF_REGISTRY_BASE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wdf"
#define WDF_GLOBAL_VALUE_IFRDISABLED L"WdfGlobalLogsDisabled" // REG_DWORD

View file

@ -0,0 +1,70 @@
//
// Copyright (C) Microsoft. All rights reserved.
//
#include "FxMin.hpp"
#include "fxobjectpch.hpp"
#include "FxUserObject.hpp"
#include "pnppriv.hpp"
//
// More object types should be added to this table as more objects
// are merged and incorporated in UMDF
//
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_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(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(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),
};
ULONG FxObjectsInfoCount = sizeof(FxObjectsInfo)/sizeof(FX_OBJECT_INFO);
} //extern "C"

View file

@ -0,0 +1,194 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxObjectUm.cpp
Abstract:
User mode implementations of FxObject APIs
Author:
Environment:
user mode only
Revision History:
--*/
#include "fxobjectpch.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "FxObjectUm.tmh"
#endif
}
extern "C" {
#define INITGUID
#include <guiddef.h>
#include <WdfFileObject_private.h>
//
// Function declarations for the WdfObjectQuery DDIs
//
_IRQL_requires_max_(PASSIVE_LEVEL)
WDFAPI
NTSTATUS
WDFEXPORT(WdfFileObjectIncrementProcessKeepAliveCount)(
_In_
PWDF_DRIVER_GLOBALS DriverGlobals,
_In_
WDFFILEOBJECT FileObject
);
_IRQL_requires_max_(PASSIVE_LEVEL)
WDFAPI
NTSTATUS
WDFEXPORT(WdfFileObjectDecrementProcessKeepAliveCount)(
_In_
PWDF_DRIVER_GLOBALS DriverGlobals,
_In_
WDFFILEOBJECT FileObject
);
}
extern "C" {
_Must_inspect_result_
NTSTATUS
FxObject::_ObjectQuery(
_In_ FxObject* Object,
_In_ CONST GUID* Guid,
_In_ ULONG QueryBufferLength,
_Out_writes_bytes_(QueryBufferLength)
PVOID QueryBuffer
)
/*++
Routine Description:
Query the object handle for specific information
This allows dynamic extensions to DDI's.
Currently, it is used to allow test hooks for verification
which are not available in a production release.
Arguments:
Object - Object to query
Guid - GUID to represent the information/DDI to query for
QueryBufferLength - Length of QueryBuffer to return data in
QueryBuffer - Pointer to QueryBuffer
Returns:
NTSTATUS
--*/
{
PFX_DRIVER_GLOBALS pFxDriverGlobals = Object->GetDriverGlobals();
//
// Design Note: This interface does not look strongly typed
// but it is. The GUID defines a specific strongly typed
// contract for QueryBuffer and QueryBufferLength.
//
#if DBG
//
// These operations are only available on checked builds for deep unit
// testing, code coverage analysis, and model verification.
//
// Add code based on the GUID
// IsEqualGUID(guid1, guid2), DEFINE_GUID, INITGUID, inc\wnet\guiddef.h
#endif
if (IsEqualGUID(*Guid, GUID_WDFP_FILEOBJECT_INTERFACE)) {
//
// Check the query buffer size before performing the cast
//
const ULONG RequiredBufferLength = sizeof(WDFP_FILEOBJECT_INTERFACE);
if (QueryBufferLength < RequiredBufferLength) {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Insufficient query buffer size for file object query "
"Required size %d, %!STATUS!",
RequiredBufferLength,
STATUS_BUFFER_TOO_SMALL);
FxVerifierDbgBreakPoint(pFxDriverGlobals);
return STATUS_BUFFER_TOO_SMALL;
}
if (nullptr == QueryBuffer) {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"NULL query buffer for file object query, %!STATUS!",
STATUS_BUFFER_TOO_SMALL);
FxVerifierDbgBreakPoint(pFxDriverGlobals);
return STATUS_INVALID_PARAMETER;
}
PWDFP_FILEOBJECT_INTERFACE FileObjectInterface =
reinterpret_cast<PWDFP_FILEOBJECT_INTERFACE>(QueryBuffer);
//
// Check the struct version (require an exact match for a private DDI)
//
if (FileObjectInterface->Size != RequiredBufferLength) {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"Wrong struct version provided for file object query, "
"%!STATUS!",
STATUS_INVALID_PARAMETER);
FxVerifierDbgBreakPoint(pFxDriverGlobals);
return STATUS_INVALID_PARAMETER;
}
FileObjectInterface->WdfpFileObjectIncrementProcessKeepAliveCount =
WDFEXPORT(WdfFileObjectIncrementProcessKeepAliveCount);
FileObjectInterface->WdfpFileObjectDecrementProcessKeepAliveCount =
WDFEXPORT(WdfFileObjectDecrementProcessKeepAliveCount);
return STATUS_SUCCESS;
}
return STATUS_NOT_FOUND;
}
} // extern "C"

View file

@ -0,0 +1,67 @@
//
// Copyright (C) Microsoft. All rights reserved.
//
#include "fxobjectpch.hpp"
#include "fxldrum.h"
extern "C" {
VOID
FxFreeAllocatedMdlsDebugInfo(
__in FxDriverGlobalsDebugExtension* DebugExtension
)
{
UNREFERENCED_PARAMETER(DebugExtension);
//DO_NOTHING()
}
_Must_inspect_result_
BOOLEAN
FX_DRIVER_GLOBALS::IsCorrectVersionRegistered(
_In_ PCUNICODE_STRING /*ServiceKeyName*/
)
{
return TRUE; // Then it won't even call the next method
}
VOID
FX_DRIVER_GLOBALS::RegisterClientVersion(
_In_ PCUNICODE_STRING ServiceKeyName
)
{
UNREFERENCED_PARAMETER(ServiceKeyName);
ASSERTMSG("Not implemented for UMDF\n", FALSE);
}
_Must_inspect_result_
BOOLEAN
FX_DRIVER_GLOBALS::IsVersionGreaterThanOrEqualTo(
__in ULONG Major,
__in ULONG Minor
)
{
if ((WdfBindInfo->Version.Major > Major) ||
(WdfBindInfo->Version.Major == Major &&
WdfBindInfo->Version.Minor >= Minor)) {
return TRUE;
}
else {
return FALSE;
}
}
}
_Must_inspect_result_
BOOLEAN
FX_DRIVER_GLOBALS::IsDebuggerAttached(
VOID
)
{
//
// COnvert the returned BOOL into BOOLEAN
//
return (IsDebuggerPresent() != FALSE);
}

View file

@ -0,0 +1,710 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
wdfpool.c
Abstract:
This module implements the driver frameworks pool routines.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxobjectpch.hpp"
// We use DoTraceMessage
extern "C" {
#if defined(EVENT_TRACING)
#include "wdfpool.tmh"
#endif
}
BOOLEAN
FxIsPagedPoolType(
__in POOL_TYPE Type
)
/*++
Routine Description:
Return whether paged pool is specified by POOL_TYPE
Arguments:
Type - POOL_TYPE
Returns:
TRUE - Paged Pool,FALSE - Non-Paged Pool
--*/
{
//
// Cleaner than doing (Type & 0x01)
//
switch( Type & (~POOL_COLD_ALLOCATION) ) {
case PagedPool:
case PagedPoolCacheAligned:
return TRUE;
default:
return FALSE;
}
}
PVOID
FxPoolAllocator(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PFX_POOL Pool,
__in POOL_TYPE Type,
__in SIZE_T Size,
__in ULONG Tag,
__in PVOID Caller
)
/*++
Routine Description:
Allocates system pool tracked in a FX_POOL tracking object.
Arguments:
Pool - FX_POOL object for tracking allocations
Type - POOL_TYPE from ntddk.h
Size - Size in bytes of the allocation
Tag - Caller specified additional tag value for debugging/tracing
Caller - Caller's address
Returns:
NULL - Could not allocate pool
!NULL - Pointer to pool of minimum Size bytes
Remarks:
In kernel mode this routine conditionally adds header on top iff the
allocation size is < PAGE_SIZE. If the allocation size is >= PAGE_SIZE
the caller would expect a page aligned pointer, hence no header is added.
In addition, ExAllocatePool* functions guarantee that a buffer < PAGE_SIZE
doesn't straddle page boundary. This allows FxPoolFree to determine whether
a header is added to buffer or not based on whether the pointer passed in
is page aligned or not. (In addition, when pool tracking is ON, this
routine adds pool tracking header based on whether additional space for this
header will push the buffer size beyond PAGE_SIZE, which is an optimization.)
Such guarantees are not available with user mode allocator, hence in case
of user mode we always add the header. (In user mode a buffer < PAGE_SIZE
can straddle page boundary and the pointer returned may happen to be page
aligned, causing FxPoolFree to free the wrong pointer.)
--*/
{
PVOID ptr;
PCHAR pTrueBase;
PFX_POOL_TRACKER pTracker;
PFX_POOL_HEADER pHeader;
NTSTATUS status;
SIZE_T allocationSize;
ptr = NULL;
//
// Allocations of a zero request size are invalid.
//
// Besides, with a zero request size, special pool could place us
// at the end of a page, and adding our header would give us a page
// aligned address, which is ambiguous with large allocations.
//
if (Size == 0) {
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL,
"Invalid Allocation Size of 0 requested");
FxVerifierDbgBreakPoint(FxDriverGlobals);
return NULL;
}
if (FxDriverGlobals->IsPoolTrackingOn()) {
if (FxDriverGlobals->FxVerifierOn &&
(FxDriverGlobals->WdfVerifierAllocateFailCount != 0xFFFFFFFF)) {
//
// If the registry key VerifierAllocateFailCount is set, all allocations
// after the specified count are failed.
//
// This is a brutal test, but also ensures the framework can cleanup
// under low memory conditions as well.
//
if (FxDriverGlobals->WdfVerifierAllocateFailCount == 0) {
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL,
"Allocation Fail Count exceeded");
return NULL;
}
// Decrement the count
InterlockedDecrement(&FxDriverGlobals->WdfVerifierAllocateFailCount);
}
//
// (Kernel mode only) PAGE_SIZE or greater allocations can not have our
// header since this would break the system allocators contract
// that PAGE_SIZE or greater allocations start on a whole page boundary
//
//
// For allocations less than a page size that will not fit with our
// header, we round up to a non-tracked whole page allocation so
// we don't burn two pages for this boundary condition.
//
// This if is the same as
// Size + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE >= PAGE_SIZE
// BUT with no integer overflow
if (Mx::IsKM() &&
(Size >= PAGE_SIZE - sizeof(FX_POOL_TRACKER) - FX_POOL_HEADER_SIZE)
) {
//
// Ensure that we ask for at least a page to ensure the
// allocation starts on a whole page.
//
if (Size < PAGE_SIZE) {
Size = PAGE_SIZE;
}
ptr = MxMemory::MxAllocatePoolWithTag(Type, Size, Tag);
//
// The current system allocator returns paged aligned memory
// in this case, which we rely on to detect whether our header
// is present or not in FxPoolFree
//
ASSERT(((ULONG_PTR)ptr & (PAGE_SIZE-1)) == 0);
}
else {
status = RtlSIZETAdd(Size,
sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE,
&allocationSize);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL,
"overflow: allocation tracker (%d) + header (%d) + pool "
"request (%I64d)", sizeof(FX_POOL_TRACKER),
FX_POOL_HEADER_SIZE, Size);
return NULL;
}
pTrueBase = (PCHAR) MxMemory::MxAllocatePoolWithTag(
Type,
allocationSize,
Tag
);
if (pTrueBase == NULL) {
return NULL;
}
pTracker = (PFX_POOL_TRACKER) pTrueBase;
pHeader = WDF_PTR_ADD_OFFSET_TYPE(pTrueBase,
sizeof(FX_POOL_TRACKER),
PFX_POOL_HEADER);
pHeader->Base = pTrueBase;
pHeader->FxDriverGlobals = FxDriverGlobals;
//
// Adjust the pointer to what we return to the driver
//
ptr = &pHeader->AllocationStart[0];
//
// Ensure the pointer we are returning is aligned on the proper
// boundary.
//
ASSERT( ((ULONG_PTR) ptr & (MEMORY_ALLOCATION_ALIGNMENT-1)) == 0);
//
// Ensure the pointer is still not page aligned after
// our adjustment. Otherwise the pool free code will
// get confused and call ExFreePool on the wrong ptr.
//
if (Mx::IsKM()) {
ASSERT(((ULONG_PTR)ptr & (PAGE_SIZE-1)) != 0 );
}
//
// We must separate paged and non-paged pool since
// the lock held differs as to whether we can accept
// page faults and block in the allocator.
//
if (FxIsPagedPoolType(Type)) {
//
// Format and insert the Tracker in the PagedHeader list.
//
FxPoolInsertPagedAllocateTracker(Pool,
pTracker,
Size,
Tag,
Caller);
}
else {
//
// Format and insert the Tracker in the NonPagedHeader list.
//
FxPoolInsertNonPagedAllocateTracker(Pool,
pTracker,
Size,
Tag,
Caller);
}
}
}
else {
//
// No pool tracking...
//
if ((Size < PAGE_SIZE) || Mx::IsUM())
{
//
// (Kernel mode only) See if adding our header promotes us past a
// page boundary
//
status = RtlSIZETAdd(Size,
FX_POOL_HEADER_SIZE,
&allocationSize);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL,
"overflow: header + pool request (%I64d)", Size);
return NULL;
}
}
else {
//
// Is the raw request for alloc >= PAGE_SIZE ? Then just use it.
//
allocationSize = Size;
}
//
// Is cooked size for alloc >= PAGE_SIZE ? Then just do it.
//
if (allocationSize >= PAGE_SIZE && Mx::IsKM())
{
//
// Important to use allocationSize so that we get a page aligned
// allocation so that we know to just free the memory pointer as is
// when it is freed.
//
ptr = MxMemory::MxAllocatePoolWithTag(Type, allocationSize, Tag);
ASSERT(((ULONG_PTR)ptr & (PAGE_SIZE-1)) == 0);
}
else {
pTrueBase = (PCHAR) MxMemory::MxAllocatePoolWithTag(Type,
allocationSize,
Tag);
if (pTrueBase != NULL) {
pHeader = (PFX_POOL_HEADER) pTrueBase;
pHeader->Base = pTrueBase;
pHeader->FxDriverGlobals = FxDriverGlobals;
ptr = &pHeader->AllocationStart[0];
if (Mx::IsKM()) {
//
// Ensure the pointer is still not page aligned after
// our adjustment. Otherwise the pool free code will
// get confused and call ExFreePool on the wrong ptr.
//
ASSERT( ((ULONG_PTR)ptr & (PAGE_SIZE-1)) != 0 );
}
}
}
}
return ptr;
}
VOID
FxPoolFree(
__in_xcount(ptr is at an offset from AllocationStart) PVOID ptr
)
/*++
Routine Description:
Release tracked pool
Arguments:
Pool - FX_POOL object allocation is tracked in
ptr - Pointer to pool to release
Returns:
Remarks:
In kernel mode the pointer passed in may or may not have a header before
it depending upon whether the pointer is page aligned or not.
In user mode the pointer passed in always has a header before it. See
remarks for FxPoolAllocator.
--*/
{
PFX_POOL_HEADER pHeader;
PVOID pTrueBase;
PFX_POOL_TRACKER pTracker;
//
// Null pointers are always bad
//
if( ptr == NULL ) {
ASSERTMSG("NULL pointer freed\n", FALSE);
Mx::MxBugCheckEx(WDF_VIOLATION,
WDF_REQUIRED_PARAMETER_IS_NULL,
(ULONG_PTR)NULL,
(ULONG_PTR)_ReturnAddress(),
(ULONG_PTR)NULL
);
}
//
// (Kernel mode only) If ptr is aligned on page boundry (indicates
// it was > PAGE_SIZE allocation)
// then there will be no common header...just free the memory without
// further processing.
//
if( Mx::IsKM() && ( ((ULONG_PTR)ptr & (PAGE_SIZE-1)) == 0 ) ) {
MxMemory::MxFreePool(ptr);
return;
}
//
// Ensure the pointer we are returning is aligned on the proper
// boundary.
//
ASSERT( ((ULONG_PTR) ptr & (MEMORY_ALLOCATION_ALIGNMENT-1)) == 0);
//
// Dereference the Common header which all <PAGE_SIZE allcations will have.
//
pHeader = CONTAINING_RECORD(ptr, FX_POOL_HEADER, AllocationStart);
pTrueBase = pHeader->Base;
//
// If PoolTracker is on then Base must point to it's header.
// This is currently the only option for this area...may change later.
//
if (pHeader->FxDriverGlobals->IsPoolTrackingOn()) {
pTracker = (PFX_POOL_TRACKER) pTrueBase;
if (FxIsPagedPoolType(pTracker->PoolType)) {
//
// Decommission this Paged Allocation tracker
//
FxPoolRemovePagedAllocateTracker(pTracker);
}
else {
//
// Decommission this NonPaged Allocation tracker
//
FxPoolRemoveNonPagedAllocateTracker(pTracker);
}
//
// Scrub the pool to zeros to catch destructed objects
// by NULL'ing the v-table ptr
//
RtlZeroMemory(pTracker, pTracker->Size + sizeof(FX_POOL_TRACKER));
}
MxMemory::MxFreePool(pTrueBase);
}
NTSTATUS
FxPoolDump(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PFX_POOL Pool
)
/*++
Routine Description:
Dump the FX_POOL tracking object
Arguments:
Pool - FX_POOL object for tracking allocations
Returns:
STATUS_SUCCESS
--*/
{
PFX_POOL_TRACKER pTracker;
PLIST_ENTRY ple;
KIRQL oldIrql;
BOOLEAN leak;
//
// Dump usage information
//
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"FxPoolDump: "
"NonPagedBytes %I64d, PagedBytes %I64d, "
"NonPagedAllocations %d, PagedAllocations %d,"
"PeakNonPagedBytes %I64d, PeakPagedBytes %I64d,"
"FxPoolDump: PeakNonPagedAllocations %d, PeakPagedAllocations %d",
Pool->NonPagedBytes, Pool->PagedBytes,
Pool->NonPagedAllocations, Pool->PagedAllocations,
Pool->PeakNonPagedBytes, Pool->PeakPagedBytes,
Pool->PeakNonPagedAllocations, Pool->PeakPagedAllocations
);
leak = FALSE;
//
// Check paged pool for leaks
//
Pool->PagedLock.Acquire();
for (ple = Pool->PagedHead.Flink; ple != &Pool->PagedHead; ple = ple->Flink) {
pTracker = CONTAINING_RECORD(ple, FX_POOL_TRACKER, Link);
// Leaker
leak = TRUE;
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"FX_POOL 0x%p leaked paged memory alloc 0x%p (tracking block %p)",
Pool, pTracker + 1, pTracker);
}
Pool->PagedLock.Release();
//
// Check non-paged pool for leaks
//
Pool->NonPagedLock.Acquire(&oldIrql);
for (ple = Pool->NonPagedHead.Flink;
ple != &Pool->NonPagedHead;
ple = ple->Flink) {
pTracker = CONTAINING_RECORD(ple, FX_POOL_TRACKER, Link );
// Leaker
leak = TRUE;
DoTraceLevelMessage(
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
"FX_POOL 0x%p leaked non-paged memory alloc 0x%p (tracking block %p)",
Pool, pTracker+1, pTracker);
}
Pool->NonPagedLock.Release(oldIrql);
if (leak) {
FxVerifierDbgBreakPoint(FxDriverGlobals);
return STATUS_MORE_ENTRIES;
}
else {
return STATUS_SUCCESS;
}
}
_Must_inspect_result_
NTSTATUS
FxPoolInitialize(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PFX_POOL Pool
)
/*++
Routine Description:
Initialize the FX_POOL tracking object
Arguments:
Pool - FX_POOL object for tracking allocations
Returns:
STATUS_SUCCESS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPOOL,
"Initializing Pool 0x%p, Tracking %d",
Pool, FxDriverGlobals->IsPoolTrackingOn());
Pool->NonPagedLock.Initialize();
InitializeListHead( &Pool->NonPagedHead );
status = Pool->PagedLock.Initialize();
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL,
"Initializing paged lock failed for Pool 0x%p, "
"status %!STATUS!",
Pool, status);
goto exit;
}
InitializeListHead( &Pool->PagedHead );
// Pool usage information
Pool->NonPagedBytes = 0;
Pool->PagedBytes = 0;
Pool->NonPagedAllocations = 0;
Pool->PagedAllocations = 0;
Pool->PeakNonPagedBytes = 0;
Pool->PeakPagedBytes = 0;
Pool->PeakNonPagedAllocations = 0;
Pool->PeakPagedAllocations = 0;
exit:
if (!NT_SUCCESS(status)) {
//
// We disable pool tracking if we could not initialize the locks needed
//
// If we don't do this we would need another flag to make FxPoolDestroy
// not access the locks
//
FxDriverGlobals->FxPoolTrackingOn = FALSE;
}
//
// FxPoolDestroy will always be called even if we fail FxPoolInitialize
//
// FxPoolDestroy will uninitialize locks both in success and failure
// cases
//
return status;
}
VOID
FxPoolDestroy(
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
__in PFX_POOL Pool
)
/*++
Routine Description:
Destroy the FX_POOL tracking object
Arguments:
Pool - FX_POOL object for tracking allocations
Returns:
STATUS_SUCCESS
--*/
{
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPOOL,
"Destroying Pool 0x%p", Pool);
if (FxDriverGlobals->IsPoolTrackingOn()) {
FxPoolDump(FxDriverGlobals, Pool);
#if FX_CORE_MODE==FX_CORE_KERNEL_MODE
FxMdlDump(FxDriverGlobals);
#endif
//
// We don't automatically free memory items since we don't
// know what they contain, and who is still referencing them.
//
}
Pool->PagedLock.Uninitialize();
Pool->NonPagedLock.Uninitialize();
return;
}
_Must_inspect_result_
NTSTATUS
FxPoolPackageInitialize(
__in PFX_DRIVER_GLOBALS FxDriverGlobals
)
/*++
Routine Description:
Initialize the pool support package at startup time.
This must be called before the first allocation.
Arguments:
FxDriverGlobals - DriverGlobals
Returns:
STATUS_SUCCESS
--*/
{
return FxPoolInitialize(FxDriverGlobals, &FxDriverGlobals->FxPoolFrameworks);
}
VOID
FxPoolPackageDestroy(
__in PFX_DRIVER_GLOBALS FxDriverGlobals
)
/*++
Routine Description:
Destroy the pool support package at unload time
This must be after the last free
Arguments:
FxDriverGlobals - Driver's globals
Returns:
STATUS_SUCCESS
--*/
{
FxPoolDestroy(FxDriverGlobals, &FxDriverGlobals->FxPoolFrameworks);
return;
}