mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 11:21:51 +00:00
[WDF] Add Windows Driver Framework files
Takern from Microsoft GitHub repo:
d9c6040fe9
Licensed under MIT
This commit is contained in:
parent
545df81502
commit
8a978a179f
475 changed files with 285099 additions and 0 deletions
285
sdk/lib/drivers/wdf/shared/support/fxcollection.cpp
Normal file
285
sdk/lib/drivers/wdf/shared/support/fxcollection.cpp
Normal file
|
@ -0,0 +1,285 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxCollection.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a simple collection class to operate on
|
||||
objects derived from FxObject.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
FxCollectionInternal::FxCollectionInternal(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
m_Count = 0;
|
||||
InitializeListHead(&m_ListHead);
|
||||
}
|
||||
|
||||
FxCollectionInternal::~FxCollectionInternal(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
VOID
|
||||
FxCollectionInternal::Clear(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
while (!IsListEmpty(&m_ListHead)) {
|
||||
Remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxCollectionInternal::Count(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_Count;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxCollectionInternal::Add(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in FxObject *Item
|
||||
)
|
||||
{
|
||||
FxCollectionEntry *pNode;
|
||||
|
||||
pNode = AllocateEntry(FxDriverGlobals);
|
||||
|
||||
if (pNode != NULL) {
|
||||
InsertTailList(&m_ListHead, &pNode->m_ListEntry);
|
||||
|
||||
AddEntry(pNode, Item);
|
||||
}
|
||||
|
||||
return pNode != NULL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxCollectionEntry*
|
||||
FxCollectionInternal::FindEntry(
|
||||
__in ULONG Index
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY ple;
|
||||
ULONG i;
|
||||
|
||||
if (Index >= m_Count) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0, ple = m_ListHead.Flink;
|
||||
ple != &m_ListHead;
|
||||
ple = ple->Flink, i++) {
|
||||
if (i != Index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxCollectionEntry*
|
||||
FxCollectionInternal::FindEntryByObject(
|
||||
__in FxObject* Object
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY ple;
|
||||
|
||||
for (ple = m_ListHead.Flink; ple != &m_ListHead; ple = ple->Flink) {
|
||||
FxCollectionEntry* pNode;
|
||||
|
||||
pNode = CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry);
|
||||
if (pNode->m_Object == Object) {
|
||||
return pNode;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxCollectionInternal::Remove(
|
||||
__in ULONG Index
|
||||
)
|
||||
{
|
||||
FxCollectionEntry *pNode;
|
||||
|
||||
pNode = FindEntry(Index);
|
||||
|
||||
if (pNode != NULL) {
|
||||
return RemoveEntry(pNode);
|
||||
}
|
||||
else {
|
||||
return STATUS_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxCollectionInternal::RemoveItem(
|
||||
__in FxObject* Item
|
||||
)
|
||||
{
|
||||
FxCollectionEntry* pNode;
|
||||
|
||||
pNode = FindEntryByObject(Item);
|
||||
|
||||
if (pNode != NULL) {
|
||||
return RemoveEntry(pNode);
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxCollectionInternal::CleanupEntry(
|
||||
__in FxCollectionEntry* Entry
|
||||
)
|
||||
{
|
||||
RemoveEntryList(&Entry->m_ListEntry);
|
||||
delete Entry;
|
||||
|
||||
m_Count--;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxCollectionInternal::RemoveEntry(
|
||||
__in FxCollectionEntry* Entry
|
||||
)
|
||||
{
|
||||
CleanupEntryObject(Entry->m_Object);
|
||||
CleanupEntry(Entry);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxObject*
|
||||
FxCollectionInternal::GetItem(
|
||||
__in ULONG Index
|
||||
)
|
||||
|
||||
{
|
||||
FxCollectionEntry* pNode;
|
||||
|
||||
pNode = FindEntry(Index);
|
||||
if (pNode != NULL) {
|
||||
return pNode->m_Object;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxObject*
|
||||
FxCollectionInternal::GetFirstItem(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (IsListEmpty(&m_ListHead)) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return CONTAINING_RECORD(m_ListHead.Flink,
|
||||
FxCollectionEntry,
|
||||
m_ListEntry)->m_Object;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxObject*
|
||||
FxCollectionInternal::GetLastItem(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (IsListEmpty(&m_ListHead)) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return CONTAINING_RECORD(m_ListHead.Blink,
|
||||
FxCollectionEntry,
|
||||
m_ListEntry)->m_Object;
|
||||
}
|
||||
}
|
||||
|
||||
FxCollection::FxCollection(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxNonPagedObject(FX_TYPE_COLLECTION, sizeof(FxCollection), FxDriverGlobals)
|
||||
{
|
||||
}
|
||||
|
||||
FxCollection::FxCollection(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in WDFTYPE Type,
|
||||
__in USHORT Size
|
||||
) : FxNonPagedObject(Type, Size, FxDriverGlobals)
|
||||
{
|
||||
}
|
||||
|
||||
FxCollection::~FxCollection(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
VOID
|
||||
FxCollection::StealCollection(
|
||||
__in FxCollection* Collection
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY ple;
|
||||
|
||||
m_Count = Collection->m_Count;
|
||||
Collection->m_Count = 0;
|
||||
|
||||
while (!IsListEmpty(&Collection->m_ListHead)) {
|
||||
FxCollectionEntry* pEntry;
|
||||
|
||||
ple = RemoveHeadList(&Collection->m_ListHead);
|
||||
pEntry = CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry);
|
||||
|
||||
//
|
||||
// When we are tracking reference tags, the tag associated with the
|
||||
// reference matters. When we added the object to Collection, we used
|
||||
// that pointer as the tag. We must remove that tag and readd the
|
||||
// reference using the this value as a tag.
|
||||
//
|
||||
// Obviously, order is important here. Add the reference first so that
|
||||
// we know the relese will make the object go away.
|
||||
//
|
||||
pEntry->m_Object->ADDREF(this);
|
||||
pEntry->m_Object->RELEASE(Collection);
|
||||
|
||||
InsertTailList(&m_ListHead, ple);
|
||||
}
|
||||
}
|
||||
|
384
sdk/lib/drivers/wdf/shared/support/fxcollectionapi.cpp
Normal file
384
sdk/lib/drivers/wdf/shared/support/fxcollectionapi.cpp
Normal file
|
@ -0,0 +1,384 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxCollectionApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the "C" interface to the collection object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxCollectionApi.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern the entire file
|
||||
//
|
||||
extern "C" {
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfCollectionCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES CollectionAttributes,
|
||||
__out
|
||||
WDFCOLLECTION *Collection
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxCollection *pCollection;
|
||||
WDFCOLLECTION hCol;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
//
|
||||
// Get the parent's globals if it is present
|
||||
//
|
||||
if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(
|
||||
pFxDriverGlobals, CollectionAttributes))) {
|
||||
FxObject* pParent;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
CollectionAttributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
}
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, Collection);
|
||||
|
||||
*Collection = NULL;
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, CollectionAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
pCollection = new (pFxDriverGlobals, CollectionAttributes)
|
||||
FxCollection(pFxDriverGlobals);
|
||||
|
||||
if (pCollection != NULL) {
|
||||
status = pCollection->Commit(CollectionAttributes, (WDFOBJECT*)&hCol);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*Collection = hCol;
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"Could not create collection object: %!STATUS!",
|
||||
status);
|
||||
|
||||
pCollection->DeleteFromFailedCreate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"Could not create collection object: "
|
||||
"STATUS_INSUFFICIENT_RESOURCES" );
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
ULONG
|
||||
WDFEXPORT(WdfCollectionGetCount)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOLLECTION Collection
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxCollection *pCollection;
|
||||
KIRQL irql;
|
||||
ULONG count;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Collection,
|
||||
FX_TYPE_COLLECTION,
|
||||
(PVOID *)&pCollection);
|
||||
|
||||
pCollection->Lock(&irql);
|
||||
count = pCollection->Count();
|
||||
pCollection->Unlock(irql);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfCollectionAdd)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOLLECTION Collection,
|
||||
__in
|
||||
WDFOBJECT Object
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxCollection *pCollection;
|
||||
FxObject *pObject;
|
||||
NTSTATUS status;
|
||||
KIRQL irql;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Collection,
|
||||
FX_TYPE_COLLECTION,
|
||||
(PVOID*) &pCollection,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxObjectHandleGetPtr(pFxDriverGlobals,
|
||||
Object,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*) &pObject);
|
||||
|
||||
pCollection->Lock(&irql);
|
||||
status = pCollection->Add(pObject) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
||||
pCollection->Unlock(irql);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfCollectionRemoveItem)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOLLECTION Collection,
|
||||
__in
|
||||
ULONG Index
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxCollection* pCollection;
|
||||
FxCollectionEntry* pEntry;
|
||||
FxObject* pObject;
|
||||
NTSTATUS status;
|
||||
KIRQL irql;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Collection,
|
||||
FX_TYPE_COLLECTION,
|
||||
(PVOID*) &pCollection,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
pCollection->Lock(&irql);
|
||||
|
||||
pEntry = pCollection->FindEntry(Index);
|
||||
|
||||
if (pEntry != NULL) {
|
||||
pObject = pEntry->m_Object;
|
||||
pCollection->CleanupEntry(pEntry);
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
pObject = NULL;
|
||||
status = STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
pCollection->Unlock(irql);
|
||||
|
||||
if (pObject != NULL) {
|
||||
pCollection->CleanupEntryObject(pObject);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"Index %d is not valid in WDFCOLLECTION %p (count is %d), %!STATUS!",
|
||||
Index, Collection, pCollection->Count(), status);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfCollectionRemove)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOLLECTION Collection,
|
||||
__in
|
||||
WDFOBJECT Item
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxCollection *pCollection;
|
||||
FxCollectionEntry *pEntry;
|
||||
FxObject* pObject;
|
||||
NTSTATUS status;
|
||||
KIRQL irql;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Collection,
|
||||
FX_TYPE_COLLECTION,
|
||||
(PVOID*) &pCollection,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxObjectHandleGetPtr(pFxDriverGlobals,
|
||||
Item,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*) &pObject);
|
||||
|
||||
pCollection->Lock(&irql);
|
||||
|
||||
pEntry = pCollection->FindEntryByObject(pObject);
|
||||
|
||||
if (pEntry != NULL) {
|
||||
pCollection->CleanupEntry(pEntry);
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
pObject = NULL;
|
||||
status = STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
pCollection->Unlock(irql);
|
||||
|
||||
if (pObject != NULL) {
|
||||
pCollection->CleanupEntryObject(pObject);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFOBJECT %p not in WDFCOLLECTION %p, %!STATUS!",
|
||||
Item, Collection, status);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
}
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFOBJECT
|
||||
WDFEXPORT(WdfCollectionGetItem)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOLLECTION Collection,
|
||||
__in
|
||||
ULONG Index
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxCollection *pCollection;
|
||||
FxObject *pObject;
|
||||
WDFOBJECT hObject;
|
||||
KIRQL irql;
|
||||
|
||||
hObject = NULL;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Collection,
|
||||
FX_TYPE_COLLECTION,
|
||||
(PVOID*) &pCollection);
|
||||
|
||||
pCollection->Lock(&irql);
|
||||
pObject = pCollection->GetItem(Index);
|
||||
pCollection->Unlock(irql);
|
||||
|
||||
if (pObject == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pObject->GetObjectHandle();
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFOBJECT
|
||||
WDFEXPORT(WdfCollectionGetFirstItem)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOLLECTION Collection
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxCollection *pCollection;
|
||||
FxObject* pObject;
|
||||
KIRQL irql;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Collection,
|
||||
FX_TYPE_COLLECTION,
|
||||
(PVOID*) &pCollection);
|
||||
|
||||
pCollection->Lock(&irql);
|
||||
pObject = pCollection->GetFirstItem();
|
||||
pCollection->Unlock(irql);
|
||||
|
||||
if (pObject != NULL) {
|
||||
return pObject->GetObjectHandle();
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
WDFOBJECT
|
||||
WDFEXPORT(WdfCollectionGetLastItem)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFCOLLECTION Collection
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
FxCollection *pCollection;
|
||||
FxObject* pObject;
|
||||
KIRQL irql;
|
||||
|
||||
FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
|
||||
Collection,
|
||||
FX_TYPE_COLLECTION,
|
||||
(PVOID*) &pCollection);
|
||||
|
||||
pCollection->Lock(&irql);
|
||||
pObject = pCollection->GetLastItem();
|
||||
pCollection->Unlock(irql);
|
||||
|
||||
if (pObject != NULL) {
|
||||
return pObject->GetObjectHandle();
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C" of entire file
|
155
sdk/lib/drivers/wdf/shared/support/fxdeviceinterface.cpp
Normal file
155
sdk/lib/drivers/wdf/shared/support/fxdeviceinterface.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceInterface.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the device interface object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceInterface.tmh"
|
||||
}
|
||||
|
||||
FxDeviceInterface::FxDeviceInterface(
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for the object. Initializes all fields
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
RtlZeroMemory(&m_InterfaceClassGUID, sizeof(m_InterfaceClassGUID));
|
||||
|
||||
RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName));
|
||||
RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString));
|
||||
|
||||
m_Entry.Next = NULL;
|
||||
|
||||
m_State = FALSE;
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
||||
m_Device = NULL;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
FxDeviceInterface::~FxDeviceInterface()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for FxDeviceInterface. Cleans up any allocations previously
|
||||
allocated.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
// the device interface should be off now
|
||||
ASSERT(m_State == FALSE);
|
||||
|
||||
// should no longer be in any list
|
||||
ASSERT(m_Entry.Next == NULL);
|
||||
|
||||
if (m_ReferenceString.Buffer != NULL) {
|
||||
FxPoolFree(m_ReferenceString.Buffer);
|
||||
RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString));
|
||||
}
|
||||
|
||||
if (m_SymbolicLinkName.Buffer != NULL) {
|
||||
RtlFreeUnicodeString(&m_SymbolicLinkName);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceInterface::Initialize(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in CONST GUID* InterfaceGUID,
|
||||
__in_opt PCUNICODE_STRING ReferenceString
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Initializes the object with the interface GUID and optional reference string
|
||||
|
||||
Arguments:
|
||||
InterfaceGUID - GUID describing the interface
|
||||
|
||||
ReferenceString - string used to differentiate between 2 interfaces on the
|
||||
same PDO
|
||||
|
||||
Return Value:
|
||||
STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
|
||||
|
||||
--*/
|
||||
{
|
||||
RtlCopyMemory(&m_InterfaceClassGUID, InterfaceGUID, sizeof(GUID));
|
||||
|
||||
if (ReferenceString != NULL) {
|
||||
return FxDuplicateUnicodeString(FxDriverGlobals,
|
||||
ReferenceString,
|
||||
&m_ReferenceString);
|
||||
}
|
||||
else {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FxDeviceInterface::SetState(
|
||||
__in BOOLEAN State
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Sets the state of the device interface
|
||||
|
||||
Arguments:
|
||||
State - the state to set
|
||||
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
m_State = State;
|
||||
|
||||
//
|
||||
// Only set the state if the interface has been registered
|
||||
//
|
||||
if (m_SymbolicLinkName.Buffer != NULL) {
|
||||
Mx::MxSetDeviceInterfaceState(&m_SymbolicLinkName, m_State);
|
||||
}
|
||||
}
|
||||
|
400
sdk/lib/drivers/wdf/shared/support/fxdeviceinterfaceapi.cpp
Normal file
400
sdk/lib/drivers/wdf/shared/support/fxdeviceinterfaceapi.cpp
Normal file
|
@ -0,0 +1,400 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceInterfaceAPI.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the device interface object external APIs
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceInterfaceAPI.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// extern "C" the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceCreateDeviceInterface)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
CONST GUID *InterfaceClassGUID,
|
||||
__in_opt
|
||||
PCUNICODE_STRING ReferenceString
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Creates a device interface associated with the passed in device object
|
||||
|
||||
Arguments:
|
||||
Device - Handle which represents the device exposing the interface
|
||||
|
||||
InterfaceGUID - GUID describing the interface being exposed
|
||||
|
||||
ReferenceString - OPTIONAL string which allows the driver writer to
|
||||
distinguish between different exposed interfaces
|
||||
|
||||
Return Value:
|
||||
STATUS_SUCCESS or appropriate NTSTATUS code
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
SINGLE_LIST_ENTRY **ppPrev, *pCur;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDeviceInterface *pDeviceInterface;
|
||||
FxDevice *pDevice;
|
||||
FxPkgPnp* pPkgPnp;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (ReferenceString != NULL) {
|
||||
status = FxValidateUnicodeString(pFxDriverGlobals, ReferenceString);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (pDevice->IsLegacy()) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p is not a PNP device, device interface creation not "
|
||||
"allowed %!STATUS!", Device, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
pDeviceInterface = new(pFxDriverGlobals, PagedPool) FxDeviceInterface();
|
||||
|
||||
if (pDeviceInterface == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p DeviceInterface object creation failed, %!STATUS!",
|
||||
Device, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pDeviceInterface->Initialize(pFxDriverGlobals,
|
||||
InterfaceClassGUID,
|
||||
ReferenceString);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p, DeviceInterface object initialization failed, %!STATUS!",
|
||||
Device, status );
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
pPkgPnp = pDevice->m_PkgPnp;
|
||||
|
||||
pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals);
|
||||
|
||||
status = pDeviceInterface->Register(pDevice);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Insert into the end of the list
|
||||
//
|
||||
ppPrev = &pPkgPnp->m_DeviceInterfaceHead.Next;
|
||||
pCur = pPkgPnp->m_DeviceInterfaceHead.Next;
|
||||
while (pCur != NULL) {
|
||||
ppPrev = &pCur->Next;
|
||||
pCur = pCur->Next;
|
||||
}
|
||||
|
||||
*ppPrev = &pDeviceInterface->m_Entry;
|
||||
}
|
||||
|
||||
pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals);
|
||||
|
||||
Done:
|
||||
if (!NT_SUCCESS(status)) {
|
||||
delete pDeviceInterface;
|
||||
pDeviceInterface = NULL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfDeviceSetDeviceInterfaceState)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
CONST GUID *InterfaceClassGUID,
|
||||
__in_opt
|
||||
PCUNICODE_STRING RefString,
|
||||
__in
|
||||
BOOLEAN State
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PSINGLE_LIST_ENTRY ple;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxDevice* pDevice;
|
||||
FxPkgPnp* pPkgPnp;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RefString != NULL) {
|
||||
status = FxValidateUnicodeString(pFxDriverGlobals, RefString);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pDevice->IsLegacy()) {
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p is not a PNP device, device interfaces not allowed",
|
||||
Device);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
pPkgPnp = pDevice->m_PkgPnp;
|
||||
|
||||
pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// Iterate over the interfaces and see if we have a match
|
||||
//
|
||||
for (ple = pPkgPnp->m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
|
||||
FxDeviceInterface *pDI;
|
||||
|
||||
pDI = FxDeviceInterface::_FromEntry(ple);
|
||||
|
||||
if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) {
|
||||
if (RefString != NULL) {
|
||||
if ((RefString->Length == pDI->m_ReferenceString.Length)
|
||||
&&
|
||||
(RtlCompareMemory(RefString->Buffer,
|
||||
pDI->m_ReferenceString.Buffer,
|
||||
RefString->Length) == RefString->Length)) {
|
||||
//
|
||||
// They match, carry on
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
else {
|
||||
//
|
||||
// The ref strings do not match, continue on in the search
|
||||
// of the collection.
|
||||
//
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (pDI->m_ReferenceString.Length > 0) {
|
||||
//
|
||||
// Caller didn't specify a ref string but this interface has
|
||||
// one, continue on in the search through the collection.
|
||||
//
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the state and break out of the loop because we found our
|
||||
// interface.
|
||||
//
|
||||
pDI->SetState(State);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFDEVICE Device,
|
||||
__in
|
||||
CONST GUID* InterfaceClassGUID,
|
||||
__in_opt
|
||||
PCUNICODE_STRING RefString,
|
||||
__in
|
||||
WDFSTRING String
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the symbolic link value of the registered device interface.
|
||||
|
||||
Arguments:
|
||||
|
||||
|
||||
Return Value:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PSINGLE_LIST_ENTRY ple;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxDevice* pDevice;
|
||||
FxPkgPnp* pPkgPnp;
|
||||
FxString* pString;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Device,
|
||||
FX_TYPE_DEVICE,
|
||||
(PVOID*) &pDevice,
|
||||
&pFxDriverGlobals );
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (RefString != NULL) {
|
||||
status = FxValidateUnicodeString(pFxDriverGlobals, RefString);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (pDevice->IsLegacy()) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFDEVICE %p is not a PNP device, device interface creation not "
|
||||
"allowed %!STATUS!", Device, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
FxObjectHandleGetPtr(pFxDriverGlobals,
|
||||
String,
|
||||
FX_TYPE_STRING,
|
||||
(PVOID*) &pString);
|
||||
|
||||
pPkgPnp = pDevice->m_PkgPnp;
|
||||
|
||||
status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
|
||||
pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals);
|
||||
|
||||
//
|
||||
// Iterate over the interfaces and see if we have a match
|
||||
//
|
||||
for (ple = pPkgPnp->m_DeviceInterfaceHead.Next;
|
||||
ple != NULL;
|
||||
ple = ple->Next) {
|
||||
FxDeviceInterface *pDI;
|
||||
|
||||
pDI = FxDeviceInterface::_FromEntry(ple);
|
||||
|
||||
if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) {
|
||||
if (RefString != NULL) {
|
||||
if ((RefString->Length == pDI->m_ReferenceString.Length)
|
||||
&&
|
||||
(RtlCompareMemory(RefString->Buffer,
|
||||
pDI->m_ReferenceString.Buffer,
|
||||
RefString->Length) == RefString->Length)) {
|
||||
//
|
||||
// They match, carry on
|
||||
//
|
||||
DO_NOTHING();
|
||||
}
|
||||
else {
|
||||
//
|
||||
// The ref strings do not match, continue on in the search
|
||||
// of the collection.
|
||||
//
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (pDI->m_ReferenceString.Length > 0) {
|
||||
//
|
||||
// Caller didn't specify a ref string but this interface has
|
||||
// one, continue on in the search through the collection.
|
||||
//
|
||||
continue;
|
||||
}
|
||||
|
||||
status = pDI->GetSymbolicLinkName(pString);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // extern "C"
|
52
sdk/lib/drivers/wdf/shared/support/fxdevicetext.cpp
Normal file
52
sdk/lib/drivers/wdf/shared/support/fxdevicetext.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceText.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the device text object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
FxDeviceText::FxDeviceText(
|
||||
VOID
|
||||
) :
|
||||
m_Description(NULL),
|
||||
m_LocationInformation(NULL),
|
||||
m_LocaleId(0)
|
||||
{
|
||||
m_Entry.Next = NULL;
|
||||
}
|
||||
|
||||
FxDeviceText::~FxDeviceText()
|
||||
{
|
||||
ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
ASSERT(m_Entry.Next == NULL);
|
||||
|
||||
if (m_Description != NULL) {
|
||||
FxPoolFree(m_Description);
|
||||
m_Description = NULL;
|
||||
}
|
||||
|
||||
if (m_LocationInformation != NULL) {
|
||||
FxPoolFree(m_LocationInformation);
|
||||
m_LocationInformation = NULL;
|
||||
}
|
||||
}
|
1530
sdk/lib/drivers/wdf/shared/support/fxregistryapi.cpp
Normal file
1530
sdk/lib/drivers/wdf/shared/support/fxregistryapi.cpp
Normal file
File diff suppressed because it is too large
Load diff
66
sdk/lib/drivers/wdf/shared/support/fxregkey.cpp
Normal file
66
sdk/lib/drivers/wdf/shared/support/fxregkey.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
//
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#if defined(EVENT_TRACING)
|
||||
#include "FxRegKey.tmh"
|
||||
#endif
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRegKey::_VerifyMultiSzString(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PCUNICODE_STRING RegValueName,
|
||||
__in_bcount(DataLength) PWCHAR DataString,
|
||||
__in ULONG DataLength
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
This static function checks the input buffer to verify that it contains
|
||||
a multi-sz string with a double-NULL termination at the end of the buffer.
|
||||
|
||||
Arguments:
|
||||
DataString - buffer containing multi-sz strings. If there are no strings
|
||||
in the buffer, the buffer should at least contain two UNICODE_NULL
|
||||
characters.
|
||||
|
||||
DataLength - the size in bytes of the input buffer.
|
||||
|
||||
Return Value:
|
||||
STATUS_OBJECT_TYPE_MISMATCH - if the the data buffer is off odd-length,
|
||||
or it doesnt end with two UNICODE_NULL characters.
|
||||
|
||||
STATUS_SUCCESS - if the buffer contains valid multi-sz strings.
|
||||
|
||||
--*/
|
||||
{
|
||||
ULONG numChars;
|
||||
|
||||
if ((DataLength % 2) != 0) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"Reg value name %wZ, DataLength %d, Data buffer length is invalid, "
|
||||
"STATUS_OBJECT_TYPE_MISMATCH",
|
||||
RegValueName, DataLength);
|
||||
return STATUS_OBJECT_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
numChars = DataLength / sizeof(WCHAR);
|
||||
if (numChars < 2 ||
|
||||
DataString[numChars-1] != UNICODE_NULL ||
|
||||
DataString[numChars-2] != UNICODE_NULL) {
|
||||
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"Read value name %wZ, DataLength %d, Data buffer from registry does not "
|
||||
"have double NULL terminal chars, STATUS_OBJECT_TYPE_MISMATCH",
|
||||
RegValueName, DataLength);
|
||||
return STATUS_OBJECT_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
340
sdk/lib/drivers/wdf/shared/support/fxrequestbuffer.cpp
Normal file
340
sdk/lib/drivers/wdf/shared/support/fxrequestbuffer.cpp
Normal file
|
@ -0,0 +1,340 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRequestBuffer.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a memory union object
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxRequestBuffer.tmh"
|
||||
}
|
||||
|
||||
FxRequestBuffer::FxRequestBuffer(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
DataType = FxRequestBufferUnspecified;
|
||||
RtlZeroMemory(&u, sizeof(u));
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxRequestBuffer::ValidateMemoryDescriptor(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PWDF_MEMORY_DESCRIPTOR Descriptor,
|
||||
__in ULONG Flags
|
||||
)
|
||||
{
|
||||
IFxMemory* pMemory;
|
||||
NTSTATUS status;
|
||||
|
||||
if (Descriptor == NULL) {
|
||||
if (Flags & MemoryDescriptorNullAllowed) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"A NULL Descriptor is not allowed");
|
||||
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// For each type, check to see if the buffer is non NULL and err out if the
|
||||
// calller considers this an error. If the buffer is NULL, but a length
|
||||
// was specified, this is considered an error.
|
||||
//
|
||||
switch (Descriptor->Type) {
|
||||
case WdfMemoryDescriptorTypeBuffer:
|
||||
if (Descriptor->u.BufferType.Buffer == NULL) {
|
||||
if ((Flags & MemoryDescriptorNoBufferAllowed) == 0) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"A NULL Buffer is not allowed");
|
||||
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
else if (Descriptor->u.BufferType.Length != 0) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"Buffer is NULL, but a length (0x%x) is specified",
|
||||
Descriptor->u.BufferType.Length);
|
||||
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
SetBuffer(Descriptor->u.BufferType.Buffer,
|
||||
Descriptor->u.BufferType.Length);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
break;
|
||||
|
||||
case WdfMemoryDescriptorTypeMdl:
|
||||
if (Descriptor->u.MdlType.Mdl == NULL) {
|
||||
if ((Flags & MemoryDescriptorNoBufferAllowed) == 0) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"A NULL MDL is not allowed");
|
||||
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
else if (Descriptor->u.MdlType.BufferLength != 0) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"MDL is NULL, but a length (0x%x) is specified",
|
||||
Descriptor->u.MdlType.BufferLength);
|
||||
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
SetMdl(Descriptor->u.MdlType.Mdl, Descriptor->u.MdlType.BufferLength);
|
||||
status = STATUS_SUCCESS;
|
||||
break;
|
||||
|
||||
case WdfMemoryDescriptorTypeHandle:
|
||||
pMemory = NULL;
|
||||
if (Descriptor->u.HandleType.Memory == NULL) {
|
||||
if (Flags & MemoryDescriptorNoBufferAllowed) {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"A NULL WDFMEMORY handle is not allowed");
|
||||
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
else {
|
||||
FxObjectHandleGetPtr(FxDriverGlobals,
|
||||
Descriptor->u.HandleType.Memory,
|
||||
IFX_TYPE_MEMORY,
|
||||
(PVOID*) &pMemory);
|
||||
|
||||
status = pMemory->ValidateMemoryOffsets(
|
||||
Descriptor->u.HandleType.Offsets);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"Memory offset values are not valid %!STATUS!", status);
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status) && pMemory != NULL) {
|
||||
SetMemory(pMemory, Descriptor->u.HandleType.Offsets);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxRequestBuffer::GetBufferLength(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
switch (DataType) {
|
||||
case FxRequestBufferMemory:
|
||||
//
|
||||
// If the BufferLength and BufferOffset is zero, then the transfer length is same
|
||||
// as the length of the request.
|
||||
//
|
||||
if (u.Memory.Offsets == NULL ||
|
||||
(u.Memory.Offsets->BufferOffset == 0 && u.Memory.Offsets->BufferLength == 0)) {
|
||||
return (ULONG) u.Memory.Memory->GetBufferSize();
|
||||
}
|
||||
else {
|
||||
//
|
||||
// If the BufferLength value is zero then the transfer length is request length
|
||||
// minus the offset value.
|
||||
//
|
||||
if (u.Memory.Offsets->BufferLength == 0) {
|
||||
return ((ULONG) u.RefMdl.Memory->GetBufferSize() - (ULONG) u.RefMdl.Offsets->BufferOffset);
|
||||
}
|
||||
else {
|
||||
return (ULONG) u.Memory.Offsets->BufferLength;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FxRequestBufferMdl:
|
||||
return u.Mdl.Length;
|
||||
|
||||
case FxRequestBufferReferencedMdl:
|
||||
//
|
||||
// If the BufferLength and BufferOffset is zero, then the transfer length is same
|
||||
// as the length of the request.
|
||||
//
|
||||
if (u.RefMdl.Offsets == NULL ||
|
||||
(u.RefMdl.Offsets->BufferOffset == 0 && u.RefMdl.Offsets->BufferLength == 0)) {
|
||||
return (ULONG) u.RefMdl.Memory->GetBufferSize();
|
||||
}
|
||||
else {
|
||||
//
|
||||
// If the BufferLength value is zero then the transfer length is request length
|
||||
// minus the offset value.
|
||||
//
|
||||
if (u.RefMdl.Offsets->BufferLength == 0) {
|
||||
return ((ULONG) u.RefMdl.Memory->GetBufferSize() - (ULONG) u.RefMdl.Offsets->BufferOffset);
|
||||
}
|
||||
else {
|
||||
return (ULONG) u.RefMdl.Offsets->BufferLength;
|
||||
}
|
||||
}
|
||||
|
||||
case FxRequestBufferBuffer:
|
||||
return u.Buffer.Length;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRequestBuffer::GetBuffer(
|
||||
__deref_out PVOID* Buffer
|
||||
)
|
||||
{
|
||||
switch (DataType) {
|
||||
case FxRequestBufferUnspecified:
|
||||
*Buffer = NULL;
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
case FxRequestBufferMemory:
|
||||
if (u.Memory.Offsets != NULL) {
|
||||
*Buffer = WDF_PTR_ADD_OFFSET(u.Memory.Memory->GetBuffer(),
|
||||
u.Memory.Offsets->BufferOffset);
|
||||
}
|
||||
else {
|
||||
*Buffer = u.Memory.Memory->GetBuffer();
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
case FxRequestBufferBuffer:
|
||||
*Buffer = u.Buffer.Buffer;
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
case FxRequestBufferMdl:
|
||||
*Buffer = Mx::MxGetSystemAddressForMdlSafe(u.Mdl.Mdl, NormalPagePriority);
|
||||
if (*Buffer != NULL) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
case FxRequestBufferReferencedMdl:
|
||||
*Buffer = Mx::MxGetSystemAddressForMdlSafe(u.RefMdl.Mdl, NormalPagePriority);
|
||||
if (*Buffer != NULL) {
|
||||
if (u.RefMdl.Offsets != NULL) {
|
||||
*Buffer = WDF_PTR_ADD_OFFSET(*Buffer,
|
||||
u.RefMdl.Offsets->BufferOffset);
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
default:
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FxRequestBuffer::AssignValues(
|
||||
__deref_out_opt PVOID* PPBuffer,
|
||||
__deref_out_opt PMDL* PPMdl,
|
||||
__out PULONG BufferLength
|
||||
)
|
||||
{
|
||||
PVOID pBuffer;
|
||||
PMDL pMdl;
|
||||
size_t bufferSize;
|
||||
|
||||
//
|
||||
// Make sure we have valid double pointers, make life simpler below
|
||||
//
|
||||
if (PPBuffer == NULL) {
|
||||
PPBuffer = &pBuffer;
|
||||
}
|
||||
if (PPMdl == NULL) {
|
||||
PPMdl = &pMdl;
|
||||
}
|
||||
|
||||
switch (DataType) {
|
||||
case FxRequestBufferMemory:
|
||||
pBuffer = u.Memory.Memory->GetBuffer();
|
||||
bufferSize = u.Memory.Memory->GetBufferSize();
|
||||
|
||||
if (u.Memory.Offsets != NULL) {
|
||||
if (u.Memory.Offsets->BufferLength > 0) {
|
||||
bufferSize = u.Memory.Offsets->BufferLength;
|
||||
}
|
||||
if (u.Memory.Offsets->BufferOffset > 0) {
|
||||
pBuffer = WDF_PTR_ADD_OFFSET(pBuffer, u.Memory.Offsets->BufferOffset);
|
||||
}
|
||||
}
|
||||
|
||||
*PPBuffer = pBuffer;
|
||||
*BufferLength = (ULONG) bufferSize;
|
||||
break;
|
||||
|
||||
case FxRequestBufferMdl:
|
||||
*PPMdl = u.Mdl.Mdl;
|
||||
*PPBuffer = NULL;
|
||||
*BufferLength = u.Mdl.Length;
|
||||
break;
|
||||
|
||||
case FxRequestBufferBuffer:
|
||||
*PPMdl = NULL;
|
||||
*PPBuffer = u.Buffer.Buffer;
|
||||
*BufferLength = u.Buffer.Length;
|
||||
break;
|
||||
|
||||
case FxRequestBufferReferencedMdl:
|
||||
*PPMdl = u.RefMdl.Mdl;
|
||||
*PPBuffer = NULL;
|
||||
if (u.RefMdl.Offsets != NULL && u.RefMdl.Offsets->BufferLength > 0) {
|
||||
*BufferLength = (ULONG) u.RefMdl.Offsets->BufferLength;
|
||||
}
|
||||
else {
|
||||
*BufferLength = (ULONG) u.RefMdl.Memory->GetBufferSize();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*PPMdl = NULL;
|
||||
*PPBuffer = NULL;
|
||||
*BufferLength = 0;
|
||||
break;
|
||||
}
|
||||
}
|
1314
sdk/lib/drivers/wdf/shared/support/fxresourceapi.cpp
Normal file
1314
sdk/lib/drivers/wdf/shared/support/fxresourceapi.cpp
Normal file
File diff suppressed because it is too large
Load diff
739
sdk/lib/drivers/wdf/shared/support/fxresourcecollection.cpp
Normal file
739
sdk/lib/drivers/wdf/shared/support/fxresourcecollection.cpp
Normal file
|
@ -0,0 +1,739 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxResourceCollection.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a base object for derived collection classes and
|
||||
the derived collection classes.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#if defined(EVENT_TRACING)
|
||||
#include "FxResourceCollection.tmh"
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxResourceCollection::RemoveAndDelete(
|
||||
__in ULONG Index
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Removes an entry from the collection and then deletes it if found. The
|
||||
caller must have removal permissions to perform this action.
|
||||
|
||||
Arguments:
|
||||
Index - zero based index into the collection at which to perform the removal
|
||||
|
||||
Return Value:
|
||||
TRUE if the item was found and deleted, FALSE otherwise
|
||||
|
||||
--*/
|
||||
{
|
||||
FxObject* pObject;
|
||||
FxCollectionEntry* pEntry;
|
||||
KIRQL irql;
|
||||
|
||||
if (IsRemoveAllowed() == FALSE) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Removes not allowed on handle %p, remove at index %d"
|
||||
"failed", GetObjectHandle(), Index);
|
||||
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pObject = NULL;
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
pEntry = FindEntry(Index);
|
||||
if (pEntry != NULL) {
|
||||
|
||||
//
|
||||
// Mark the list as changed so when we go to create a WDM resource list we
|
||||
// know if a new list is needed.
|
||||
//
|
||||
MarkChanged();
|
||||
|
||||
pObject = pEntry->m_Object;
|
||||
|
||||
//
|
||||
// Remove the entry
|
||||
//
|
||||
RemoveEntry(pEntry);
|
||||
}
|
||||
Unlock(irql);
|
||||
|
||||
if (pObject != NULL) {
|
||||
//
|
||||
// Delete the object since we created it
|
||||
//
|
||||
pObject->DeleteObject();
|
||||
pObject = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxResourceCollection::AddAt(
|
||||
__in ULONG Index,
|
||||
__in FxObject* Object
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Adds an object into the collection at the specified index.
|
||||
|
||||
Arguments:
|
||||
Index - zero baesd index in which to insert into the list. WDF_INSERT_AT_END
|
||||
is a special value which indicates that the insertion is an append.
|
||||
|
||||
Object - object to add
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
FxCollectionEntry *pNew;
|
||||
PLIST_ENTRY ple;
|
||||
NTSTATUS status;
|
||||
KIRQL irql;
|
||||
|
||||
if (IsAddAllowed() == FALSE) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Adds not allowed on handle %p, add at index %d"
|
||||
"failed", GetObjectHandle(), Index);
|
||||
|
||||
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
||||
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
Lock(&irql);
|
||||
|
||||
ple = NULL;
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
pNew = AllocateEntry(GetDriverGlobals());
|
||||
|
||||
if (pNew != NULL) {
|
||||
//
|
||||
// Inserting at the current count (i.e. one past the end) is the same
|
||||
// as append.
|
||||
//
|
||||
if (Index == WDF_INSERT_AT_END || Index == Count()) {
|
||||
ple = &m_ListHead;
|
||||
}
|
||||
else {
|
||||
FxCollectionEntry* cur, *end;
|
||||
ULONG i;
|
||||
|
||||
for (cur = Start(), end = End(), i = 0;
|
||||
cur != end;
|
||||
cur = cur->Next(), i++) {
|
||||
if (i == Index) {
|
||||
ple = &cur->m_ListEntry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ple == NULL) {
|
||||
delete pNew;
|
||||
status = STATUS_ARRAY_BOUNDS_EXCEEDED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
PLIST_ENTRY blink;
|
||||
|
||||
// ple now points to the list entry which we will insert our node
|
||||
// *before*
|
||||
|
||||
blink = ple->Blink;
|
||||
|
||||
// Link the previous with the new entry
|
||||
blink->Flink = &pNew->m_ListEntry;
|
||||
pNew->m_ListEntry.Blink = blink;
|
||||
|
||||
// Link the current with the new entry
|
||||
pNew->m_ListEntry.Flink = ple;
|
||||
ple->Blink = &pNew->m_ListEntry;
|
||||
|
||||
AddEntry(pNew, Object);
|
||||
|
||||
//
|
||||
// Mark the list as changed so when we go to create a WDM resource list
|
||||
// we know if a new list is needed.
|
||||
//
|
||||
MarkChanged();
|
||||
}
|
||||
|
||||
Unlock(irql);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
Object->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxIoResList::BuildFromWdmList(
|
||||
__deref_in PIO_RESOURCE_LIST* WdmResourceList
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Builds up the collection with FxResourceIo objects based on the passed in
|
||||
WDM io resource list
|
||||
|
||||
Arguments:
|
||||
WdmResourceList - list which specifies the io resource objects to create
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
PIO_RESOURCE_DESCRIPTOR pWdmDescriptor;
|
||||
ULONG i, count;
|
||||
NTSTATUS status;
|
||||
|
||||
pWdmDescriptor = &(*WdmResourceList)->Descriptors[0];
|
||||
count = (*WdmResourceList)->Count;
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
//
|
||||
// Now create a new resource object for each resource
|
||||
// in our list.
|
||||
//
|
||||
FxResourceIo *pResource;
|
||||
|
||||
pResource = new(GetDriverGlobals())
|
||||
FxResourceIo(GetDriverGlobals(), pWdmDescriptor);
|
||||
|
||||
if (pResource == NULL) {
|
||||
//
|
||||
// We failed, clean up, and exit. Since we are only
|
||||
// keeping references on the master collection, if
|
||||
// we free this, everything else will go away too.
|
||||
//
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = pResource->AssignParentObject(this);
|
||||
|
||||
//
|
||||
// See notes in previous AssignParentObject as to why
|
||||
// we are asserting.
|
||||
//
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
UNREFERENCED_PARAMETER(status);
|
||||
|
||||
status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
pWdmDescriptor++;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = m_OwningList->Add(this) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*WdmResourceList = (PIO_RESOURCE_LIST) pWdmDescriptor;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxCmResList::BuildFromWdmList(
|
||||
__in PCM_RESOURCE_LIST WdmResourceList,
|
||||
__in UCHAR AccessFlags
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Builds up the collection with FxResourceCm objects based on the passed in
|
||||
WDM io resource list.
|
||||
|
||||
Arguments:
|
||||
WdmResourceList - list which specifies the io resource objects to create
|
||||
|
||||
AccessFlags - permissions to be associated with the list
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
//
|
||||
// Predispose to success
|
||||
//
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
Clear();
|
||||
|
||||
m_AccessFlags = AccessFlags;
|
||||
|
||||
if (WdmResourceList != NULL) {
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
|
||||
ULONG count, i;
|
||||
|
||||
//
|
||||
// We only expect to see one full resource descriptor.
|
||||
//
|
||||
ASSERT(WdmResourceList->Count == 1);
|
||||
|
||||
count = WdmResourceList->List[0].PartialResourceList.Count;
|
||||
pDescriptor = WdmResourceList->List[0].PartialResourceList.PartialDescriptors;
|
||||
|
||||
for(i = 0; i < count; i++, pDescriptor++) {
|
||||
FxResourceCm *pResource;
|
||||
|
||||
pResource = new(GetDriverGlobals())
|
||||
FxResourceCm(GetDriverGlobals(), pDescriptor);
|
||||
|
||||
if (pResource == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = pResource->AssignParentObject(this);
|
||||
|
||||
//
|
||||
// Since we control our own lifetime here, the assign should
|
||||
// always work.
|
||||
//
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
|
||||
status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
Clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PCM_RESOURCE_LIST
|
||||
FxCmResList::CreateWdmList(
|
||||
__in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Allocates and initializes a WDM CM resource list based off of the current
|
||||
contents of this collection.
|
||||
|
||||
Arguments:
|
||||
PoolType - the pool type from which to allocate the resource list
|
||||
|
||||
Return Value:
|
||||
a new resource list upon success, NULL upon failure
|
||||
|
||||
--*/
|
||||
{
|
||||
PCM_RESOURCE_LIST pWdmResourceList;
|
||||
ULONG size;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
pWdmResourceList = NULL;
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
if (Count()) {
|
||||
//
|
||||
// NOTE: This function assumes all resources are on the same bus
|
||||
// and therefore there is only one FULL_RESOURCE_DESCRIPTOR.
|
||||
//
|
||||
size = sizeof(CM_RESOURCE_LIST) +
|
||||
(sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count() - 1));
|
||||
|
||||
pWdmResourceList = (PCM_RESOURCE_LIST)
|
||||
MxMemory::MxAllocatePoolWithTag(PoolType, size, pFxDriverGlobals->Tag);
|
||||
|
||||
if (pWdmResourceList != NULL) {
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
|
||||
FxCollectionEntry *cur, *end;
|
||||
|
||||
RtlZeroMemory(pWdmResourceList, size);
|
||||
|
||||
pWdmResourceList->Count = 1; // We only return one full descriptor
|
||||
|
||||
pWdmResourceList->List[0].PartialResourceList.Version = 1;
|
||||
pWdmResourceList->List[0].PartialResourceList.Revision = 1;
|
||||
pWdmResourceList->List[0].PartialResourceList.Count = Count();
|
||||
|
||||
pDescriptor =
|
||||
pWdmResourceList->List[0].PartialResourceList.PartialDescriptors;
|
||||
|
||||
end = End();
|
||||
for (cur = Start(); cur != end; cur = cur->Next()) {
|
||||
FxResourceCm *pResource;
|
||||
|
||||
pResource = (FxResourceCm*) cur->m_Object;
|
||||
|
||||
RtlCopyMemory(pDescriptor,
|
||||
&pResource->m_Descriptor,
|
||||
sizeof(pResource->m_Descriptor));
|
||||
pDescriptor++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pWdmResourceList;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FxCmResList::GetCount(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ULONG count;
|
||||
KIRQL irql;
|
||||
|
||||
Lock(&irql);
|
||||
count = Count();
|
||||
Unlock(irql);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR
|
||||
FxCmResList::GetDescriptor(
|
||||
__in ULONG Index
|
||||
)
|
||||
{
|
||||
FxResourceCm* pObject;
|
||||
KIRQL irql;
|
||||
|
||||
Lock(&irql);
|
||||
pObject = (FxResourceCm*) GetItem(Index);
|
||||
Unlock(irql);
|
||||
|
||||
if (pObject == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Copy the current descriptor to the clone and return it
|
||||
//
|
||||
RtlCopyMemory(&pObject->m_DescriptorClone,
|
||||
&pObject->m_Descriptor,
|
||||
sizeof(pObject->m_Descriptor));
|
||||
|
||||
return &pObject->m_DescriptorClone;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxIoResReqList*
|
||||
FxIoResReqList::_CreateFromWdmList(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList,
|
||||
__in UCHAR AccessFlags
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Allocates and populates an FxIoResReqList based on the WDM resource
|
||||
requirements list.
|
||||
|
||||
Arguments:
|
||||
WdmRequirementsList - a list of IO_RESOURCE_LISTs which will indicate how
|
||||
to fill in the returned collection object
|
||||
|
||||
AccessFlags - permissions to associate with the newly created object
|
||||
|
||||
Return Value:
|
||||
a new object upon success, NULL upon failure
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
FxIoResReqList* pIoResReqList;
|
||||
ULONG i;
|
||||
|
||||
pIoResReqList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
|
||||
FxIoResReqList(FxDriverGlobals, AccessFlags);
|
||||
|
||||
if (pIoResReqList != NULL) {
|
||||
PIO_RESOURCE_LIST pWdmResourceList;
|
||||
NTSTATUS status;
|
||||
|
||||
if (WdmRequirementsList == NULL) {
|
||||
return pIoResReqList;
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
pWdmResourceList = &WdmRequirementsList->List[0];
|
||||
|
||||
pIoResReqList->m_InterfaceType = WdmRequirementsList->InterfaceType;
|
||||
pIoResReqList->m_SlotNumber = WdmRequirementsList->SlotNumber;
|
||||
|
||||
for (i = 0; i < WdmRequirementsList->AlternativeLists; i++) {
|
||||
FxIoResList *pResList;
|
||||
|
||||
pResList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
|
||||
FxIoResList(FxDriverGlobals, pIoResReqList);
|
||||
|
||||
if (pResList != NULL) {
|
||||
status = pResList->AssignParentObject(pIoResReqList);
|
||||
|
||||
//
|
||||
// Since we control our own lifetime, assigning the parent should
|
||||
// never fail.
|
||||
//
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
|
||||
status = pResList->BuildFromWdmList(&pWdmResourceList);
|
||||
}
|
||||
else {
|
||||
//
|
||||
// We failed to allocate a child collection. Clean up
|
||||
// and break out of the loop.
|
||||
//
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
//
|
||||
// Cleanup and return a NULL object
|
||||
//
|
||||
pIoResReqList->DeleteObject();
|
||||
pIoResReqList = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pIoResReqList;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PIO_RESOURCE_REQUIREMENTS_LIST
|
||||
FxIoResReqList::CreateWdmList(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Creates a WDM io resource requirements list based off of the current
|
||||
contents of the collection
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
new WDM io resource requirements list allocated out of paged pool upon success,
|
||||
NULL upon failure or an empty list
|
||||
|
||||
--*/
|
||||
{
|
||||
PIO_RESOURCE_REQUIREMENTS_LIST pRequirementsList;
|
||||
FxCollectionEntry *cur, *end;
|
||||
NTSTATUS status;
|
||||
ULONG totalDescriptors;
|
||||
ULONG size;
|
||||
ULONG count;
|
||||
ULONG tmp;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
|
||||
totalDescriptors = 0;
|
||||
pRequirementsList = NULL;
|
||||
|
||||
count = Count();
|
||||
pFxDriverGlobals = GetDriverGlobals();
|
||||
|
||||
if (count > 0) {
|
||||
//
|
||||
// The collection object should contain a set of child collections
|
||||
// with each of the various requirement lists. Use the number of
|
||||
// these collections to determine the size of our requirements
|
||||
// list.
|
||||
//
|
||||
end = End();
|
||||
for (cur = Start(); cur != end; cur = cur->Next()) {
|
||||
status = RtlULongAdd(totalDescriptors,
|
||||
((FxIoResList *) cur->m_Object)->Count(),
|
||||
&totalDescriptors);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Overflow;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We now have enough information to determine how much memory we
|
||||
// need to allocate for our requirements list.
|
||||
//
|
||||
// size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
|
||||
// (sizeof(IO_RESOURCE_LIST) * (count - 1)) +
|
||||
// (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors) -
|
||||
// (sizeof(IO_RESOURCE_DESCRIPTOR) * count);
|
||||
//
|
||||
// sizeof(IO_RESOURCE_DESCRIPTOR) * count is subtracted off because
|
||||
// each IO_RESOURCE_LIST has an embedded IO_RESOURCE_DESCRIPTOR in it
|
||||
// and we don't want to overallocated.
|
||||
//
|
||||
|
||||
//
|
||||
// To handle overflow each mathematical operation is split out into an
|
||||
// overflow safe call.
|
||||
//
|
||||
size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
|
||||
|
||||
// sizeof(IO_RESOURCE_LIST) * (count - 1)
|
||||
status = RtlULongMult(sizeof(IO_RESOURCE_LIST), count - 1, &tmp);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Overflow;
|
||||
}
|
||||
|
||||
status = RtlULongAdd(size, tmp, &size);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Overflow;
|
||||
}
|
||||
|
||||
// (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors)
|
||||
status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR),
|
||||
totalDescriptors,
|
||||
&tmp);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Overflow;
|
||||
}
|
||||
|
||||
status = RtlULongAdd(size, tmp, &size);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Overflow;
|
||||
}
|
||||
|
||||
// - sizeof(IO_RESOURCE_DESCRIPTOR) * Count() (note the subtraction!)
|
||||
status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR), count, &tmp);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Overflow;
|
||||
}
|
||||
|
||||
// Sub, not Add!
|
||||
status = RtlULongSub(size, tmp, &size);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Overflow;
|
||||
}
|
||||
|
||||
pRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST)
|
||||
MxMemory::MxAllocatePoolWithTag(PagedPool, size, pFxDriverGlobals->Tag);
|
||||
|
||||
if (pRequirementsList != NULL) {
|
||||
PIO_RESOURCE_LIST pList;
|
||||
FxResourceIo *pResource;
|
||||
|
||||
pList = pRequirementsList->List;
|
||||
|
||||
//
|
||||
// Start by zero initializing our structure
|
||||
//
|
||||
RtlZeroMemory(pRequirementsList, size);
|
||||
|
||||
//
|
||||
// InterfaceType and BusNumber are unused for WDM, but InterfaceType
|
||||
// is used by the arbiters.
|
||||
//
|
||||
pRequirementsList->InterfaceType = m_InterfaceType;
|
||||
|
||||
pRequirementsList->SlotNumber = m_SlotNumber;
|
||||
|
||||
//
|
||||
// Now populate the requirements list with the resources from
|
||||
// our collections.
|
||||
//
|
||||
pRequirementsList->ListSize = size;
|
||||
pRequirementsList->AlternativeLists = Count();
|
||||
|
||||
end = End();
|
||||
for (cur = Start(); cur != end; cur = cur->Next()) {
|
||||
FxIoResList* pIoResList;
|
||||
PIO_RESOURCE_DESCRIPTOR pDescriptor;
|
||||
FxCollectionEntry *pIoResCur, *pIoResEnd;
|
||||
|
||||
pIoResList = (FxIoResList*) cur->m_Object;
|
||||
|
||||
pList->Version = 1;
|
||||
pList->Revision = 1;
|
||||
pList->Count = pIoResList->Count();
|
||||
|
||||
pDescriptor = pList->Descriptors;
|
||||
|
||||
pIoResEnd = pIoResList->End();
|
||||
for (pIoResCur = pIoResList->Start();
|
||||
pIoResCur != pIoResEnd;
|
||||
pIoResCur = pIoResCur->Next()) {
|
||||
|
||||
pResource = (FxResourceIo *) pIoResCur->m_Object;
|
||||
RtlCopyMemory(pDescriptor,
|
||||
&pResource->m_Descriptor,
|
||||
sizeof(pResource->m_Descriptor));
|
||||
pDescriptor++;
|
||||
}
|
||||
|
||||
pList = (PIO_RESOURCE_LIST) pDescriptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pRequirementsList;
|
||||
|
||||
Overflow:
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Integer overflow occured when computing size of "
|
||||
"IO_RESOURCE_REQUIREMENTS_LIST");
|
||||
|
||||
return NULL;
|
||||
}
|
142
sdk/lib/drivers/wdf/shared/support/fxspinlock.cpp
Normal file
142
sdk/lib/drivers/wdf/shared/support/fxspinlock.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxSpinLock.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements FxSpinLock
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
#include "FxSpinLock.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxSpinLock.tmh"
|
||||
}
|
||||
|
||||
FxSpinLock::FxSpinLock(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in USHORT ExtraSize
|
||||
) :
|
||||
FxObject(FX_TYPE_SPIN_LOCK, COMPUTE_OBJECT_SIZE(sizeof(FxSpinLock), ExtraSize), FxDriverGlobals)
|
||||
{
|
||||
FX_SPIN_LOCK_HISTORY* pHistory;
|
||||
|
||||
m_Irql = 0;
|
||||
m_InterruptLock = FALSE;
|
||||
|
||||
pHistory = GetHistory();
|
||||
|
||||
if (pHistory != NULL) {
|
||||
RtlZeroMemory(pHistory, sizeof(FX_SPIN_LOCK_HISTORY));
|
||||
|
||||
pHistory->CurrentHistory = &pHistory->History[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__drv_raisesIRQL(DISPATCH_LEVEL)
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
FxSpinLock::AcquireLock(
|
||||
__in PVOID CallersAddress
|
||||
)
|
||||
{
|
||||
PFX_SPIN_LOCK_HISTORY pHistory;
|
||||
KIRQL irql;
|
||||
|
||||
m_SpinLock.Acquire(&irql);
|
||||
|
||||
m_Irql = irql;
|
||||
|
||||
pHistory = GetHistory();
|
||||
|
||||
if (pHistory != NULL) {
|
||||
PFX_SPIN_LOCK_HISTORY_ENTRY pCur;
|
||||
|
||||
//
|
||||
// This assert should never fire here, but this helps track ownership
|
||||
// in the case of a release without an acquire.
|
||||
//
|
||||
ASSERT(pHistory->OwningThread == NULL);
|
||||
pHistory->OwningThread = Mx::MxGetCurrentThread();
|
||||
|
||||
pCur = pHistory->CurrentHistory;
|
||||
|
||||
Mx::MxQueryTickCount(&pCur->AcquiredAtTime);
|
||||
pCur->CallersAddress = CallersAddress;
|
||||
}
|
||||
}
|
||||
|
||||
__drv_requiresIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
FxSpinLock::ReleaseLock(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
PFX_SPIN_LOCK_HISTORY pHistory;
|
||||
|
||||
pHistory = GetHistory();
|
||||
|
||||
if (pHistory != NULL) {
|
||||
LARGE_INTEGER now;
|
||||
PFX_SPIN_LOCK_HISTORY_ENTRY pCur;
|
||||
|
||||
if (pHistory->OwningThread != Mx::MxGetCurrentThread()) {
|
||||
if (pHistory->OwningThread == NULL) {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFSPINLOCK %p being released by thread 0x%p, but was "
|
||||
"never acquired!", GetObjectHandle(), Mx::MxGetCurrentThread());
|
||||
}
|
||||
else {
|
||||
DoTraceLevelMessage(
|
||||
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFSPINLOCK 0x%p not owned by thread 0x%p, owned by thread 0x%p",
|
||||
GetObjectHandle(), Mx::MxGetCurrentThread(),
|
||||
pHistory->OwningThread);
|
||||
}
|
||||
|
||||
FxVerifierBugCheck(GetDriverGlobals(),
|
||||
WDF_INVALID_LOCK_OPERATION,
|
||||
(ULONG_PTR) GetObjectHandle(),
|
||||
0x1);
|
||||
//
|
||||
// Will not get here
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(pHistory->OwningThread != NULL);
|
||||
|
||||
Mx::MxQueryTickCount(&now);
|
||||
|
||||
pCur = pHistory->CurrentHistory;
|
||||
pCur->LockedDuraction = now.QuadPart - pCur->AcquiredAtTime.QuadPart;
|
||||
|
||||
pHistory->CurrentHistory++;
|
||||
if (pHistory->CurrentHistory >=
|
||||
pHistory->History + FX_SPIN_LOCK_NUM_HISTORY_ENTRIES) {
|
||||
pHistory->CurrentHistory = pHistory->History;
|
||||
}
|
||||
|
||||
pHistory->OwningThread = NULL;
|
||||
}
|
||||
|
||||
m_SpinLock.Release(m_Irql);
|
||||
}
|
181
sdk/lib/drivers/wdf/shared/support/fxspinlockapi.cpp
Normal file
181
sdk/lib/drivers/wdf/shared/support/fxspinlockapi.cpp
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxSpinLockAPI.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements external APIS to access FxSpinLock
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
#include "FxSpinLock.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxSpinLockAPI.tmh"
|
||||
}
|
||||
|
||||
//
|
||||
// Extern the entire file
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfSpinLockCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES SpinLockAttributes,
|
||||
__out
|
||||
WDFSPINLOCK* SpinLock
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxSpinLock* pLock;
|
||||
WDFSPINLOCK lock;
|
||||
USHORT extra;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
//
|
||||
// Get the parent's globals if it is present
|
||||
//
|
||||
if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(
|
||||
pFxDriverGlobals, SpinLockAttributes))) {
|
||||
FxObject* pParent;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
SpinLockAttributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
}
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, SpinLock);
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, SpinLockAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pFxDriverGlobals->FxVerifierLock) {
|
||||
extra = sizeof(FX_SPIN_LOCK_HISTORY);
|
||||
}
|
||||
else {
|
||||
extra = 0;
|
||||
}
|
||||
|
||||
*SpinLock = NULL;
|
||||
|
||||
pLock = new(pFxDriverGlobals, SpinLockAttributes, extra)
|
||||
FxSpinLock(pFxDriverGlobals, extra);
|
||||
|
||||
if (pLock == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
status = pLock->Commit(SpinLockAttributes, (WDFOBJECT*)&lock);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
*SpinLock = lock;
|
||||
}
|
||||
else {
|
||||
pLock->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_raisesIRQL(DISPATCH_LEVEL)
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfSpinLockAcquire)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
__drv_savesIRQL
|
||||
_Requires_lock_not_held_(_Curr_)
|
||||
_Acquires_lock_(_Curr_)
|
||||
WDFSPINLOCK SpinLock
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxSpinLock* pLock;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
SpinLock,
|
||||
FX_TYPE_SPIN_LOCK,
|
||||
(PVOID*) &pLock,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
if (pLock->IsInterruptLock()) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFSPINLOCK %p is associated with an interrupt, "
|
||||
"cannot be used for normal sync operations",
|
||||
SpinLock);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
pLock->AcquireLock(
|
||||
pFxDriverGlobals->FxVerifierLock ? _ReturnAddress() : NULL);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
__drv_minIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfSpinLockRelease)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
__drv_restoresIRQL
|
||||
_Requires_lock_held_(_Curr_)
|
||||
_Releases_lock_(_Curr_)
|
||||
WDFSPINLOCK SpinLock
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxSpinLock* pLock;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
SpinLock,
|
||||
FX_TYPE_SPIN_LOCK,
|
||||
(PVOID*) &pLock,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
if (pLock->IsInterruptLock()) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"WDFSPINLOCK %p is associated with an interrupt, "
|
||||
"cannot be used for normal sync operations",
|
||||
SpinLock);
|
||||
FxVerifierDbgBreakPoint(pFxDriverGlobals);
|
||||
return;
|
||||
}
|
||||
|
||||
pLock->ReleaseLock();
|
||||
}
|
||||
|
||||
} // extern "C"
|
67
sdk/lib/drivers/wdf/shared/support/fxstring.cpp
Normal file
67
sdk/lib/drivers/wdf/shared/support/fxstring.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxString.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a simple string class to operate on
|
||||
unicode strings.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
FxString::FxString(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxObject(FX_TYPE_STRING, sizeof(FxString), FxDriverGlobals)
|
||||
{
|
||||
RtlInitUnicodeString(&m_UnicodeString, NULL);
|
||||
MarkPassiveDispose(ObjectDoNotLock);
|
||||
}
|
||||
|
||||
FxString::~FxString()
|
||||
{
|
||||
if (m_UnicodeString.Buffer) {
|
||||
FxPoolFree(m_UnicodeString.Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxString::Assign(
|
||||
__in const UNICODE_STRING* UnicodeString
|
||||
)
|
||||
{
|
||||
return FxDuplicateUnicodeString(GetDriverGlobals(),
|
||||
UnicodeString,
|
||||
&m_UnicodeString);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxString::Assign(
|
||||
__in PCWSTR SourceString
|
||||
)
|
||||
|
||||
{
|
||||
UNICODE_STRING string;
|
||||
|
||||
RtlInitUnicodeString(&string, SourceString);
|
||||
|
||||
return Assign(&string);
|
||||
}
|
152
sdk/lib/drivers/wdf/shared/support/fxstringapi.cpp
Normal file
152
sdk/lib/drivers/wdf/shared/support/fxstringapi.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxStringApi.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the "C" interface to the collection object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxStringAPI.tmh"
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
WDFEXPORT(WdfStringCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt
|
||||
PCUNICODE_STRING UnicodeString,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES StringAttributes,
|
||||
__out
|
||||
WDFSTRING* String
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxString* pString;
|
||||
NTSTATUS status;
|
||||
|
||||
pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
|
||||
//
|
||||
// Get the parent's globals if it is present
|
||||
//
|
||||
if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
|
||||
StringAttributes))) {
|
||||
FxObject* pParent;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
|
||||
StringAttributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&pParent,
|
||||
&pFxDriverGlobals);
|
||||
}
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, String);
|
||||
|
||||
*String = NULL;
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FxValidateObjectAttributes(pFxDriverGlobals, StringAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (UnicodeString != NULL) {
|
||||
status = FxValidateUnicodeString(pFxDriverGlobals, UnicodeString);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
pString = new (pFxDriverGlobals, StringAttributes) FxString(pFxDriverGlobals);
|
||||
|
||||
if (pString != NULL) {
|
||||
if (UnicodeString != NULL) {
|
||||
status = pString->Assign(UnicodeString);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
status = pString->Commit(StringAttributes, (WDFOBJECT*)String);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
pString->DeleteFromFailedCreate();
|
||||
pString = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
DoTraceLevelMessage(
|
||||
pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"Could not allocate WDFSTRING handle, %!STATUS!", status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
VOID
|
||||
WDFEXPORT(WdfStringGetUnicodeString)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFSTRING String,
|
||||
__out
|
||||
PUNICODE_STRING UnicodeString
|
||||
)
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxString* pString;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
String,
|
||||
FX_TYPE_STRING,
|
||||
(PVOID*) &pString,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
FxPointerNotNull(pFxDriverGlobals, UnicodeString);
|
||||
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(UnicodeString,
|
||||
pString->GetUnicodeString(),
|
||||
sizeof(UNICODE_STRING));
|
||||
}
|
||||
|
||||
} // extern "C"
|
25
sdk/lib/drivers/wdf/shared/support/fxsupportpch.hpp
Normal file
25
sdk/lib/drivers/wdf/shared/support/fxsupportpch.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*++
|
||||
|
||||
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
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __FX_SUPPORT_PCH_HPP__
|
||||
#define __FX_SUPPORT_PCH_HPP__
|
||||
|
||||
#if FX_CORE_MODE == FX_CORE_USER_MODE
|
||||
#include "um\FxSupportPchUM.hpp"
|
||||
#elif FX_CORE_MODE == FX_CORE_KERNEL_MODE
|
||||
#include "km\FxSupportPchKM.hpp"
|
||||
#endif
|
||||
|
||||
#endif // __FX_SUPPORT_PCH_HPP__
|
149
sdk/lib/drivers/wdf/shared/support/fxtelemetry.cpp
Normal file
149
sdk/lib/drivers/wdf/shared/support/fxtelemetry.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxTelemetry.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a telemetry methods.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
|
||||
#include "fxsupportpch.hpp"
|
||||
|
||||
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
|
||||
#include "fxldr.h"
|
||||
#include <ntstrsafe.h>
|
||||
#else
|
||||
#include "DriverFrameworks-UserMode-UmEvents.h"
|
||||
#include "FxldrUm.h"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#if defined(EVENT_TRACING)
|
||||
#include "FxTelemetry.tmh"
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
GetNameFromPath(
|
||||
_In_ PCUNICODE_STRING Path,
|
||||
_Out_ PUNICODE_STRING Name
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Given a potential full path name, return just the filename portion, OR,
|
||||
Given a potential full registry path name, return just the subkey portion.
|
||||
|
||||
Pointer to the filename protion in the full path name string, OR,
|
||||
Pointer to the subkey portion in the full registry path name.
|
||||
|
||||
Arguments:
|
||||
|
||||
Path - Pointer to the full path name string.
|
||||
|
||||
Name - Pointer to receive the name
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
BOOLEAN foundSlash;
|
||||
|
||||
ASSERT(Path != NULL);
|
||||
|
||||
//
|
||||
// Ideally a check of Path->Length == 0 would be sufficient except that
|
||||
// PreFAST thinks that Length can be odd, so it thinks Length == 1 is possible.
|
||||
// Comparing Length < sizeof(WCHAR) satisfies PreFAST and keeps the logic
|
||||
// at runtime correct.
|
||||
//
|
||||
if (Path->Length < sizeof(WCHAR)) {
|
||||
RtlZeroMemory(Name, sizeof(UNICODE_STRING));
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize Name to point to the last WCHAR of the buffer and we will work
|
||||
// our way backwards to the beginning of the string or a \
|
||||
//
|
||||
|
||||
Name->Buffer = WDF_PTR_ADD_OFFSET_TYPE(Path->Buffer,
|
||||
Path->Length - sizeof(WCHAR),
|
||||
PWCH);
|
||||
Name->Length = sizeof(WCHAR);
|
||||
foundSlash = FALSE;
|
||||
|
||||
while (Name->Buffer >= Path->Buffer) {
|
||||
if (*Name->Buffer == L'\\') {
|
||||
//
|
||||
// Skip the \ in the buffer moving forward a character and adjusting
|
||||
// the length
|
||||
//
|
||||
foundSlash = TRUE;
|
||||
Name->Buffer++;
|
||||
Name->Length -= sizeof(WCHAR);
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Move backwards in the string
|
||||
//
|
||||
Name->Buffer--;
|
||||
Name->Length += sizeof(WCHAR);
|
||||
}
|
||||
|
||||
if (foundSlash && Name->Length == 0) {
|
||||
//
|
||||
// Handle the case where a slash was found and it is the only character
|
||||
//
|
||||
Name->Buffer = NULL;
|
||||
}
|
||||
else if (foundSlash == FALSE) {
|
||||
//
|
||||
// Handle the case where no slash was found. In this case, Name->Buffer
|
||||
// points to one WCHAR before the beginning of the string.
|
||||
//
|
||||
Name->Length -= sizeof(WCHAR);
|
||||
Name->Buffer++;
|
||||
}
|
||||
|
||||
//
|
||||
// Need to set MaximumLength to the same value as Length so that the struct
|
||||
// format is valid.
|
||||
//
|
||||
Name->MaximumLength = Name->Length;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
552
sdk/lib/drivers/wdf/shared/support/fxtransactionedlist.cpp
Normal file
552
sdk/lib/drivers/wdf/shared/support/fxtransactionedlist.cpp
Normal file
|
@ -0,0 +1,552 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxTransactionedList.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a simple transactioned list which allows the caller
|
||||
to lock the list and then iterate over it without worrying about deletes
|
||||
and adds.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
FxTransactionedList::FxTransactionedList()
|
||||
{
|
||||
m_ListLockedRecursionCount = 0;
|
||||
m_DeleteOnRemove = FALSE;
|
||||
m_Deleting = FALSE;
|
||||
m_Retries = 0;
|
||||
m_DeletingDoneEvent = NULL;
|
||||
|
||||
InitializeListHead(&m_ListHead);
|
||||
InitializeListHead(&m_TransactionHead);
|
||||
}
|
||||
|
||||
FxTransactionedList::~FxTransactionedList()
|
||||
{
|
||||
FxTransactionedEntry* pEntry;
|
||||
PLIST_ENTRY ple;
|
||||
|
||||
//
|
||||
// If m_DeleteOnRemove is FALSE, there is no need to iterate over any of the
|
||||
// lists to free anything.
|
||||
//
|
||||
if (m_DeleteOnRemove == FALSE) {
|
||||
ASSERT(IsListEmpty(&m_ListHead));
|
||||
ASSERT(IsListEmpty(&m_TransactionHead));
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(m_ListLockedRecursionCount == 0);
|
||||
|
||||
while (!IsListEmpty(&m_ListHead)) {
|
||||
ple = RemoveHeadList(&m_ListHead);
|
||||
InitializeListHead(ple);
|
||||
|
||||
pEntry = FxTransactionedEntry::_FromEntry(ple);
|
||||
|
||||
switch (pEntry->m_Transaction) {
|
||||
case FxTransactionActionNothing:
|
||||
//
|
||||
// Nothing to do, no pending transaction
|
||||
//
|
||||
break;
|
||||
|
||||
case FxTransactionActionAdd:
|
||||
//
|
||||
// Should not have an add transaction and be on the main list at the
|
||||
// same time!
|
||||
//
|
||||
ASSERT(FALSE);
|
||||
break;
|
||||
|
||||
case FxTransactionActionRemove:
|
||||
//
|
||||
// Make sure it is not on the transaction list
|
||||
//
|
||||
RemoveEntryList(&pEntry->m_TransactionLink);
|
||||
InitializeListHead(&pEntry->m_TransactionLink);
|
||||
|
||||
//
|
||||
// When inserted as a remove transaction, we add this reference in
|
||||
// RemoveLocked
|
||||
//
|
||||
pEntry->GetTransactionedObject()->RELEASE(pEntry);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
pEntry->GetTransactionedObject()->DeleteObject();
|
||||
}
|
||||
|
||||
while (!IsListEmpty(&m_TransactionHead)) {
|
||||
ple = RemoveHeadList(&m_TransactionHead);
|
||||
InitializeListHead(ple);
|
||||
|
||||
pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
|
||||
|
||||
//
|
||||
// We yanked out all of the removes in the previous loop
|
||||
//
|
||||
ASSERT(pEntry->m_Transaction == FxTransactionActionAdd);
|
||||
|
||||
//
|
||||
// Delete the object since this list owns it.
|
||||
//
|
||||
pEntry->GetTransactionedObject()->DeleteObject();
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTransactionedList::LockForEnum(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
AcquireLock(FxDriverGlobals, &irql);
|
||||
m_ListLockedRecursionCount++;
|
||||
ReleaseLock(FxDriverGlobals, irql);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTransactionedList::UnlockFromEnum(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
)
|
||||
{
|
||||
LIST_ENTRY releaseHead;
|
||||
KIRQL irql;
|
||||
MxEvent* event;
|
||||
|
||||
InitializeListHead(&releaseHead);
|
||||
event = NULL;
|
||||
AcquireLock(FxDriverGlobals, &irql);
|
||||
m_ListLockedRecursionCount--;
|
||||
ProcessTransactionList(&releaseHead);
|
||||
|
||||
if (m_ListLockedRecursionCount == 0 && m_Deleting) {
|
||||
event = m_DeletingDoneEvent;
|
||||
m_DeletingDoneEvent = NULL;
|
||||
}
|
||||
ReleaseLock(FxDriverGlobals, irql);
|
||||
|
||||
ProcessObjectsToRelease(&releaseHead);
|
||||
|
||||
if (event != NULL) {
|
||||
event->Set();
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTransactionedList::ProcessTransactionList(
|
||||
__in PLIST_ENTRY ReleaseHead
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *ple;
|
||||
FxTransactionedEntry* pEntry;
|
||||
|
||||
//
|
||||
// If there are other iterators, do not process transactions until they are
|
||||
// done.
|
||||
//
|
||||
if (m_ListLockedRecursionCount != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (!IsListEmpty(&m_TransactionHead)) {
|
||||
ple = RemoveHeadList(&m_TransactionHead);
|
||||
InitializeListHead(ple);
|
||||
|
||||
pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
|
||||
|
||||
ASSERT(pEntry->m_Transaction != FxTransactionActionNothing);
|
||||
|
||||
if (pEntry->m_Transaction == FxTransactionActionAdd) {
|
||||
//
|
||||
// Add to the main list
|
||||
//
|
||||
InsertTailList(&m_ListHead, &pEntry->m_ListLink);
|
||||
|
||||
//
|
||||
// Virtual notification of addition
|
||||
//
|
||||
EntryAdded(pEntry);
|
||||
}
|
||||
else if (pEntry->m_Transaction == FxTransactionActionRemove) {
|
||||
//
|
||||
// Remove it from the main list and move it to a free list
|
||||
//
|
||||
RemoveEntryList(&pEntry->m_ListLink);
|
||||
InsertTailList(ReleaseHead, &pEntry->m_TransactionLink);
|
||||
|
||||
//
|
||||
// Virtual notification of removal
|
||||
//
|
||||
EntryRemoved(pEntry);
|
||||
}
|
||||
|
||||
pEntry->m_Transaction = FxTransactionActionNothing;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTransactionedList::ProcessObjectsToRelease(
|
||||
__in PLIST_ENTRY ReleaseHead
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *ple;
|
||||
FxTransactionedEntry* pEntry;
|
||||
|
||||
while (!IsListEmpty(ReleaseHead)) {
|
||||
ple = RemoveHeadList(ReleaseHead);
|
||||
InitializeListHead(ple);
|
||||
|
||||
pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
|
||||
|
||||
//
|
||||
// We always release our reference we took when we post the change
|
||||
// to the list
|
||||
//
|
||||
pEntry->GetTransactionedObject()->RELEASE(pEntry);
|
||||
|
||||
//
|
||||
// 2ndary release if the list is set to do this
|
||||
//
|
||||
if (m_DeleteOnRemove) {
|
||||
pEntry->GetTransactionedObject()->DeleteObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxTransactionedList::Deleting(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in_opt MxEvent* DeleteDoneEvent
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
BOOLEAN result;
|
||||
|
||||
result = TRUE;
|
||||
|
||||
AcquireLock(FxDriverGlobals, &irql);
|
||||
m_Deleting = TRUE;
|
||||
|
||||
if (m_ListLockedRecursionCount != 0) {
|
||||
m_DeletingDoneEvent = DeleteDoneEvent;
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
ReleaseLock(FxDriverGlobals, irql);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxTransactionedList::Add(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in FxTransactionedEntry* Entry
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
KIRQL irql;
|
||||
|
||||
AcquireLock(FxDriverGlobals, &irql);
|
||||
|
||||
if (m_Deleting) {
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
}
|
||||
else {
|
||||
status = ProcessAdd(Entry);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
if (m_ListLockedRecursionCount == 0) {
|
||||
//
|
||||
// We can insert the entry now, do so
|
||||
//
|
||||
InsertTailList(&m_ListHead, &Entry->m_ListLink);
|
||||
|
||||
EntryAdded(Entry);
|
||||
}
|
||||
else {
|
||||
//
|
||||
// List is locked, queue a transaction
|
||||
//
|
||||
Entry->m_Transaction = FxTransactionActionAdd;
|
||||
InsertTailList(&m_TransactionHead, &Entry->m_TransactionLink);
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseLock(FxDriverGlobals, irql);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTransactionedList::SearchForAndRemove(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in PVOID EntryData
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
FxTransactionedEntry* pEntry;
|
||||
PLIST_ENTRY ple;
|
||||
BOOLEAN removed;
|
||||
|
||||
removed = FALSE;
|
||||
|
||||
AcquireLock(FxDriverGlobals, &irql);
|
||||
|
||||
for (ple = m_TransactionHead.Flink;
|
||||
ple != &m_TransactionHead;
|
||||
ple = ple->Flink) {
|
||||
|
||||
pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
|
||||
|
||||
if (Compare(pEntry, EntryData)) {
|
||||
if (pEntry->GetTransactionAction() == FxTransactionActionAdd) {
|
||||
RemoveEntryList(&pEntry->m_TransactionLink);
|
||||
InitializeListHead(&pEntry->m_TransactionLink);
|
||||
|
||||
removed = TRUE;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Already being removed, just return
|
||||
//
|
||||
ASSERT(pEntry->GetTransactionAction() ==
|
||||
FxTransactionActionRemove);
|
||||
}
|
||||
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Walk the committed list
|
||||
//
|
||||
pEntry = NULL;
|
||||
|
||||
while ((pEntry = GetNextEntryLocked(pEntry)) != NULL) {
|
||||
if (Compare(pEntry, EntryData)) {
|
||||
removed = RemoveLocked(pEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Done:
|
||||
ReleaseLock(FxDriverGlobals, irql);
|
||||
|
||||
if (removed && m_DeleteOnRemove) {
|
||||
pEntry->GetTransactionedObject()->DeleteObject();
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxTransactionedList::Remove(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in FxTransactionedEntry* Entry
|
||||
)
|
||||
{
|
||||
BOOLEAN removed;
|
||||
KIRQL irql;
|
||||
|
||||
AcquireLock(FxDriverGlobals, &irql);
|
||||
removed = RemoveLocked(Entry);
|
||||
ReleaseLock(FxDriverGlobals,irql);
|
||||
|
||||
if (removed && m_DeleteOnRemove) {
|
||||
Entry->GetTransactionedObject()->DeleteObject();
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
FxTransactionedList::RemoveLocked(
|
||||
__in FxTransactionedEntry* Entry
|
||||
)
|
||||
{
|
||||
BOOLEAN removed;
|
||||
|
||||
removed = FALSE;
|
||||
|
||||
if (Entry->m_Transaction == FxTransactionActionAdd) {
|
||||
//
|
||||
// Not yet added to the list proper, remove it from the transaction list
|
||||
//
|
||||
removed = TRUE;
|
||||
RemoveEntryList(&Entry->m_TransactionLink);
|
||||
InitializeListHead(&Entry->m_TransactionLink);
|
||||
|
||||
Entry->m_Transaction = FxTransactionActionNothing;
|
||||
}
|
||||
else {
|
||||
ASSERT(!IsListEmpty(&Entry->m_ListLink));
|
||||
|
||||
if (m_ListLockedRecursionCount == 0) {
|
||||
//
|
||||
// List is not locked, remove it now
|
||||
//
|
||||
RemoveEntryList(&Entry->m_ListLink);
|
||||
InitializeListHead(&Entry->m_ListLink);
|
||||
|
||||
//
|
||||
// Virtual notification
|
||||
//
|
||||
EntryRemoved(Entry);
|
||||
|
||||
removed = TRUE;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// List is locked for enumeration, queue a transaction
|
||||
//
|
||||
Entry->m_Transaction = FxTransactionActionRemove;
|
||||
InsertTailList(&m_TransactionHead, &Entry->m_TransactionLink);
|
||||
Entry->GetTransactionedObject()->ADDREF(Entry);
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxTransactionedEntry*
|
||||
FxTransactionedList::GetNextEntry(
|
||||
__in_opt FxTransactionedEntry* Entry
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Gets the next entry. Assumes the caller has called LockedForEnum
|
||||
|
||||
Arguments:
|
||||
Entry the current entry in the iteratation, NULL for the first
|
||||
|
||||
Return Value:
|
||||
next entry in the iteration, NULL if there are no more entries
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// The caller should have locked the list for enumeration
|
||||
//
|
||||
ASSERT(m_ListLockedRecursionCount > 0 || m_Deleting);
|
||||
|
||||
return GetNextEntryLocked(Entry);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
FxTransactionedEntry*
|
||||
FxTransactionedList::GetNextEntryLocked(
|
||||
__in_opt FxTransactionedEntry* Entry
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Returns the next entry. Assumes that the caller has the list locked through
|
||||
a call to AcquireLock() or through LockForEnum()
|
||||
|
||||
Arguments:
|
||||
Entry the current entry in the iteratation, NULL for the first
|
||||
|
||||
Return Value:
|
||||
next entry in the iteration, NULL if there are no more entries
|
||||
|
||||
--*/
|
||||
{
|
||||
PLIST_ENTRY ple;
|
||||
|
||||
if (Entry == NULL) {
|
||||
ple = m_ListHead.Flink;
|
||||
}
|
||||
else {
|
||||
ple = Entry->m_ListLink.Flink;
|
||||
}
|
||||
|
||||
//
|
||||
// Find the next entry which does not have a pending transaction on it
|
||||
//
|
||||
for ( ; ple != &m_ListHead; ple = ple->Flink) {
|
||||
FxTransactionedEntry* pNext;
|
||||
|
||||
pNext = FxTransactionedEntry::_FromEntry(ple);
|
||||
if (pNext->m_Transaction == FxTransactionActionNothing) {
|
||||
return pNext;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Reached the end of the list
|
||||
//
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FxSpinLockTransactionedList::FxSpinLockTransactionedList() :
|
||||
FxTransactionedList()
|
||||
{
|
||||
}
|
||||
|
||||
__drv_raisesIRQL(DISPATCH_LEVEL)
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
FxSpinLockTransactionedList::AcquireLock(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__out PKIRQL Irql
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(FxDriverGlobals);
|
||||
m_ListLock.Acquire(Irql);
|
||||
}
|
||||
|
||||
__drv_requiresIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
FxSpinLockTransactionedList::ReleaseLock(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in __drv_restoresIRQL KIRQL Irql
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(FxDriverGlobals);
|
||||
m_ListLock.Release(Irql);
|
||||
}
|
||||
|
||||
_Acquires_lock_(_Global_critical_region_)
|
||||
VOID
|
||||
FxWaitLockTransactionedList::AcquireLock(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__out PKIRQL Irql
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Irql);
|
||||
m_StateChangeListLock.AcquireLock(FxDriverGlobals);
|
||||
}
|
||||
|
||||
_Releases_lock_(_Global_critical_region_)
|
||||
VOID
|
||||
FxWaitLockTransactionedList::ReleaseLock(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in KIRQL Irql
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Irql);
|
||||
m_StateChangeListLock.ReleaseLock(FxDriverGlobals);
|
||||
}
|
||||
|
||||
|
74
sdk/lib/drivers/wdf/shared/support/fxwaitlock.cpp
Normal file
74
sdk/lib/drivers/wdf/shared/support/fxwaitlock.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxWaitLock.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the FxWaitLock's factory method.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
#if defined(EVENT_TRACING)
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxWaitLock.tmh"
|
||||
}
|
||||
#endif
|
||||
|
||||
__checkReturn
|
||||
NTSTATUS
|
||||
FxWaitLock::_Create(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
|
||||
__in_opt FxObject* ParentObject,
|
||||
__in BOOLEAN AssignDriverAsDefaultParent,
|
||||
__out WDFWAITLOCK* LockHandle
|
||||
)
|
||||
{
|
||||
FxWaitLock* lock;
|
||||
NTSTATUS status;
|
||||
|
||||
*LockHandle = NULL;
|
||||
|
||||
lock = new (FxDriverGlobals, Attributes) FxWaitLock(FxDriverGlobals);
|
||||
if (lock == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
|
||||
"Memory allocation failed: %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = lock->Initialize();
|
||||
if (!NT_SUCCESS(status)) {
|
||||
lock->DeleteFromFailedCreate();
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
|
||||
"faield to initialize wait lock: %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = lock->Commit(Attributes,
|
||||
(WDFOBJECT*)LockHandle,
|
||||
ParentObject,
|
||||
AssignDriverAsDefaultParent);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
lock->DeleteFromFailedCreate();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
184
sdk/lib/drivers/wdf/shared/support/fxwaitlockapi.cpp
Normal file
184
sdk/lib/drivers/wdf/shared/support/fxwaitlockapi.cpp
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxWaitLockAPI.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the external APIs for FxWaitLock
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
// extern the entire file
|
||||
extern "C" {
|
||||
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
NTSTATUS
|
||||
WDFAPI
|
||||
WDFEXPORT(WdfWaitLockCreate)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in_opt
|
||||
PWDF_OBJECT_ATTRIBUTES LockAttributes,
|
||||
__out
|
||||
WDFWAITLOCK* Lock
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Creates a lock object which can be acquired at PASSIVE_LEVEL and will return
|
||||
to the caller at PASSIVE_LEVEL once acquired.
|
||||
|
||||
Arguments:
|
||||
LockAttributes - generic attributes to be associated with the created lock
|
||||
|
||||
Lock - pointer to receive the newly created lock
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS fxDriverGlobals;
|
||||
NTSTATUS status;
|
||||
FxObject* parent;
|
||||
|
||||
fxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
|
||||
parent = NULL;
|
||||
|
||||
//
|
||||
// Get the parent's globals if it is present
|
||||
//
|
||||
if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(fxDriverGlobals,
|
||||
LockAttributes))) {
|
||||
FxObjectHandleGetPtrAndGlobals(fxDriverGlobals,
|
||||
LockAttributes->ParentObject,
|
||||
FX_TYPE_OBJECT,
|
||||
(PVOID*)&parent,
|
||||
&fxDriverGlobals);
|
||||
}
|
||||
|
||||
FxPointerNotNull(fxDriverGlobals, Lock);
|
||||
|
||||
status = FxValidateObjectAttributes(fxDriverGlobals, LockAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return FxWaitLock::_Create(fxDriverGlobals,
|
||||
LockAttributes,
|
||||
parent,
|
||||
TRUE,
|
||||
Lock);
|
||||
}
|
||||
|
||||
__drv_when(Timeout != 0, _Must_inspect_result_)
|
||||
__drv_when(Timeout == 0, __drv_maxIRQL(PASSIVE_LEVEL))
|
||||
__drv_when(Timeout != 0 && *Timeout == 0, __drv_maxIRQL(DISPATCH_LEVEL))
|
||||
__drv_when(Timeout != 0 && *Timeout != 0, __drv_maxIRQL(PASSIVE_LEVEL))
|
||||
NTSTATUS
|
||||
WDFAPI
|
||||
WDFEXPORT(WdfWaitLockAcquire)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWAITLOCK Lock,
|
||||
__in_opt
|
||||
PLONGLONG Timeout
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Attempts to acquire the lock object. If a non NULL timeout is provided, the
|
||||
attempt to acquire the lock may fail if it cannot be acquired in the
|
||||
specified time.
|
||||
|
||||
Arguments:
|
||||
Lock - the lock to acquire
|
||||
|
||||
Timeout - optional timeout in acquiring the lock. If calling at an IRQL >=
|
||||
DISPATCH_LEVEL, then this parameter is not NULL (and should more
|
||||
then likely be zero)
|
||||
|
||||
Return Value:
|
||||
STATUS_TIMEOUT if a timeout was provided and the lock could not be acquired
|
||||
in the specified time, otherwise STATUS_SUCCESS
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxWaitLock* pLock;
|
||||
NTSTATUS status;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Lock,
|
||||
FX_TYPE_WAIT_LOCK,
|
||||
(PVOID*) &pLock,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
if (Timeout == NULL || *Timeout != 0) {
|
||||
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pLock->AcquireLock(pFxDriverGlobals, Timeout);
|
||||
}
|
||||
|
||||
__drv_maxIRQL(DISPATCH_LEVEL)
|
||||
VOID
|
||||
WDFAPI
|
||||
WDFEXPORT(WdfWaitLockRelease)(
|
||||
__in
|
||||
PWDF_DRIVER_GLOBALS DriverGlobals,
|
||||
__in
|
||||
WDFWAITLOCK Lock
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Releases a previously acquired wait lock
|
||||
|
||||
Arguments:
|
||||
Lock - the lock to release
|
||||
|
||||
--*/
|
||||
{
|
||||
DDI_ENTRY();
|
||||
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
||||
FxWaitLock* pLock;
|
||||
|
||||
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
|
||||
Lock,
|
||||
FX_TYPE_WAIT_LOCK,
|
||||
(PVOID*) &pLock,
|
||||
&pFxDriverGlobals);
|
||||
|
||||
pLock->ReleaseLock(pFxDriverGlobals);
|
||||
}
|
||||
|
||||
} // extern "C"
|
236
sdk/lib/drivers/wdf/shared/support/km/fxdeviceinterfacekm.cpp
Normal file
236
sdk/lib/drivers/wdf/shared/support/km/fxdeviceinterfacekm.cpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceInterfaceKM.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the device interface object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceInterfaceKM.tmh"
|
||||
}
|
||||
|
||||
FxDeviceInterface::FxDeviceInterface(
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for the object. Initializes all fields
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
RtlZeroMemory(&m_InterfaceClassGUID, sizeof(m_InterfaceClassGUID));
|
||||
|
||||
RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName));
|
||||
RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString));
|
||||
|
||||
m_Entry.Next = NULL;
|
||||
|
||||
m_State = FALSE;
|
||||
}
|
||||
|
||||
FxDeviceInterface::~FxDeviceInterface()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for FxDeviceInterface. Cleans up any allocations previously
|
||||
allocated.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
// the device interface should be off now
|
||||
ASSERT(m_State == FALSE);
|
||||
|
||||
// should no longer be in any list
|
||||
ASSERT(m_Entry.Next == NULL);
|
||||
|
||||
if (m_ReferenceString.Buffer != NULL) {
|
||||
FxPoolFree(m_ReferenceString.Buffer);
|
||||
RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString));
|
||||
}
|
||||
|
||||
if (m_SymbolicLinkName.Buffer != NULL) {
|
||||
RtlFreeUnicodeString(&m_SymbolicLinkName);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceInterface::Initialize(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in CONST GUID* InterfaceGUID,
|
||||
__in_opt PCUNICODE_STRING ReferenceString
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Initializes the object with the interface GUID and optional reference string
|
||||
|
||||
Arguments:
|
||||
InterfaceGUID - GUID describing the interface
|
||||
|
||||
ReferenceString - string used to differentiate between 2 interfaces on the
|
||||
same PDO
|
||||
|
||||
Return Value:
|
||||
STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
|
||||
|
||||
--*/
|
||||
{
|
||||
RtlCopyMemory(&m_InterfaceClassGUID, InterfaceGUID, sizeof(GUID));
|
||||
|
||||
if (ReferenceString != NULL) {
|
||||
return FxDuplicateUnicodeString(FxDriverGlobals,
|
||||
ReferenceString,
|
||||
&m_ReferenceString);
|
||||
}
|
||||
else {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FxDeviceInterface::SetState(
|
||||
__in BOOLEAN State
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Sets the state of the device interface
|
||||
|
||||
Arguments:
|
||||
State - the state to set
|
||||
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
m_State = State;
|
||||
|
||||
//
|
||||
// Only set the state if the interface has been registered
|
||||
//
|
||||
if (m_SymbolicLinkName.Buffer != NULL) {
|
||||
Mx::MxSetDeviceInterfaceState(&m_SymbolicLinkName, m_State);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceInterface::Register(
|
||||
__in PDEVICE_OBJECT Pdo
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Registers the device interface for a given PDO
|
||||
|
||||
Arguments:
|
||||
Pdo - PDO for the device stack
|
||||
|
||||
|
||||
Return Value:
|
||||
returned by IoRegisterDeviceInterface
|
||||
|
||||
--*/
|
||||
{
|
||||
PUNICODE_STRING pString;
|
||||
|
||||
if (m_ReferenceString.Length > 0) {
|
||||
pString = &m_ReferenceString;
|
||||
}
|
||||
else {
|
||||
pString = NULL;
|
||||
}
|
||||
|
||||
return Mx::MxRegisterDeviceInterface(
|
||||
Pdo, &m_InterfaceClassGUID, pString, &m_SymbolicLinkName);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceInterface::Register(
|
||||
_In_ FxDevice* Device
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
MdDeviceObject pdo;
|
||||
|
||||
pdo = Device->GetSafePhysicalDevice();
|
||||
|
||||
if (pdo != NULL) {
|
||||
status = Register(pdo);
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Leave the device interface unregistered. When we are in hardware
|
||||
// available, we will register there once we know for sure we have a
|
||||
// real live PDO that the system has acknowledged.
|
||||
//
|
||||
DO_NOTHING();
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxDeviceInterface::GetSymbolicLinkName(
|
||||
_In_ FxString* LinkString
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
if (m_SymbolicLinkName.Buffer == NULL) {
|
||||
//
|
||||
// The device interface has not yet been registered b/c it
|
||||
// belongs to a PDO and the PDO has not been recognized by
|
||||
// pnp yet.
|
||||
//
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
UNREFERENCED_PARAMETER(LinkString);
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Attempt a copy
|
||||
//
|
||||
status = LinkString->Assign(&m_SymbolicLinkName);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
296
sdk/lib/drivers/wdf/shared/support/km/fxregkeykm.cpp
Normal file
296
sdk/lib/drivers/wdf/shared/support/km/fxregkeykm.cpp
Normal file
|
@ -0,0 +1,296 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRegKey.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxRegKeyKM.tmh"
|
||||
}
|
||||
|
||||
#define AT_PASSIVE() ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL)
|
||||
|
||||
FxRegKey::FxRegKey(
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxPagedObject(FX_TYPE_REG_KEY, sizeof(FxRegKey), FxDriverGlobals),
|
||||
m_Key(NULL),
|
||||
m_Globals(FxDriverGlobals)
|
||||
{
|
||||
}
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
FxRegKey::~FxRegKey()
|
||||
{
|
||||
if (m_Key != NULL) {
|
||||
ZwClose(m_Key);
|
||||
m_Key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxRegKey::_Close(
|
||||
__in HANDLE Key
|
||||
)
|
||||
{
|
||||
return ZwClose(Key);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxRegKey::_Create(
|
||||
__in_opt HANDLE ParentKey,
|
||||
__in PCUNICODE_STRING KeyName,
|
||||
__out HANDLE* NewKey,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in ULONG CreateOptions,
|
||||
__out_opt PULONG CreateDisposition
|
||||
)
|
||||
{
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
|
||||
AT_PASSIVE();
|
||||
|
||||
//
|
||||
// Force OBJ_KERNEL_HANDLE because we are never passing the handle back
|
||||
// up to a process and we don't want to create a handle in an arbitrary
|
||||
// process from which that process can close the handle out from underneath
|
||||
// us.
|
||||
//
|
||||
InitializeObjectAttributes(
|
||||
&oa,
|
||||
(PUNICODE_STRING) KeyName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
ParentKey,
|
||||
NULL);
|
||||
|
||||
return ZwCreateKey(NewKey,
|
||||
DesiredAccess,
|
||||
&oa,
|
||||
0,
|
||||
0,
|
||||
CreateOptions,
|
||||
CreateDisposition);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxRegKey::_OpenKey(
|
||||
__in_opt HANDLE ParentKey,
|
||||
__in PCUNICODE_STRING KeyName,
|
||||
__out HANDLE* Key,
|
||||
__in ACCESS_MASK DesiredAccess
|
||||
)
|
||||
{
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
|
||||
AT_PASSIVE();
|
||||
|
||||
//
|
||||
// Force OBJ_KERNEL_HANDLE because we are never passing the handle back
|
||||
// up to a process and we don't want to create a handle in an arbitrary
|
||||
// process from which that process can close the handle out from underneath
|
||||
// us.
|
||||
//
|
||||
InitializeObjectAttributes(
|
||||
&oa,
|
||||
(PUNICODE_STRING)KeyName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
ParentKey,
|
||||
NULL);
|
||||
|
||||
return ZwOpenKey(Key, DesiredAccess, &oa);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxRegKey::_SetValue(
|
||||
_In_ HANDLE Key,
|
||||
__in PCUNICODE_STRING ValueName,
|
||||
__in ULONG ValueType,
|
||||
__in_bcount(ValueLength) PVOID Value,
|
||||
__in ULONG ValueLength
|
||||
)
|
||||
{
|
||||
AT_PASSIVE();
|
||||
|
||||
return ZwSetValueKey(Key,
|
||||
(PUNICODE_STRING)ValueName,
|
||||
0,
|
||||
ValueType,
|
||||
Value,
|
||||
ValueLength);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxRegKey::_QueryValue(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in HANDLE Key,
|
||||
__in PCUNICODE_STRING ValueName,
|
||||
__in ULONG ValueLength,
|
||||
__out_bcount_opt(ValueLength) PVOID Value,
|
||||
__out_opt PULONG ValueLengthQueried,
|
||||
__out_opt PULONG ValueType
|
||||
)
|
||||
{
|
||||
KEY_VALUE_PARTIAL_INFORMATION *pPartial, partial;
|
||||
NTSTATUS status;
|
||||
ULONG length;
|
||||
|
||||
if (Value == NULL) {
|
||||
//
|
||||
// Caller wants just the length
|
||||
//
|
||||
pPartial = &partial;
|
||||
length = _ComputePartialSize(0);
|
||||
RtlZeroMemory(&partial, length);
|
||||
}
|
||||
else {
|
||||
length = _ComputePartialSize(ValueLength);
|
||||
pPartial = (PKEY_VALUE_PARTIAL_INFORMATION)
|
||||
MxMemory::MxAllocatePoolWithTag(PagedPool, length, FxDriverGlobals->Tag);
|
||||
|
||||
if (pPartial == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We always pass a buffer of at least sizeof(KEY_VALUE_PARTIAL_INFORMATION)
|
||||
// to ZwQueryValueKey. This means that ZwQueryValueKey will write at least
|
||||
// some information to the buffer it receives, even if the user-supplied data
|
||||
// buffer is NULL or too small.
|
||||
//
|
||||
// According to ZwQueryValueKey's contract, this means that it will never return
|
||||
// STATUS_BUFFER_TOO_SMALL (returned when no data is written). Therefore, if the
|
||||
// user passes a NULL or insufficient buffer and the value exists in the registry,
|
||||
// ZwQueryValueKey will return STATUS_BUFFER_OVERFLOW.
|
||||
//
|
||||
status = ZwQueryValueKey(Key,
|
||||
(PUNICODE_STRING)ValueName,
|
||||
KeyValuePartialInformation,
|
||||
pPartial,
|
||||
length,
|
||||
&length);
|
||||
|
||||
if (NT_SUCCESS(status) && Value != NULL && (ValueLength >= pPartial->DataLength)) {
|
||||
RtlCopyMemory(Value, &pPartial->Data[0], pPartial->DataLength);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
|
||||
if (ValueLengthQueried != NULL) {
|
||||
*ValueLengthQueried = pPartial->DataLength;
|
||||
}
|
||||
if (ValueType != NULL) {
|
||||
*ValueType = pPartial->Type;
|
||||
}
|
||||
}
|
||||
|
||||
if (pPartial != &partial) {
|
||||
MxMemory::MxFreePool(pPartial);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxRegKey::_QueryULong(
|
||||
__in HANDLE Key,
|
||||
__in PCUNICODE_STRING ValueName,
|
||||
__out PULONG Value
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG length;
|
||||
|
||||
PKEY_VALUE_PARTIAL_INFORMATION pPartial;
|
||||
UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(ULONG))];
|
||||
|
||||
length = sizeof(buffer);
|
||||
pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0];
|
||||
|
||||
status = ZwQueryValueKey(Key,
|
||||
(PUNICODE_STRING)ValueName,
|
||||
KeyValuePartialInformation,
|
||||
pPartial,
|
||||
length,
|
||||
&length);
|
||||
|
||||
if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
|
||||
pPartial->Type != REG_DWORD) {
|
||||
status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
ASSERT(sizeof(ULONG) == pPartial->DataLength);
|
||||
|
||||
RtlCopyMemory(Value, &pPartial->Data[0], sizeof(ULONG));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
FxRegKey::_QueryQuadWord(
|
||||
__in HANDLE Key,
|
||||
__in PCUNICODE_STRING ValueName,
|
||||
__out PLARGE_INTEGER Value
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG length;
|
||||
|
||||
PKEY_VALUE_PARTIAL_INFORMATION pPartial;
|
||||
UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(LARGE_INTEGER))];
|
||||
|
||||
length = sizeof(buffer);
|
||||
pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0];
|
||||
|
||||
status = ZwQueryValueKey(Key,
|
||||
(PUNICODE_STRING)ValueName,
|
||||
KeyValuePartialInformation,
|
||||
pPartial,
|
||||
length,
|
||||
&length);
|
||||
|
||||
if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
|
||||
pPartial->Type != REG_QWORD) {
|
||||
status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
ASSERT(sizeof(LARGE_INTEGER) == pPartial->DataLength);
|
||||
|
||||
RtlCopyMemory(Value, &pPartial->Data[0], sizeof(LARGE_INTEGER));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
277
sdk/lib/drivers/wdf/shared/support/km/fxrequestbufferkm.cpp
Normal file
277
sdk/lib/drivers/wdf/shared/support/km/fxrequestbufferkm.cpp
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRequestBufferKm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a memory union object
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxRequestBufferKm.tmh"
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRequestBuffer::GetOrAllocateMdl(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__deref_out_opt PMDL* Mdl,
|
||||
__inout PMDL* MdlToFree,
|
||||
__inout PBOOLEAN UnlockWhenFreed,
|
||||
__in LOCK_OPERATION Operation,
|
||||
__in BOOLEAN ReuseMdl,
|
||||
__inout_opt size_t* SizeOfMdl
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function attempts to reuse the passed-in MDL (if any) or allocates
|
||||
a new MDL if reuse flag isn't passed-in or if the existing MDL isn't
|
||||
big enough.
|
||||
|
||||
Arguments:
|
||||
|
||||
Return Value:
|
||||
FxDriverGlobals - Driver globals
|
||||
|
||||
Mdl - on return it contains the MDL allocated/reused
|
||||
|
||||
MdlToFree - pointer to any MDL
|
||||
* to be reused, if the size is <= current size, or
|
||||
* freed and set to newly allocated MDL
|
||||
|
||||
UnlockWhenFreed - whether to unlock pages when freeing MDL
|
||||
(if FALSE, MDL may represent just MDL buffer but the pages
|
||||
might have already been unlocked)
|
||||
|
||||
Operation - Operation to pass to MmLockPages
|
||||
|
||||
ReuseMdl - whether to reuse *MdlToFree
|
||||
Please note that this can be FALSE even when MDL is supplied
|
||||
|
||||
SizeOfMdl - on input contains size of *MdlToFree,
|
||||
on return contains size of *Mdl
|
||||
|
||||
Remarks:
|
||||
|
||||
*MdlToFree is modified only when this function frees the passed in MDL
|
||||
Otherwise it leaves it untouched. Caller is responsible for storing
|
||||
properly initialized value and/or freeing what's stored in the value.
|
||||
|
||||
--*/
|
||||
{
|
||||
PVOID pBuf;
|
||||
NTSTATUS status;
|
||||
ULONG length;
|
||||
BOOLEAN oldUnlockValue;
|
||||
|
||||
pBuf = NULL;
|
||||
|
||||
oldUnlockValue = *UnlockWhenFreed;
|
||||
|
||||
//
|
||||
// Format functions that use this helper call
|
||||
// FxRequestBase::ValidateTarget which calls ContextReleaseAndRestore
|
||||
// which unlocks any locked pages.
|
||||
//
|
||||
// Hence pages must already be unlocked now. Let's assert that.
|
||||
//
|
||||
// This condition needs to be true since we unconditionally set
|
||||
// *UnlockWhenFreed to FALSE just below.
|
||||
//
|
||||
ASSERT (oldUnlockValue == FALSE);
|
||||
|
||||
*UnlockWhenFreed = FALSE;
|
||||
|
||||
//
|
||||
// Even if ReuseMdl is not true, SizeOfMdl may be supplied to store
|
||||
// the size of allocated MDL to be used later
|
||||
//
|
||||
ASSERT(ReuseMdl ? (SizeOfMdl != NULL && *MdlToFree != NULL) : TRUE);
|
||||
|
||||
switch (DataType) {
|
||||
case FxRequestBufferUnspecified:
|
||||
*Mdl = NULL;
|
||||
//
|
||||
// We should not set *MdlToFree to NULL as *MdlToFree might have a valid
|
||||
// MDL which we should not overwrite with NULL without freeing it
|
||||
//
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
case FxRequestBufferMemory:
|
||||
if (u.Memory.Offsets != NULL) {
|
||||
pBuf = WDF_PTR_ADD_OFFSET(u.Memory.Memory->GetBuffer(),
|
||||
u.Memory.Offsets->BufferOffset);
|
||||
}
|
||||
else {
|
||||
pBuf = u.Memory.Memory->GetBuffer();
|
||||
}
|
||||
// || ||
|
||||
// \/ \/ fall through
|
||||
|
||||
case FxRequestBufferBuffer:
|
||||
if (pBuf == NULL) {
|
||||
pBuf = u.Buffer.Buffer;
|
||||
}
|
||||
|
||||
length = GetBufferLength();
|
||||
status = GetOrAllocateMdlWorker(FxDriverGlobals,
|
||||
Mdl,
|
||||
&ReuseMdl,
|
||||
length,
|
||||
pBuf,
|
||||
SizeOfMdl,
|
||||
oldUnlockValue,
|
||||
MdlToFree
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"Couldn't allocate memory for MDL of length 0x%x %!STATUS!", length, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// If we are reusing the MDL we need to initialize it with current
|
||||
// buffer.
|
||||
//
|
||||
if (ReuseMdl == TRUE) {
|
||||
Mx::MxInitializeMdl(*Mdl, pBuf, length);
|
||||
}
|
||||
|
||||
status = FxProbeAndLockWithAccess(*Mdl, KernelMode, Operation);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"Couldn't lock pages for MDL 0x%p %!STATUS!", *Mdl, status);
|
||||
|
||||
//
|
||||
// Free MDL only if it was not reused.
|
||||
//
|
||||
if (ReuseMdl == FALSE) {
|
||||
FxMdlFree(FxDriverGlobals, *Mdl);
|
||||
}
|
||||
|
||||
*Mdl = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
*UnlockWhenFreed = TRUE;
|
||||
*MdlToFree = *Mdl;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
case FxRequestBufferMdl:
|
||||
*Mdl = u.Mdl.Mdl;
|
||||
//
|
||||
// We should not set *MdlToFree to NULL as *MdlToFree might have a valid
|
||||
// MDL which we should not overwrite with NULL without freeing it
|
||||
//
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
case FxRequestBufferReferencedMdl:
|
||||
if (u.RefMdl.Offsets == NULL ||
|
||||
(u.RefMdl.Offsets->BufferOffset == 0 && u.RefMdl.Offsets->BufferLength == 0)) {
|
||||
*Mdl = u.RefMdl.Mdl;
|
||||
//
|
||||
// We should not set *MdlToFree to NULL as *MdlToFree might have a valid
|
||||
// MDL which we should not overwrite with NULL without freeing it
|
||||
//
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Do not use MmGetSystemAddressForMdlSafe because StartVa could be
|
||||
// in UM while MappedVa (obviously) is in KM. Since
|
||||
// IoBuildPartial Mdl basically uses
|
||||
// pBuf - MmGetMdlVirtualAddress(SrcMdl) to compute offset, if one
|
||||
// VA is in UM (e.g. MmGetMdlVirtualAddress(SrcMdl)), you get the
|
||||
// (drastically) wrong offset.
|
||||
//
|
||||
pBuf = Mx::MxGetMdlVirtualAddress(u.RefMdl.Mdl);
|
||||
ASSERT(pBuf != NULL);
|
||||
|
||||
pBuf = WDF_PTR_ADD_OFFSET(pBuf, u.RefMdl.Offsets->BufferOffset);
|
||||
|
||||
//
|
||||
// GetBufferLength will compute the correct length with the given offsets
|
||||
//
|
||||
length = GetBufferLength();
|
||||
status = GetOrAllocateMdlWorker(FxDriverGlobals,
|
||||
Mdl,
|
||||
&ReuseMdl,
|
||||
length,
|
||||
pBuf,
|
||||
SizeOfMdl,
|
||||
oldUnlockValue,
|
||||
MdlToFree
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
|
||||
"Couldn't allocate memory for MDL of length 0x%x %!STATUS!", length, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
Mx::MxBuildPartialMdl(
|
||||
u.RefMdl.Mdl,
|
||||
*Mdl,
|
||||
pBuf,
|
||||
length
|
||||
);
|
||||
|
||||
*MdlToFree = *Mdl;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
default:
|
||||
*Mdl = NULL;
|
||||
//
|
||||
// We should not set *MdlToFree to NULL as *MdlToFree might have a valid
|
||||
// MDL which we should not overwrite with NULL without freeing it
|
||||
//
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestBuffer::SetMemory(
|
||||
__in IFxMemory* Memory,
|
||||
__in PWDFMEMORY_OFFSET Offsets
|
||||
)
|
||||
{
|
||||
PMDL pMdl;
|
||||
|
||||
pMdl = Memory->GetMdl();
|
||||
if (pMdl != NULL) {
|
||||
DataType = FxRequestBufferReferencedMdl;
|
||||
u.RefMdl.Memory = Memory;
|
||||
u.RefMdl.Offsets = Offsets;
|
||||
u.RefMdl.Mdl = pMdl;
|
||||
}
|
||||
else {
|
||||
DataType = FxRequestBufferMemory;
|
||||
u.Memory.Memory = Memory;
|
||||
u.Memory.Offsets = Offsets;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxResourceCollection.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a base object for derived collection classes and
|
||||
the derived collection classes.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
#if defined(EVENT_TRACING)
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxResourceCollectionKm.tmh"
|
||||
}
|
||||
#endif
|
||||
|
||||
FxCmResList::~FxCmResList()
|
||||
{
|
||||
}
|
||||
|
||||
|
41
sdk/lib/drivers/wdf/shared/support/km/fxsupportpchkm.hpp
Normal file
41
sdk/lib/drivers/wdf/shared/support/km/fxsupportpchkm.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
fxsupportpchkm.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_KM_HPP__
|
||||
#define __FX_SUPPORT_PCH_KM_HPP__
|
||||
|
||||
extern "C" {
|
||||
#include <mx.h>
|
||||
}
|
||||
|
||||
#include <fxmin.hpp>
|
||||
|
||||
#include "FxCollection.hpp"
|
||||
#include "StringUtil.hpp"
|
||||
#include "FxString.hpp"
|
||||
#include "FxDeviceText.hpp"
|
||||
#include "FxWaitLock.hpp"
|
||||
|
||||
#include <WdfResource.h>
|
||||
#include <FxResource.hpp>
|
||||
|
||||
#endif // __FX_SUPPORT_PCH_KM_HPP__
|
732
sdk/lib/drivers/wdf/shared/support/km/fxtelemetrykm.cpp
Normal file
732
sdk/lib/drivers/wdf/shared/support/km/fxtelemetrykm.cpp
Normal file
|
@ -0,0 +1,732 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxTelemetryKm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a telemetry methods.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxsupportpch.hpp"
|
||||
#include "fxldr.h"
|
||||
#include <ntstrsafe.h>
|
||||
#include <winmeta.h>
|
||||
#include <telemetry\microsofttelemetry.h>
|
||||
|
||||
extern "C" {
|
||||
#if defined(EVENT_TRACING)
|
||||
#include "FxTelemetryKm.tmh"
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ec044b58-3d13-3d13-936f-7b67dfb3e */
|
||||
TRACELOGGING_DEFINE_PROVIDER(g_TelemetryProvider,
|
||||
KMDF_FX_TRACE_LOGGING_PROVIDER_NAME,
|
||||
(0xec044b58, 0x3d13, 0x4880, 0x93, 0x6f, 0x7b, 0x67, 0xdf, 0xb3, 0xe0, 0x56),
|
||||
TraceLoggingOptionMicrosoftTelemetry());
|
||||
|
||||
VOID
|
||||
AllocAndInitializeTelemetryContext(
|
||||
_In_ PFX_TELEMETRY_CONTEXT* TelemetryContext
|
||||
)
|
||||
{
|
||||
PFX_TELEMETRY_CONTEXT context = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
context = (PFX_TELEMETRY_CONTEXT)MxMemory::MxAllocatePoolWithTag(
|
||||
NonPagedPool,
|
||||
sizeof(FX_TELEMETRY_CONTEXT),
|
||||
FX_TAG);
|
||||
if (NULL == context) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = ExUuidCreate(&(context->DriverSessionGUID));
|
||||
if (!NT_SUCCESS(status)) {
|
||||
MxMemory::MxFreePool(context);
|
||||
context = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
context->DoOnceFlagsBitmap = 0;
|
||||
|
||||
exit:
|
||||
*TelemetryContext = context;
|
||||
}
|
||||
|
||||
VOID
|
||||
RegisterTelemetryProvider(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
TraceLoggingRegister(g_TelemetryProvider);
|
||||
}
|
||||
|
||||
VOID
|
||||
UnregisterTelemetryProvider(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
TraceLoggingUnregister(g_TelemetryProvider);
|
||||
}
|
||||
|
||||
VOID
|
||||
LogDeviceStartTelemetryEvent(
|
||||
_In_ PFX_DRIVER_GLOBALS DriverGlobals,
|
||||
_In_opt_ FxDevice* Fdo
|
||||
)
|
||||
{
|
||||
//
|
||||
// See if telemetry registered and all the criteria to log is met.
|
||||
if (IsLoggingEnabledAndNeeded(DriverGlobals) == FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Log driver info stream
|
||||
//
|
||||
LogDriverInfoStream(DriverGlobals, Fdo);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
IsLoggingEnabledAndNeeded(
|
||||
_In_ PFX_DRIVER_GLOBALS DriverGlobals
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER lastLoggedTime;
|
||||
LARGE_INTEGER currentTime;
|
||||
LONGLONG delta;
|
||||
|
||||
// If provider is not enabled exit.
|
||||
if (FALSE == FX_TELEMETRY_ENABLED(g_TelemetryProvider, DriverGlobals)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ASSERT(DriverGlobals->TelemetryContext);
|
||||
|
||||
//
|
||||
// If we already fired an event during PnP start we are done. This avoids
|
||||
// repeatedly firing events during PnP rebalance.
|
||||
//
|
||||
if (InterlockedBitTestAndSet(
|
||||
&DriverGlobals->TelemetryContext->DoOnceFlagsBitmap,
|
||||
DeviceStartEventBit) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// log only if it has been MIN_HOURS_BEFORE_NEXT_LOG time since last log.
|
||||
// We don't log every time driver loads to avoid sending too much data
|
||||
// too many times in case of a buggy driver going through load/unload cycle
|
||||
// or when a device is plugged in two many times.
|
||||
//
|
||||
lastLoggedTime.QuadPart = 0;
|
||||
RegistryReadLastLoggedTime(DriverGlobals, &lastLoggedTime);
|
||||
|
||||
if (lastLoggedTime.QuadPart == 0) {
|
||||
//
|
||||
// driver is loading for first time ater install so need to log
|
||||
// event
|
||||
//
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Mx::MxQuerySystemTime(¤tTime);
|
||||
|
||||
delta = (currentTime.QuadPart - lastLoggedTime.QuadPart);
|
||||
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
|
||||
"lastlogged %I64x, current %I64x, delta %I64x",
|
||||
lastLoggedTime.QuadPart, currentTime.QuadPart, delta);
|
||||
|
||||
//
|
||||
// KeQuerySystemTime returns time in 100-ns. We convert MIN_HOURS_BEFORE_NEXT_LOG
|
||||
// to 100-nano sec unit and then compare.
|
||||
//
|
||||
if (delta < WDF_ABS_TIMEOUT_IN_SEC(MIN_HOURS_BEFORE_NEXT_LOG * 60 * 60)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
LogDriverInfoStream(
|
||||
_In_ PFX_DRIVER_GLOBALS DriverGlobals,
|
||||
_In_opt_ FxDevice* Fdo
|
||||
)
|
||||
{
|
||||
FxTelemetryDriverInfo driverInfo = {0};
|
||||
FxAutoString hardwareIDs, setupClass, busEnum, manufacturer;
|
||||
|
||||
//
|
||||
// Log driver and device info
|
||||
//
|
||||
GetDriverInfo(DriverGlobals, Fdo, &driverInfo);
|
||||
|
||||
if (Fdo != NULL) {
|
||||
//
|
||||
// Get Setup class
|
||||
//
|
||||
FxGetDevicePropertyString(Fdo,
|
||||
DevicePropertyClassName,
|
||||
&setupClass.m_UnicodeString);
|
||||
//
|
||||
// Get Bus enumerator
|
||||
//
|
||||
FxGetDevicePropertyString(Fdo,
|
||||
DevicePropertyEnumeratorName,
|
||||
&busEnum.m_UnicodeString);
|
||||
//
|
||||
// Get hardware id multi-string
|
||||
//
|
||||
FxGetDevicePropertyString(Fdo,
|
||||
DevicePropertyHardwareID,
|
||||
&hardwareIDs.m_UnicodeString);
|
||||
|
||||
GetFirstHardwareId(&hardwareIDs.m_UnicodeString);
|
||||
|
||||
//
|
||||
// Get manufacturer
|
||||
//
|
||||
FxGetDevicePropertyString(Fdo,
|
||||
DevicePropertyManufacturer,
|
||||
&manufacturer.m_UnicodeString);
|
||||
}
|
||||
|
||||
KMDF_CENSUS_EVT_WRITE_DEVICE_START(g_TelemetryProvider,
|
||||
DriverGlobals,
|
||||
driverInfo,
|
||||
setupClass,
|
||||
busEnum,
|
||||
hardwareIDs,
|
||||
manufacturer);
|
||||
|
||||
//
|
||||
// write current time to registry
|
||||
//
|
||||
RegistryWriteCurrentTime(DriverGlobals);
|
||||
}
|
||||
|
||||
VOID
|
||||
GetFirstHardwareId(
|
||||
_Inout_ PUNICODE_STRING HardwareIds
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine returns the first hardware ID present in the multi-string.
|
||||
If the first string is longer than max allowed by Telemetry, a null value is
|
||||
returned instead of retruning a partial ID.
|
||||
|
||||
Arguments:
|
||||
|
||||
HardwareIds - a multi-string terminated by two unicode_nulls.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PWCHAR curr;
|
||||
USHORT lengthCch;
|
||||
|
||||
ASSERT(HardwareIds != NULL);
|
||||
|
||||
curr = (PWCHAR) HardwareIds->Buffer;
|
||||
lengthCch = (HardwareIds->Length)/sizeof(WCHAR);
|
||||
|
||||
//
|
||||
// if the caller supplied NULL buffer, then nothing to do.
|
||||
//
|
||||
if (curr == NULL) {
|
||||
RtlInitUnicodeString(HardwareIds, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// if the first element is NULL then update the length
|
||||
//
|
||||
if (*curr == UNICODE_NULL) {
|
||||
HardwareIds->Length = 0;
|
||||
HardwareIds->MaximumLength = HardwareIds->Length + sizeof(UNICODE_NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < lengthCch; i++, curr++) {
|
||||
|
||||
if (*curr == UNICODE_NULL) {
|
||||
//
|
||||
// We found the first string. Update size. We only want to keep the
|
||||
// first string.
|
||||
//
|
||||
HardwareIds->Length = (USHORT)(i * sizeof(WCHAR));
|
||||
HardwareIds->MaximumLength = HardwareIds->Length + sizeof(UNICODE_NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
GetDriverInfo(
|
||||
_In_ PFX_DRIVER_GLOBALS Globals,
|
||||
_In_opt_ FxDevice* Fdo,
|
||||
_Out_ FxTelemetryDriverInfo* DriverInfo
|
||||
)
|
||||
{
|
||||
FxPkgPnp* pnpPkg;
|
||||
USHORT devInfo = 0;
|
||||
|
||||
DriverInfo->bitmap.IsVerifierOn = Globals->FxVerifierOn;
|
||||
DriverInfo->bitmap.IsEnhancedVerifierOn = FLAG_TO_BOOL(Globals->FxEnhancedVerifierOptions, FxEnhancedVerifierFunctionTableHookMask);
|
||||
|
||||
if (Fdo == NULL) {
|
||||
//
|
||||
// this is for non-pnp or noDispatchOverride.
|
||||
//
|
||||
DriverInfo->bitmap.IsNonPnpDriver = FLAG_TO_BOOL(Globals->Public.DriverFlags, WdfDriverInitNonPnpDriver);
|
||||
DriverInfo->bitmap.IsNoDispatchOverride = FLAG_TO_BOOL(Globals->Public.DriverFlags, WdfDriverInitNoDispatchOverride);
|
||||
}
|
||||
else {
|
||||
pnpPkg = Fdo->m_PkgPnp;
|
||||
devInfo = Fdo->GetDeviceTelemetryInfoFlags();
|
||||
|
||||
DriverInfo->bitmap.IsFilter = Fdo->GetFdoPkg()->IsFilter();
|
||||
DriverInfo->bitmap.IsUsingRemoveLockOption = Fdo->IsRemoveLockEnabledForIo();
|
||||
DriverInfo->bitmap.IsUsingNonDefaultHardwareReleaseOrder = pnpPkg->IsDefaultReleaseHardwareOrder();
|
||||
DriverInfo->bitmap.IsPowerPolicyOwner = pnpPkg->IsPowerPolicyOwner();
|
||||
DriverInfo->bitmap.IsS0IdleWakeFromS0Enabled = pnpPkg->IsS0IdleWakeFromS0Enabled();
|
||||
DriverInfo->bitmap.IsS0IdleUsbSSEnabled = pnpPkg->IsS0IdleUsbSSEnabled();
|
||||
DriverInfo->bitmap.IsS0IdleSystemManaged = pnpPkg->IsS0IdleSystemManaged();
|
||||
DriverInfo->bitmap.IsSxWakeEnabled = pnpPkg->IsSxWakeEnabled();
|
||||
DriverInfo->bitmap.IsUsingLevelTriggeredLineInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoLineBasedLevelTriggeredInterrupt);
|
||||
DriverInfo->bitmap.IsUsingEdgeTriggeredLineInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoLineBasedEdgeTriggeredInterrupt);
|
||||
DriverInfo->bitmap.IsUsingMsiXOrSingleMsi22Interrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoMsiXOrSingleMsi22Interrupt);
|
||||
DriverInfo->bitmap.IsUsingMsi22MultiMessageInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoMsi22MultiMessageInterrupt);
|
||||
DriverInfo->bitmap.IsUsingMultipleInterrupt = pnpPkg->HasMultipleInterrupts();
|
||||
DriverInfo->bitmap.IsUsingPassiveLevelInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoPassiveLevelInterrupt);
|
||||
DriverInfo->bitmap.IsUsingBusMasterDma = IsDeviceInfoFlagSet(devInfo, DeviceInfoDmaBusMaster);
|
||||
DriverInfo->bitmap.IsUsingSystemDma = IsDeviceInfoFlagSet(devInfo, DeviceInfoDmaSystem);
|
||||
DriverInfo->bitmap.IsUsingSystemDmaDuplex = IsDeviceInfoFlagSet(devInfo, DeviceInfoDmaSystemDuplex);
|
||||
DriverInfo->bitmap.IsUsingStaticBusEnumration = IsDeviceInfoFlagSet(devInfo, DeviceInfoHasStaticChildren);
|
||||
DriverInfo->bitmap.IsUsingDynamicBusEnumeration = IsDeviceInfoFlagSet(devInfo, DeviceInfoHasDynamicChildren);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
RegistryReadLastLoggedTime(
|
||||
_In_ PFX_DRIVER_GLOBALS DriverGlobals,
|
||||
_Out_ PLARGE_INTEGER LastLoggedTime
|
||||
)
|
||||
{
|
||||
FxAutoRegKey hKey, hWdf;
|
||||
DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf");
|
||||
DECLARE_CONST_UNICODE_STRING(valueName, WDF_LAST_TELEMETRY_LOG_TIME_VALUE);
|
||||
LARGE_INTEGER value;
|
||||
NTSTATUS status;
|
||||
|
||||
ASSERT(LastLoggedTime != NULL);
|
||||
LastLoggedTime->QuadPart = 0;
|
||||
|
||||
status = FxRegKey::_OpenKey(NULL,
|
||||
DriverGlobals->Driver->GetRegistryPathUnicodeString(),
|
||||
&hWdf.m_Key,
|
||||
KEY_READ);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Unable to open driver's service key, status %!STATUS!", status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = FxRegKey::_OpenKey(hWdf.m_Key,
|
||||
¶metersPath,
|
||||
&hKey.m_Key,
|
||||
KEY_READ);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Unable to open driver's service parameters key, status %!STATUS!",
|
||||
status);
|
||||
return;
|
||||
}
|
||||
|
||||
value.QuadPart = 0;
|
||||
status = FxRegKey::_QueryQuadWord(
|
||||
hKey.m_Key, &valueName, &value);
|
||||
|
||||
//
|
||||
// Set value only on success.
|
||||
//
|
||||
if (NT_SUCCESS(status)) {
|
||||
LastLoggedTime->QuadPart = value.QuadPart;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
RegistryWriteCurrentTime(
|
||||
_In_ PFX_DRIVER_GLOBALS DriverGlobals
|
||||
)
|
||||
{
|
||||
FxAutoRegKey hDriver, hParameters, hWdf;
|
||||
DECLARE_CONST_UNICODE_STRING(parametersPart, L"Parameters");
|
||||
DECLARE_CONST_UNICODE_STRING(wdfPart, L"Wdf");
|
||||
LARGE_INTEGER currentTime;
|
||||
|
||||
//
|
||||
// Not defined with the macro because ZwSetValue doesn't use
|
||||
// PCUNICODE_STRING
|
||||
//
|
||||
UNICODE_STRING wdfTimeOfLastTelemetryLog;
|
||||
NTSTATUS status;
|
||||
|
||||
RtlInitUnicodeString(&wdfTimeOfLastTelemetryLog, WDF_LAST_TELEMETRY_LOG_TIME_VALUE);
|
||||
|
||||
status = FxRegKey::_OpenKey(NULL,
|
||||
DriverGlobals->Driver->GetRegistryPathUnicodeString(),
|
||||
&hDriver.m_Key,
|
||||
KEY_WRITE | KEY_READ
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, 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,
|
||||
¶metersPart,
|
||||
&hParameters.m_Key,
|
||||
KEY_WRITE | KEY_READ
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, 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(DriverGlobals, TRACE_LEVEL_ERROR, 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
|
||||
//
|
||||
currentTime.QuadPart = 0;
|
||||
Mx::MxQuerySystemTime(¤tTime);
|
||||
|
||||
status = Mx::MxSetValueKey(hWdf.m_Key,
|
||||
&wdfTimeOfLastTelemetryLog,
|
||||
0,
|
||||
REG_QWORD,
|
||||
¤tTime.QuadPart,
|
||||
sizeof(currentTime)
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Failed to record current time for Telemetry log, status %!STATUS!",
|
||||
status);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxGetDevicePropertyString(
|
||||
_In_ FxDevice* Fdo,
|
||||
_In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,
|
||||
_Out_ PUNICODE_STRING PropertyString
|
||||
)
|
||||
{
|
||||
MdDeviceObject pdo;
|
||||
NTSTATUS status;
|
||||
PFX_DRIVER_GLOBALS pFxDriverGlobals = Fdo->GetDriverGlobals();
|
||||
ULONG length = 0;
|
||||
PVOID buffer = NULL;
|
||||
|
||||
ASSERT(PropertyString != NULL);
|
||||
RtlZeroMemory(PropertyString, sizeof(UNICODE_STRING));
|
||||
|
||||
pdo = Fdo->GetSafePhysicalDevice();
|
||||
if (pdo == NULL) {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not get PDO from FDO WDFDEVICE 0x%p, %!STATUS!",
|
||||
Fdo->GetHandle(), status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = FxDevice::_GetDeviceProperty(pdo, DeviceProperty, 0, NULL, &length);
|
||||
if (status != STATUS_BUFFER_TOO_SMALL) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not retrieve property %d length %d, %!STATUS!",
|
||||
DeviceProperty, length, status);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, length);
|
||||
if (buffer == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not allocate memory for property %d length %d, %!STATUS!",
|
||||
DeviceProperty, length, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = FxDevice::_GetDeviceProperty(pdo, DeviceProperty, length, buffer, &length);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
||||
"Could not query for full buffer, size %d, for "
|
||||
"property %d, %!STATUS!",
|
||||
length, DeviceProperty, status);
|
||||
FxPoolFree(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyString->Buffer = (PWCH)buffer;
|
||||
PropertyString->Length = (USHORT) length - sizeof(UNICODE_NULL);
|
||||
PropertyString->MaximumLength = (USHORT) length;
|
||||
|
||||
//
|
||||
// ensure it's null terminated
|
||||
//
|
||||
PropertyString->Buffer[PropertyString->Length/sizeof(WCHAR)] = UNICODE_NULL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
GetImageName(
|
||||
_In_ PFX_DRIVER_GLOBALS DriverGlobals,
|
||||
_Out_ PUNICODE_STRING ImageName
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Retrieve the ImageName value from the named Service registry key.
|
||||
|
||||
Caller is responsible for freeing the buffer allocated in ImageName::Buffer.
|
||||
|
||||
Arguments:
|
||||
DriverGlobals - pointer to FX_DRIVER_GLOBALS
|
||||
|
||||
ImageeName - Pointer to a UNICODE_STRING which will receive the image name
|
||||
upon a return value of NT_SUCCESS()
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
NTSTATUS status;
|
||||
FxAutoRegKey hKey;
|
||||
DECLARE_CONST_UNICODE_STRING(valueName, L"ImagePath");
|
||||
UNICODE_STRING imagePath = {0};
|
||||
UNICODE_STRING imageName = {0};
|
||||
PKEY_VALUE_PARTIAL_INFORMATION value = NULL;
|
||||
USHORT size;
|
||||
|
||||
ASSERT(ImageName != NULL);
|
||||
RtlZeroMemory(ImageName, sizeof(UNICODE_STRING));
|
||||
|
||||
//
|
||||
// Open driver's Service base key
|
||||
//
|
||||
status = FxRegKey::_OpenKey(NULL,
|
||||
DriverGlobals->Driver->GetRegistryPathUnicodeString(),
|
||||
&hKey.m_Key,
|
||||
KEY_READ);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Unable to open driver's service key, status %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = QueryAndAllocString(hKey.m_Key,
|
||||
DriverGlobals,
|
||||
&valueName,
|
||||
&value);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Failed to get Image name from service key, status %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
BuildStringFromPartialInfo(value, &imagePath);
|
||||
|
||||
//
|
||||
// Now read the "ImagePath" and extract just the driver filename as a new
|
||||
// unicode string.
|
||||
//
|
||||
GetNameFromPath(&imagePath, &imageName);
|
||||
|
||||
if (imageName.Length == 0x0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"ERROR: GetNameFromPath could not find a name, status 0x%x\n",
|
||||
status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for interger overflow for length before we allocate memory
|
||||
// size = path->Length + sizeof(UNICODE_NULL);
|
||||
// len is used below to compute the string size including the NULL, so
|
||||
// compute len to include the terminating NULL.
|
||||
//
|
||||
status = RtlUShortAdd(imageName.Length, sizeof(UNICODE_NULL), &size);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"ERROR: size computation failed with Status 0x%x\n", status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
//
|
||||
// allocate a buffer to hold Unicode string + null char.
|
||||
//
|
||||
ImageName->Buffer = (PWCH) FxPoolAllocate(DriverGlobals, PagedPool, size);
|
||||
|
||||
if (ImageName->Buffer == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"ERROR: ExAllocatePoolWithTag failed with Status 0x%x\n", status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
RtlZeroMemory(ImageName->Buffer, size);
|
||||
ImageName->Length = 0x0;
|
||||
ImageName->MaximumLength = size;
|
||||
|
||||
status = RtlUnicodeStringCopy(ImageName, &imageName);
|
||||
|
||||
//
|
||||
// The copy cannot fail since we setup the buffer to hold enough space for
|
||||
// the contents of the ImagePath value.
|
||||
//
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
|
||||
cleanUp:
|
||||
|
||||
if (value != NULL) {
|
||||
FxPoolFree(value);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
_Must_inspect_result_
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
NTSTATUS
|
||||
QueryAndAllocString(
|
||||
_In_ HANDLE Key,
|
||||
_In_ PFX_DRIVER_GLOBALS Globals,
|
||||
_In_ PCUNICODE_STRING ValueName,
|
||||
_Out_ PKEY_VALUE_PARTIAL_INFORMATION* Info
|
||||
)
|
||||
{
|
||||
PKEY_VALUE_PARTIAL_INFORMATION info;
|
||||
NTSTATUS status;
|
||||
ULONG length;
|
||||
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
info = NULL;
|
||||
|
||||
ASSERT(Info != NULL);
|
||||
*Info = NULL;
|
||||
|
||||
status = Mx::MxQueryValueKey(Key,
|
||||
(PUNICODE_STRING)ValueName,
|
||||
KeyValuePartialInformation,
|
||||
NULL,
|
||||
0,
|
||||
&length);
|
||||
|
||||
if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//
|
||||
// Pool can be paged b/c we are running at PASSIVE_LEVEL and we are going
|
||||
// to free it at the end of this function.
|
||||
//
|
||||
status = RtlULongAdd(length,
|
||||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data),
|
||||
&length);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
info = (PKEY_VALUE_PARTIAL_INFORMATION) FxPoolAllocate(Globals,
|
||||
PagedPool,
|
||||
length);
|
||||
|
||||
if (info == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
RtlZeroMemory(info, length);
|
||||
|
||||
//
|
||||
// Query registry for the data under ValueName
|
||||
//
|
||||
status = Mx::MxQueryValueKey(Key,
|
||||
(PUNICODE_STRING) ValueName,
|
||||
KeyValuePartialInformation,
|
||||
info,
|
||||
length,
|
||||
&length);
|
||||
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
if (info->Type != REG_SZ && info->Type != REG_EXPAND_SZ) {
|
||||
status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (info->DataLength == 0 ||
|
||||
(info->DataLength % 2) != 0 ||
|
||||
(info->DataLength >
|
||||
(length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)))) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*Info = info;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (info != NULL) {
|
||||
FxPoolFree(info);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
308
sdk/lib/drivers/wdf/shared/support/stringutil.cpp
Normal file
308
sdk/lib/drivers/wdf/shared/support/stringutil.cpp
Normal file
|
@ -0,0 +1,308 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
StringUtil.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements string utlities in the framework
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
Both kernel and user mode
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "StringUtil.tmh"
|
||||
}
|
||||
|
||||
size_t
|
||||
FxCalculateTotalStringSize(
|
||||
__in FxCollectionInternal *StringCollection,
|
||||
__in BOOLEAN Verify,
|
||||
__out_opt PBOOLEAN ContainsOnlyStrings
|
||||
)
|
||||
{
|
||||
size_t cbLength;
|
||||
FxString *pString;
|
||||
FxCollectionEntry* cur, *end;
|
||||
|
||||
cbLength = 0;
|
||||
|
||||
end = StringCollection->End();
|
||||
for (cur = StringCollection->Start();
|
||||
cur != end;
|
||||
cur = cur->Next()) {
|
||||
pString = (FxString *) cur->m_Object;
|
||||
|
||||
if (Verify && pString->GetType() != FX_TYPE_STRING) {
|
||||
*ContainsOnlyStrings = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cbLength += pString->ByteLength(TRUE);
|
||||
}
|
||||
|
||||
if (ContainsOnlyStrings != NULL) {
|
||||
*ContainsOnlyStrings = TRUE;
|
||||
}
|
||||
|
||||
if (StringCollection->Count() == 0) {
|
||||
//
|
||||
// If there are not entries, we still need 2 NULLs
|
||||
//
|
||||
cbLength = sizeof(UNICODE_NULL) * 2;
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Extra NULL
|
||||
//
|
||||
cbLength += sizeof(UNICODE_NULL);
|
||||
}
|
||||
|
||||
//
|
||||
// ASSERT that we are reporting an integral number of WCHARs in bytes
|
||||
//
|
||||
ASSERT((cbLength % sizeof(WCHAR)) == 0);
|
||||
|
||||
return cbLength;
|
||||
}
|
||||
|
||||
size_t
|
||||
FxCalculateTotalMultiSzStringSize(
|
||||
__in __nullnullterminated PCWSTR MultiSz
|
||||
)
|
||||
{
|
||||
PCWSTR pCur;
|
||||
size_t cbSize, cbLength;
|
||||
|
||||
cbSize = 0;
|
||||
|
||||
pCur = MultiSz;
|
||||
|
||||
while (*pCur != NULL) {
|
||||
//
|
||||
// Compute length of string including terminating NULL
|
||||
//
|
||||
cbLength = (wcslen(pCur) + 1) * sizeof(WCHAR);
|
||||
|
||||
cbSize += cbLength;
|
||||
pCur = (PWSTR) WDF_PTR_ADD_OFFSET(pCur, cbLength);
|
||||
}
|
||||
|
||||
if (cbSize == 0) {
|
||||
//
|
||||
// If there are no strings, we still need 2 NULLs
|
||||
//
|
||||
cbSize = sizeof(UNICODE_NULL);
|
||||
}
|
||||
|
||||
//
|
||||
// Final NULL which makes this a multi sz
|
||||
//
|
||||
cbSize += sizeof(UNICODE_NULL);
|
||||
|
||||
//
|
||||
// ASSERT that we are reporting an integral number of WCHARs in bytes
|
||||
//
|
||||
ASSERT((cbSize % sizeof(WCHAR)) == 0);
|
||||
|
||||
return cbSize;
|
||||
}
|
||||
|
||||
#pragma prefast(push)
|
||||
// Caller is responsible for allocating the correct amount of memory.
|
||||
#pragma prefast(disable:__WARNING_INCORRECT_ANNOTATION_STRING )
|
||||
PWSTR
|
||||
FxCopyMultiSz(
|
||||
__out LPWSTR Buffer,
|
||||
__in FxCollectionInternal* StringCollection
|
||||
)
|
||||
{
|
||||
LPWSTR pCur;
|
||||
ULONG length;
|
||||
FxCollectionEntry* cur, *end;
|
||||
|
||||
pCur = Buffer;
|
||||
end = StringCollection->End();
|
||||
|
||||
for (cur = StringCollection->Start(); cur != end; cur = cur->Next()) {
|
||||
FxString* pSourceString;
|
||||
|
||||
pSourceString = (FxString *) cur->m_Object;
|
||||
|
||||
length = pSourceString->ByteLength(TRUE);
|
||||
RtlCopyMemory(pCur, pSourceString->Buffer(), length);
|
||||
|
||||
//
|
||||
// Length is expressed in number of bytes, not number of
|
||||
// characters.
|
||||
//
|
||||
// length includes the NULL.
|
||||
//
|
||||
pCur = WDF_PTR_ADD_OFFSET_TYPE(pCur, length, LPWSTR);
|
||||
}
|
||||
|
||||
//
|
||||
// If there are no entries, we still need 2 NULLs.
|
||||
//
|
||||
if (StringCollection->Count() == 0) {
|
||||
*pCur = UNICODE_NULL;
|
||||
pCur++;
|
||||
}
|
||||
|
||||
//
|
||||
// double NULL terminate the string
|
||||
//
|
||||
*pCur = UNICODE_NULL;
|
||||
|
||||
//
|
||||
// Return the start of the next location in the buffer
|
||||
//
|
||||
return pCur + 1;
|
||||
}
|
||||
#pragma prefast(pop)
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDuplicateUnicodeString(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in const UNICODE_STRING* Source,
|
||||
__out PUNICODE_STRING Destination
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Makes a deep copy from Source to Destination.
|
||||
|
||||
Destination is assumed to have been initialized by the caller, be owned by
|
||||
an internal Fx object. Destination could already contain a previously
|
||||
allocated buffer. If one exists and is large enough, it will be reused
|
||||
for the copy.
|
||||
|
||||
This function guarantees that the Buffer will be NULL terminated. While
|
||||
this is not necessary because Length describes the length of the buffer, the
|
||||
resulting buffer can be copied back to the client driver and we cannot trust
|
||||
the client driver to treat the string as an unterminated buffer, typically
|
||||
the client driver will just extract the buffer and treat it as NULL
|
||||
terminated. To be defensive with this type of (mis)use, we always NULL
|
||||
terminate the resuling Buffer.
|
||||
|
||||
Arguments:
|
||||
Source - source struct to copy from. This string can originate from the
|
||||
client driver.
|
||||
|
||||
Destination - destination struct to copy to. This struct is assumed to be
|
||||
internal and is not given to the outside caller
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
NTSTATUS status;
|
||||
USHORT srcCbLength, srcCbLengthAndNull, dstMaxCbLength;
|
||||
|
||||
//
|
||||
// NOTE: We assume the sources string will be smaller than 64k.
|
||||
//
|
||||
srcCbLength = Source->Length;
|
||||
dstMaxCbLength = Destination->MaximumLength;
|
||||
|
||||
status = RtlUShortAdd(srcCbLength,
|
||||
sizeof(UNICODE_NULL),
|
||||
&srcCbLengthAndNull);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"Interger overflow occured when duplicating string %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// First see if we already have enough memory to hold the string + a NULL
|
||||
//
|
||||
if (dstMaxCbLength < srcCbLengthAndNull) {
|
||||
//
|
||||
// Allocate enough memory for the source string and a NULL character
|
||||
//
|
||||
dstMaxCbLength = srcCbLengthAndNull;
|
||||
|
||||
//
|
||||
// We need to allocate memory. Free any old memory first.
|
||||
//
|
||||
if (Destination->Buffer != NULL) {
|
||||
FxPoolFree(Destination->Buffer);
|
||||
|
||||
RtlZeroMemory(Destination, sizeof(UNICODE_STRING));
|
||||
}
|
||||
|
||||
Destination->Buffer = (PWSTR) FxPoolAllocate(
|
||||
FxDriverGlobals, PagedPool, dstMaxCbLength);
|
||||
|
||||
if (Destination->Buffer == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
|
||||
"Failed to allocate memory when duplicating string %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
Destination->MaximumLength = dstMaxCbLength;
|
||||
}
|
||||
|
||||
//
|
||||
// If we get here and we have a buffer, then we can just copy the
|
||||
// string into the buffer.
|
||||
//
|
||||
RtlCopyMemory(Destination->Buffer, Source->Buffer, srcCbLength);
|
||||
Destination->Length = srcCbLength;
|
||||
|
||||
//
|
||||
// Make sure the string is NULL terminated and there is room for the NULL
|
||||
//
|
||||
ASSERT(Destination->Length + sizeof(UNICODE_NULL) <=
|
||||
Destination->MaximumLength);
|
||||
Destination->Buffer[Destination->Length/sizeof(WCHAR)] = UNICODE_NULL;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
PWCHAR
|
||||
FxDuplicateUnicodeStringToString(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in const UNICODE_STRING* Source
|
||||
)
|
||||
{
|
||||
PWSTR pDuplicate;
|
||||
|
||||
pDuplicate = (PWSTR) FxPoolAllocate(
|
||||
FxDriverGlobals, PagedPool, Source->Length + sizeof(UNICODE_NULL));
|
||||
|
||||
if (pDuplicate != NULL) {
|
||||
RtlCopyMemory(pDuplicate, Source->Buffer, Source->Length);
|
||||
|
||||
//
|
||||
// Make sure the string is NULL terminated. We can safely do this
|
||||
// because we allocated an extra WCHAR for the null terminator.
|
||||
//
|
||||
pDuplicate[Source->Length/sizeof(WCHAR)] = UNICODE_NULL;
|
||||
}
|
||||
|
||||
return pDuplicate;
|
||||
}
|
289
sdk/lib/drivers/wdf/shared/support/um/fxdeviceinterfaceum.cpp
Normal file
289
sdk/lib/drivers/wdf/shared/support/um/fxdeviceinterfaceum.cpp
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxDeviceInterfaceUM.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements the device interface object.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
User mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxDeviceInterfaceUM.tmh"
|
||||
}
|
||||
|
||||
FxDeviceInterface::FxDeviceInterface(
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Constructor for the object. Initializes all fields
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
RtlZeroMemory(&m_InterfaceClassGUID, sizeof(m_InterfaceClassGUID));
|
||||
|
||||
RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName));
|
||||
RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString));
|
||||
|
||||
m_Entry.Next = NULL;
|
||||
|
||||
m_State = FALSE;
|
||||
}
|
||||
|
||||
FxDeviceInterface::~FxDeviceInterface()
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Destructor for FxDeviceInterface. Cleans up any allocations previously
|
||||
allocated.
|
||||
|
||||
Arguments:
|
||||
None
|
||||
|
||||
Return Value:
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
// the device interface should be off now
|
||||
ASSERT(m_State == FALSE);
|
||||
|
||||
// should no longer be in any list
|
||||
ASSERT(m_Entry.Next == NULL);
|
||||
|
||||
if (m_ReferenceString.Buffer != NULL) {
|
||||
FxPoolFree(m_ReferenceString.Buffer);
|
||||
RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString));
|
||||
}
|
||||
|
||||
if (m_SymbolicLinkName.Buffer != NULL) {
|
||||
MxMemory::MxFreePool(m_SymbolicLinkName.Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceInterface::Initialize(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in CONST GUID* InterfaceGUID,
|
||||
__in_opt PCUNICODE_STRING ReferenceString
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Initializes the object with the interface GUID and optional reference string
|
||||
|
||||
Arguments:
|
||||
InterfaceGUID - GUID describing the interface
|
||||
|
||||
ReferenceString - string used to differentiate between 2 interfaces on the
|
||||
same PDO
|
||||
|
||||
Return Value:
|
||||
STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
|
||||
|
||||
--*/
|
||||
{
|
||||
RtlCopyMemory(&m_InterfaceClassGUID, InterfaceGUID, sizeof(GUID));
|
||||
|
||||
if (ReferenceString != NULL) {
|
||||
return FxDuplicateUnicodeString(FxDriverGlobals,
|
||||
ReferenceString,
|
||||
&m_ReferenceString);
|
||||
}
|
||||
else {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FxDeviceInterface::SetState(
|
||||
__in BOOLEAN State
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Sets the state of the device interface
|
||||
|
||||
Arguments:
|
||||
State - the state to set
|
||||
|
||||
|
||||
Return Value:
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr;
|
||||
NTSTATUS status;
|
||||
IWudfDeviceStack *pDeviceStack;
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Get the IWudfDeviceStack interface
|
||||
//
|
||||
pDeviceStack = m_Device->GetDeviceStackInterface();
|
||||
|
||||
//
|
||||
// Enable the interface
|
||||
//
|
||||
hr = pDeviceStack->SetDeviceInterfaceState(&this->m_InterfaceClassGUID,
|
||||
this->m_ReferenceString.Buffer,
|
||||
State);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
m_State = State;
|
||||
}
|
||||
else {
|
||||
status = FxDevice::NtStatusFromHr(pDeviceStack, hr);
|
||||
DoTraceLevelMessage(
|
||||
FxDevice::GetFxDevice(m_Device)->GetDriverGlobals(),
|
||||
TRACE_LEVEL_WARNING, TRACINGPNP,
|
||||
"Failed to %s device interface %!STATUS!",
|
||||
(State ? "enable" : "disable"), status);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceInterface::Register(
|
||||
__in MdDeviceObject DeviceObject
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Registers the device interface for a given PDO
|
||||
|
||||
Arguments:
|
||||
DeviceObject - FDO for the device stack in case of UM, and PDO for
|
||||
in case of KM.
|
||||
|
||||
Return Value:
|
||||
returned by IWudfDeviceStack::CreateDeviceInterface
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr;
|
||||
NTSTATUS status;
|
||||
IWudfDeviceStack *pDeviceStack;
|
||||
|
||||
m_Device = DeviceObject;
|
||||
|
||||
//
|
||||
// Get the IWudfDeviceStack interface
|
||||
//
|
||||
pDeviceStack = m_Device->GetDeviceStackInterface();
|
||||
|
||||
hr = pDeviceStack->CreateDeviceInterface(&m_InterfaceClassGUID,
|
||||
m_ReferenceString.Buffer);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
status = FxDevice::NtStatusFromHr(pDeviceStack, hr);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxDeviceInterface::Register(
|
||||
_In_ FxDevice* Device
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
//
|
||||
// For UMDF, PDO is already known so no reason to defer registration.
|
||||
// Also, note that Register takes fdo as parameter for UMDF.
|
||||
//
|
||||
status = Register(Device->GetDeviceObject());
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxDeviceInterface::GetSymbolicLinkName(
|
||||
_In_ FxString* LinkString
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PCWSTR symLink = NULL;
|
||||
|
||||
if (m_SymbolicLinkName.Buffer == NULL) {
|
||||
IWudfDeviceStack *pDeviceStack;
|
||||
IWudfDeviceStack2 *pDeviceStack2;
|
||||
|
||||
//
|
||||
// Get the IWudfDeviceStack interface
|
||||
//
|
||||
pDeviceStack = m_Device->GetDeviceStackInterface();
|
||||
HRESULT hrQI;
|
||||
HRESULT hr;
|
||||
|
||||
hrQI = pDeviceStack->QueryInterface(IID_IWudfDeviceStack2,
|
||||
(PVOID*)&pDeviceStack2);
|
||||
FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pDeviceStack2));
|
||||
pDeviceStack->Release();
|
||||
|
||||
//
|
||||
// Get the symbolic link
|
||||
//
|
||||
hr = pDeviceStack2->GetInterfaceSymbolicLink(&m_InterfaceClassGUID,
|
||||
m_ReferenceString.Buffer,
|
||||
&symLink);
|
||||
if (FAILED(hr)) {
|
||||
status = FxDevice::GetFxDevice(m_Device)->NtStatusFromHr(hr);
|
||||
}
|
||||
else {
|
||||
RtlInitUnicodeString(&m_SymbolicLinkName, symLink);
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Attempt a copy
|
||||
//
|
||||
status = LinkString->Assign(&m_SymbolicLinkName);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
302
sdk/lib/drivers/wdf/shared/support/um/fxregkeyum.cpp
Normal file
302
sdk/lib/drivers/wdf/shared/support/um/fxregkeyum.cpp
Normal file
|
@ -0,0 +1,302 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRegKey.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
user mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
//#define UNICODE
|
||||
//#define _UNICODE
|
||||
#include <Winreg.h>
|
||||
|
||||
extern "C" {
|
||||
#if defined(EVENT_TRACING)
|
||||
#include "FxRegKeyUM.tmh"
|
||||
#endif
|
||||
}
|
||||
|
||||
FxRegKey::FxRegKey(
|
||||
PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
) :
|
||||
FxPagedObject(FX_TYPE_REG_KEY, sizeof(FxRegKey), FxDriverGlobals),
|
||||
m_Key(NULL),
|
||||
m_Globals(FxDriverGlobals),
|
||||
m_CanCloseHandle(TRUE)
|
||||
{
|
||||
}
|
||||
|
||||
__drv_maxIRQL(PASSIVE_LEVEL)
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
FxRegKey::~FxRegKey()
|
||||
{
|
||||
if (m_Key != NULL) {
|
||||
if (m_CanCloseHandle == TRUE) {
|
||||
RegCloseKey((HKEY)m_Key);
|
||||
}
|
||||
m_Key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
FxRegKey::_Close(
|
||||
__in HANDLE Key
|
||||
)
|
||||
{
|
||||
DWORD err = RegCloseKey((HKEY)Key);
|
||||
|
||||
if (ERROR_SUCCESS == err) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return WinErrorToNtStatus(err);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
FxRegKey::_Create(
|
||||
__in_opt HANDLE ParentKey,
|
||||
__in PCUNICODE_STRING KeyName,
|
||||
__out HANDLE* NewKey,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in ULONG CreateOptions,
|
||||
__out_opt PULONG CreateDisposition
|
||||
)
|
||||
{
|
||||
HKEY parentKey;
|
||||
|
||||
if (NULL == ParentKey)
|
||||
{
|
||||
parentKey = HKEY_LOCAL_MACHINE;
|
||||
}
|
||||
else
|
||||
{
|
||||
parentKey = (HKEY) ParentKey;
|
||||
}
|
||||
|
||||
DWORD err = RegCreateKeyEx(parentKey,
|
||||
KeyName->Buffer,
|
||||
0,
|
||||
NULL,
|
||||
CreateOptions,
|
||||
DesiredAccess,
|
||||
NULL,
|
||||
(PHKEY)NewKey,
|
||||
CreateDisposition);
|
||||
|
||||
if (ERROR_SUCCESS == err) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return WinErrorToNtStatus(err);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
FxRegKey::_OpenKey(
|
||||
__in_opt HANDLE ParentKey,
|
||||
__in PCUNICODE_STRING KeyName,
|
||||
__out HANDLE* Key,
|
||||
__in ACCESS_MASK DesiredAccess
|
||||
)
|
||||
{
|
||||
HKEY parentKey;
|
||||
|
||||
if (NULL == ParentKey)
|
||||
{
|
||||
parentKey = HKEY_LOCAL_MACHINE;
|
||||
}
|
||||
else
|
||||
{
|
||||
parentKey = (HKEY) ParentKey;
|
||||
}
|
||||
|
||||
DWORD err = RegOpenKeyEx(parentKey,
|
||||
KeyName->Buffer,
|
||||
0,
|
||||
DesiredAccess,
|
||||
(PHKEY)Key);
|
||||
|
||||
if (ERROR_SUCCESS == err) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return WinErrorToNtStatus(err);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
FxRegKey::_SetValue(
|
||||
_In_ HANDLE Key,
|
||||
_In_ PCUNICODE_STRING ValueName,
|
||||
_In_ ULONG ValueType,
|
||||
_In_reads_bytes_(ValueLength) PVOID Value,
|
||||
_In_ ULONG ValueLength
|
||||
)
|
||||
{
|
||||
DWORD err;
|
||||
|
||||
err = RegSetValueEx((HKEY)Key,
|
||||
ValueName->Buffer,
|
||||
0,
|
||||
ValueType,
|
||||
(BYTE*)Value,
|
||||
ValueLength);
|
||||
if (ERROR_SUCCESS == err) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return WinErrorToNtStatus(err);
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
FxRegKey::_QueryValue(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in HANDLE Key,
|
||||
__in PCUNICODE_STRING ValueName,
|
||||
__in ULONG ValueLength,
|
||||
__out_bcount_opt(ValueLength) PVOID Value,
|
||||
__out_opt PULONG ValueLengthQueried,
|
||||
__out_opt PULONG ValueType
|
||||
)
|
||||
{
|
||||
DWORD err;
|
||||
NTSTATUS status;
|
||||
ULONG length;
|
||||
|
||||
UNREFERENCED_PARAMETER(FxDriverGlobals);
|
||||
ASSERT(Key != HKEY_PERFORMANCE_DATA);
|
||||
|
||||
length = ValueLength;
|
||||
|
||||
err = RegQueryValueEx((HKEY)Key,
|
||||
ValueName->Buffer,
|
||||
NULL,
|
||||
ValueType,
|
||||
(LPBYTE)Value,
|
||||
&length);
|
||||
|
||||
if (ValueLengthQueried != NULL) {
|
||||
*ValueLengthQueried = length;
|
||||
}
|
||||
|
||||
//
|
||||
// Please see the comment in FxRegKeyKm.cpp FxRegKey::_QueryValue about
|
||||
// the call to ZwQueryValueKey.
|
||||
//
|
||||
// If the user supplies a NULL data buffer, RegQueryValueEx will return
|
||||
// ERROR_SUCCESS. However, in order to satisfy UMDF-KMDF DDI parity as well
|
||||
// as internal mode-agnostic code, we must overwrite RegQueryValueEx's
|
||||
// return value of ERROR_SUCCESS (STATUS_SUCCESS) with STATUS_BUFFER_OVERFLOW.
|
||||
//
|
||||
// Other return values are overwritten because WinErrorToNtStatus does not map
|
||||
// all Win32 error codes that RegQueryValueEx returns to the same NTSTATUS
|
||||
// values that ZwQueryValueKey would return in the KM implementation of
|
||||
// FxRegKey::_QueryValue.
|
||||
//
|
||||
if (err == ERROR_SUCCESS) {
|
||||
if (Value != NULL) {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
status = STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
}
|
||||
else if (err == ERROR_MORE_DATA) {
|
||||
status = STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
else if (err == ERROR_FILE_NOT_FOUND) {
|
||||
status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
else {
|
||||
status = WinErrorToNtStatus(err);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
FxRegKey::_QueryULong(
|
||||
__in HANDLE Key,
|
||||
__in PCUNICODE_STRING ValueName,
|
||||
__out PULONG Value
|
||||
)
|
||||
{
|
||||
DWORD err;
|
||||
NTSTATUS status;
|
||||
ULONG length, type;
|
||||
|
||||
ASSERT(Key != HKEY_PERFORMANCE_DATA);
|
||||
|
||||
type = REG_DWORD;
|
||||
length = sizeof(ULONG);
|
||||
|
||||
err = RegQueryValueEx((HKEY)Key,
|
||||
ValueName->Buffer,
|
||||
NULL,
|
||||
&type,
|
||||
(LPBYTE)Value,
|
||||
&length);
|
||||
|
||||
if ((err == ERROR_SUCCESS || err == ERROR_MORE_DATA) &&
|
||||
type != REG_DWORD) {
|
||||
|
||||
ASSERT(FALSE);
|
||||
|
||||
status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||
}
|
||||
else {
|
||||
if (ERROR_SUCCESS == err) {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
status = WinErrorToNtStatus(err);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
NTSTATUS
|
||||
FxRegKey::_QueryQuadWord(
|
||||
__in HANDLE Key,
|
||||
__in PCUNICODE_STRING ValueName,
|
||||
__out PLARGE_INTEGER Value
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Key);
|
||||
UNREFERENCED_PARAMETER(ValueName);
|
||||
UNREFERENCED_PARAMETER(Value);
|
||||
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
103
sdk/lib/drivers/wdf/shared/support/um/fxrequestbufferum.cpp
Normal file
103
sdk/lib/drivers/wdf/shared/support/um/fxrequestbufferum.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
FxRequestBufferUm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a memory union object
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
User mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "FxRequestBufferUm.tmh"
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxRequestBuffer::GetOrAllocateMdl(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__deref_out_opt PMDL* Mdl,
|
||||
__inout PMDL* MdlToFree,
|
||||
__inout PBOOLEAN UnlockWhenFreed,
|
||||
__in LOCK_OPERATION Operation,
|
||||
__in BOOLEAN ReuseMdl,
|
||||
__inout_opt size_t* SizeOfMdl
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function attempts to reuse the passed-in MDL (if any) or allocates
|
||||
a new MDL if reuse flag isn't passed-in or if the existing MDL isn't
|
||||
big enough.
|
||||
|
||||
Arguments:
|
||||
|
||||
Return Value:
|
||||
FxDriverGlobals - Driver globals
|
||||
|
||||
Mdl - on return it contains the MDL allocated/reused
|
||||
|
||||
MdlToFree - pointer to any MDL
|
||||
* to be reused, if the size is <= current size, or
|
||||
* freed and set to newly allocated MDL
|
||||
|
||||
UnlockWhenFreed - whether to unlock pages when freeing MDL
|
||||
(if FALSE, MDL may represent just MDL buffer but the pages
|
||||
might have already been unlocked)
|
||||
|
||||
Operation - Operation to pass to MmLockPages
|
||||
|
||||
ReuseMdl - whether to reuse *MdlToFree
|
||||
Please note that this can be FALSE even when MDL is supplied
|
||||
|
||||
SizeOfMdl - on input contains size of *MdlToFree,
|
||||
on return contains size of *Mdl
|
||||
|
||||
Remarks:
|
||||
|
||||
*MdlToFree is modified only when this function frees the passed in MDL
|
||||
Otherwise it leaves it untouched. Caller is responsible for storing
|
||||
properly initialized value and/or freeing what's stored in the value.
|
||||
|
||||
--*/
|
||||
{
|
||||
UNREFERENCED_PARAMETER(FxDriverGlobals);
|
||||
UNREFERENCED_PARAMETER(Mdl);
|
||||
UNREFERENCED_PARAMETER(MdlToFree);
|
||||
UNREFERENCED_PARAMETER(UnlockWhenFreed);
|
||||
UNREFERENCED_PARAMETER(Operation);
|
||||
UNREFERENCED_PARAMETER(ReuseMdl);
|
||||
UNREFERENCED_PARAMETER(SizeOfMdl);
|
||||
|
||||
UfxVerifierTrapNotImpl();
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxRequestBuffer::SetMemory(
|
||||
__in IFxMemory* Memory,
|
||||
__in PWDFMEMORY_OFFSET Offsets
|
||||
)
|
||||
{
|
||||
DataType = FxRequestBufferMemory;
|
||||
u.Memory.Memory = Memory;
|
||||
u.Memory.Offsets = Offsets;
|
||||
}
|
||||
|
788
sdk/lib/drivers/wdf/shared/support/um/fxresourcecollectionum.cpp
Normal file
788
sdk/lib/drivers/wdf/shared/support/um/fxresourcecollectionum.cpp
Normal file
|
@ -0,0 +1,788 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxResourceCollection.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a base object for derived collection classes and
|
||||
the derived collection classes.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
User mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
#include <intsafe.h>
|
||||
|
||||
#if defined(EVENT_TRACING)
|
||||
// Tracing support
|
||||
extern "C" {
|
||||
#include "FxResourceCollectionUm.tmh"
|
||||
}
|
||||
#endif
|
||||
|
||||
FxCmResList::~FxCmResList()
|
||||
{
|
||||
DeleteRegisterResourceTable();
|
||||
DeletePortResourceTable();
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxCmResList::BuildRegisterResourceTable(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ULONG count;
|
||||
ULONG i, index;
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
|
||||
ULONG numRegisterDesc;
|
||||
BOOLEAN locked = FALSE;
|
||||
NTSTATUS status;
|
||||
|
||||
count = GetCount();
|
||||
numRegisterDesc = 0;
|
||||
|
||||
//
|
||||
// count number of register descriptors
|
||||
//
|
||||
for (i = 0; i < count; i++) {
|
||||
desc = GetDescriptor(i);
|
||||
if (desc == NULL) {
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Resource Descriptor not found %!STATUS!", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (desc->Type == CmResourceTypeMemory ||
|
||||
desc->Type == CmResourceTypeMemoryLarge) {
|
||||
numRegisterDesc++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numRegisterDesc == 0) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// allocate table
|
||||
//
|
||||
LockResourceTable();
|
||||
locked = TRUE;
|
||||
|
||||
status = FxRegisterResourceInfo::_CreateAndInit(
|
||||
GetDriverGlobals(),
|
||||
numRegisterDesc,
|
||||
&m_RegisterResourceTable
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Failed to allocate memory for resource table"
|
||||
" %!STATUS!", status);
|
||||
goto exit;
|
||||
}
|
||||
m_RegisterResourceTableSizeCe = numRegisterDesc;
|
||||
|
||||
//
|
||||
// Populate table
|
||||
//
|
||||
index = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
desc = GetDescriptor(i);
|
||||
if (desc == NULL) {
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Resource Descriptor not found %!STATUS!", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (desc->Type == CmResourceTypeMemory ||
|
||||
desc->Type == CmResourceTypeMemoryLarge) {
|
||||
SIZE_T len;
|
||||
PHYSICAL_ADDRESS pa;
|
||||
|
||||
//
|
||||
// This will populate Length and StartPa
|
||||
//
|
||||
len = GetResourceLength(desc, &pa);
|
||||
if (len) {
|
||||
m_RegisterResourceTable[index].SetPhysicalAddress(pa, len);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (m_RegisterResourceTable != NULL) {
|
||||
delete [] m_RegisterResourceTable;
|
||||
m_RegisterResourceTable = NULL;
|
||||
m_RegisterResourceTableSizeCe = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (locked) {
|
||||
UnlockResourceTable();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FxCmResList::BuildPortResourceTable(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ULONG count;
|
||||
ULONG i, index;
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
|
||||
ULONG numPortDesc;
|
||||
BOOLEAN locked = FALSE;
|
||||
NTSTATUS status;
|
||||
|
||||
count = GetCount();
|
||||
numPortDesc = 0;
|
||||
|
||||
//
|
||||
// count number of register descriptors
|
||||
//
|
||||
for (i = 0; i < count; i++) {
|
||||
desc = GetDescriptor(i);
|
||||
if (desc == NULL) {
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Resource Descriptor not found %!STATUS!", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (desc->Type == CmResourceTypePort) {
|
||||
numPortDesc++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numPortDesc == 0) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// allocate table
|
||||
//
|
||||
LockResourceTable();
|
||||
locked = TRUE;
|
||||
|
||||
status = FxPortResourceInfo::_CreateAndInit(
|
||||
GetDriverGlobals(),
|
||||
numPortDesc,
|
||||
&m_PortResourceTable
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Failed to allocate memory for resource table"
|
||||
" %!STATUS!", status);
|
||||
goto exit;
|
||||
}
|
||||
m_PortResourceTableSizeCe = numPortDesc;
|
||||
|
||||
//
|
||||
// Populate table
|
||||
//
|
||||
index = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
desc = GetDescriptor(i);
|
||||
if (desc == NULL) {
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Resource Descriptor not found %!STATUS!", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (desc->Type == CmResourceTypePort) {
|
||||
SIZE_T len;
|
||||
PHYSICAL_ADDRESS pa;
|
||||
|
||||
//
|
||||
// This will populate Length, StartPa and EndPa
|
||||
//
|
||||
len = GetResourceLength(desc, &pa);
|
||||
if (len) {
|
||||
m_PortResourceTable[index].SetPhysicalAddress(pa, len);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (m_PortResourceTable != NULL) {
|
||||
delete [] m_PortResourceTable;
|
||||
m_PortResourceTable = NULL;
|
||||
m_PortResourceTableSizeCe = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (locked) {
|
||||
UnlockResourceTable();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FxCmResList::UpdateRegisterResourceEntryLocked(
|
||||
__in FxRegisterResourceInfo* Entry,
|
||||
__in PVOID SystemMappedAddress,
|
||||
__in SIZE_T NumberOfBytes,
|
||||
__in PVOID UsermodeMappedAddress
|
||||
)
|
||||
{
|
||||
Entry->SetMappedAddress(SystemMappedAddress, NumberOfBytes, UsermodeMappedAddress);
|
||||
}
|
||||
|
||||
VOID
|
||||
FxCmResList::ClearRegisterResourceEntryLocked(
|
||||
__in FxRegisterResourceInfo* Entry
|
||||
)
|
||||
{
|
||||
Entry->ClearMappedAddress();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FxCmResList::ValidateRegisterPhysicalAddressRange (
|
||||
__in PHYSICAL_ADDRESS PhysicalAddress,
|
||||
__in SIZE_T Size,
|
||||
__out FxRegisterResourceInfo** TableEntry
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine checks whether the physical address range is part of the resources
|
||||
assigned to the device by pnp manager. It also returns the table entry
|
||||
corresponding to the physical address range from register resource table.
|
||||
|
||||
Arguments:
|
||||
|
||||
PhysicalAddress - Supplies physical address to validate
|
||||
|
||||
Size - Supplies size of address range in bytes.
|
||||
|
||||
TableEntry - Supplies a pointer to store the table entry that corresponds to
|
||||
this physical address.
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
S_OK if physical address is one assigned by pnp manager to this device.
|
||||
E_INAVLIDARG otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
ULONG i;
|
||||
HRESULT hr;
|
||||
ULONGLONG driverStartPa, driverEndPa, systemStartPa, systemEndPa;
|
||||
ULONGLONG tmp;
|
||||
FxRegisterResourceInfo* entry = NULL;
|
||||
|
||||
*TableEntry = NULL;
|
||||
|
||||
//
|
||||
// Physical address is of LONGLONG type (signed) we need to cast it to
|
||||
// ULONGLONG for comparision because in a LONGLONG comprison, the
|
||||
// result is different when highest bit is set vs when it is not set.
|
||||
//
|
||||
driverStartPa = PhysicalAddress.QuadPart;
|
||||
|
||||
//
|
||||
// driverEndPa = driverStartPa + Size - 1;
|
||||
//
|
||||
hr = ULongLongAdd(driverStartPa, Size, &tmp);
|
||||
FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred"
|
||||
"when computing register address range", SUCCEEDED(hr)),
|
||||
GetDriverGlobals()->Public.DriverName);
|
||||
|
||||
driverEndPa = tmp - 1;
|
||||
|
||||
//
|
||||
// We allow one physical address range mapping only. The base address and
|
||||
// length can be flexible within the assigned range.
|
||||
//
|
||||
for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
|
||||
entry = &m_RegisterResourceTable[i];
|
||||
|
||||
//
|
||||
// No need to do int overflow safe additon here since start address and
|
||||
// length are assigned by pnp manager. Note that we don't store endPa in
|
||||
// resource table the way we do for SystemVa is because endPa is not
|
||||
// needed in hot path so can be computed using length.
|
||||
//
|
||||
systemStartPa = entry->m_StartPa.QuadPart;
|
||||
systemEndPa = systemStartPa + entry->m_Length - 1;
|
||||
|
||||
if (driverStartPa >= systemStartPa &&
|
||||
driverEndPa <= systemEndPa) {
|
||||
|
||||
FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Attempt to do multiple "
|
||||
"mapping of same resource, or multiple mapping in same resource"
|
||||
" range",
|
||||
(entry->m_StartSystemVa == NULL)), GetDriverGlobals()->Public.DriverName);
|
||||
FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NULL(entry->m_EndSystemVa),
|
||||
GetDriverGlobals()->Public.DriverName);
|
||||
FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NULL(entry->m_StartUsermodeVa),
|
||||
GetDriverGlobals()->Public.DriverName);
|
||||
FX_VERIFY_WITH_NAME(INTERNAL, CHECK("Mapped length not zero",
|
||||
(entry->m_MappedLength == 0)), GetDriverGlobals()->Public.DriverName);
|
||||
|
||||
*TableEntry = entry;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FxCmResList::ValidateAndClearMapping(
|
||||
__in PVOID Address,
|
||||
__in SIZE_T Length
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine checks whether the mapped system base address and size is part
|
||||
of the resources assigned to the device by pnp manager. If so it clears the
|
||||
system and usermode address mapping from the table.
|
||||
|
||||
Arguments:
|
||||
|
||||
Address - Supplies system base address to validate
|
||||
|
||||
Size - Supplies size of address range in bytes.
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
S_OK if system address is one mapped to a register resource.
|
||||
E_INAVLIDARG otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
ULONG i;
|
||||
FxRegisterResourceInfo* entry = NULL;
|
||||
|
||||
LockResourceTable();
|
||||
|
||||
for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
|
||||
entry = &m_RegisterResourceTable[i];
|
||||
|
||||
if (NULL != entry->m_StartSystemVa &&
|
||||
Address == entry->m_StartSystemVa &&
|
||||
Length == entry->m_MappedLength) {
|
||||
//
|
||||
// there is a valid mapping. clear it.
|
||||
//
|
||||
FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(entry->m_EndSystemVa),
|
||||
GetDriverGlobals()->Public.DriverName);
|
||||
|
||||
ClearRegisterResourceEntryLocked(entry);
|
||||
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnlockResourceTable();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FxCmResList::ValidateRegisterSystemBaseAddress (
|
||||
__in PVOID Address,
|
||||
__out PVOID* UsermodeBaseAddress
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine checks whether the mapped system base address and size is part
|
||||
of the resources assigned to the device by pnp manager. If so, it returns
|
||||
corresponding user-mode mapped base address. It is applicable
|
||||
only when registers are mapped to user-mode.
|
||||
|
||||
Arguments:
|
||||
|
||||
Address - Supplies system base address to validate
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
S_OK if system address is one mapped to a register resource.
|
||||
E_INAVLIDARG otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
ULONG i;
|
||||
FxRegisterResourceInfo* entry = NULL;
|
||||
|
||||
LockResourceTable();
|
||||
for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
|
||||
entry = &m_RegisterResourceTable[i];
|
||||
|
||||
if (Address == entry->m_StartSystemVa) {
|
||||
|
||||
FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(entry->m_StartUsermodeVa),
|
||||
GetDriverGlobals()->Public.DriverName);
|
||||
|
||||
*UsermodeBaseAddress = entry->m_StartUsermodeVa;
|
||||
|
||||
UnlockResourceTable();
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
UnlockResourceTable();
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FxCmResList::ValidateRegisterSystemAddressRange (
|
||||
__in PVOID SystemAddress,
|
||||
__in SIZE_T Length,
|
||||
__out_opt PVOID* UsermodeAddress
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine checks whether given system mapped address and length is within
|
||||
one of the assigned resource ranges. Optionally, tt computes the usermode
|
||||
address corresponding to the system address.
|
||||
|
||||
Arguments:
|
||||
|
||||
Address - Supplies register address to validate
|
||||
|
||||
Size - Supplies size of address range in bytes.
|
||||
|
||||
UsermodeAddress - returns usermode address corresponding to system address
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
S_OK if system address range is valid.
|
||||
E_INAVLIDARG otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
FxRegisterResourceInfo* entry = NULL;
|
||||
SIZE_T offset = 0;
|
||||
ULONG i;
|
||||
PVOID start = NULL;
|
||||
PVOID end = NULL;
|
||||
ULONG_PTR tmp;
|
||||
|
||||
//
|
||||
// compute system address range to look for
|
||||
//
|
||||
start = SystemAddress;
|
||||
|
||||
//
|
||||
// Use interger overflow safe functions
|
||||
// end = ((PUCHAR)SystemAddress) + Length - 1;
|
||||
//
|
||||
hr = ULongPtrAdd((ULONG_PTR) start, Length, &tmp);
|
||||
FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred"
|
||||
"when computing register address range", SUCCEEDED(hr)),
|
||||
GetDriverGlobals()->Public.DriverName);
|
||||
|
||||
end = (PVOID)(tmp - 1);
|
||||
|
||||
//
|
||||
// check if range is in the register resource table
|
||||
//
|
||||
hr = E_INVALIDARG;
|
||||
for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
|
||||
entry = &m_RegisterResourceTable[i];
|
||||
|
||||
if (start >= entry->m_StartSystemVa &&
|
||||
end <= entry->m_EndSystemVa) {
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// compute the corresponding usermode address
|
||||
//
|
||||
if (SUCCEEDED(hr) && UsermodeAddress != NULL) {
|
||||
offset = ((PUCHAR)SystemAddress) - ((PUCHAR)entry->m_StartSystemVa);
|
||||
*UsermodeAddress = ((PUCHAR)entry->m_StartUsermodeVa) + offset;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
SIZE_T
|
||||
FxCmResList::GetResourceLength(
|
||||
__in PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||||
__out_opt PHYSICAL_ADDRESS* Start
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine decodes the length from a CmPartialResourceDescriptor
|
||||
describing a memory resource.
|
||||
|
||||
Arguments:
|
||||
|
||||
Descriptor - Supplies resource descriptor from which to decode length
|
||||
|
||||
Start - Supplies optional buffer into which start address will be stored.
|
||||
|
||||
Return Value:
|
||||
|
||||
Decoded Length
|
||||
|
||||
--*/
|
||||
{
|
||||
ULONGLONG length;
|
||||
|
||||
length = 0;
|
||||
|
||||
ASSERT((Descriptor->Type == CmResourceTypeMemory) ||
|
||||
(Descriptor->Type == CmResourceTypeMemoryLarge) ||
|
||||
(Descriptor->Type == CmResourceTypePort));
|
||||
|
||||
//
|
||||
// If it is not large memory resource than length is in u.Memory.Length.
|
||||
// For large memory resource, the length is given by different fields in
|
||||
// CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
|
||||
//
|
||||
if ((Descriptor->Type == CmResourceTypeMemory) ||
|
||||
(Descriptor->Type == CmResourceTypePort)) {
|
||||
length = Descriptor->u.Memory.Length;
|
||||
|
||||
} else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_40) {
|
||||
length = (((ULONGLONG)Descriptor->u.Memory40.Length40) << 8);
|
||||
|
||||
} else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_48) {
|
||||
length = (((ULONGLONG)Descriptor->u.Memory48.Length48) << 16);
|
||||
|
||||
} else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_64) {
|
||||
length = (((ULONGLONG)Descriptor->u.Memory64.Length64) << 32);
|
||||
|
||||
} else {
|
||||
//
|
||||
// It should not be possible to get here.
|
||||
//
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
if (Start != NULL) {
|
||||
*Start = Descriptor->u.Generic.Start;
|
||||
}
|
||||
|
||||
//
|
||||
// large memory descriptor is only supported on 64-bit so the casting
|
||||
// below is ok.
|
||||
//
|
||||
return (SIZE_T) length;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FxCmResList::MapIoSpaceWorker(
|
||||
__in PHYSICAL_ADDRESS PhysicalAddress,
|
||||
__in SIZE_T NumberOfBytes,
|
||||
__in MEMORY_CACHING_TYPE CacheType,
|
||||
__deref_out VOID** PseudoBaseAddress
|
||||
)
|
||||
{
|
||||
IWudfDeviceStack *deviceStack;
|
||||
PVOID systemAddress;
|
||||
PVOID usermodeAddress;
|
||||
HRESULT hr;
|
||||
FxRegisterResourceInfo* resEntry;
|
||||
|
||||
//
|
||||
// check if this physical resource is among the assigned resources.
|
||||
// If it is, retrieve the table entry corresponding to to register res.
|
||||
//
|
||||
LockResourceTable();
|
||||
|
||||
hr = ValidateRegisterPhysicalAddressRange(PhysicalAddress,
|
||||
NumberOfBytes,
|
||||
&resEntry);
|
||||
|
||||
FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO),
|
||||
CHECK("Invalid physical address or number of bytes provided",
|
||||
(SUCCEEDED(hr))), GetDriverGlobals()->Public.DriverName);
|
||||
|
||||
*PseudoBaseAddress = NULL;
|
||||
|
||||
//
|
||||
// Call host
|
||||
//
|
||||
deviceStack = GetDevice()->GetDeviceStack();
|
||||
systemAddress = NULL;
|
||||
usermodeAddress = NULL;
|
||||
|
||||
if(GetDevice()->AreRegistersMappedToUsermode()) {
|
||||
hr = deviceStack->MapIoSpace(PhysicalAddress,
|
||||
NumberOfBytes,
|
||||
CacheType,
|
||||
&systemAddress,
|
||||
&usermodeAddress);
|
||||
}
|
||||
else {
|
||||
hr = deviceStack->MapIoSpace(PhysicalAddress,
|
||||
NumberOfBytes,
|
||||
CacheType,
|
||||
&systemAddress,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
//
|
||||
// update the mapped resource list entry and add it to list
|
||||
//
|
||||
UpdateRegisterResourceEntryLocked(resEntry,
|
||||
systemAddress,
|
||||
NumberOfBytes,
|
||||
usermodeAddress);
|
||||
|
||||
//
|
||||
// Convert system address to pseudo (opaque) base address
|
||||
//
|
||||
*PseudoBaseAddress = GetDevice()->GetPseudoAddressFromSystemAddress(
|
||||
systemAddress
|
||||
);
|
||||
}
|
||||
|
||||
UnlockResourceTable();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
FxCmResList::ValidateResourceUnmap(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ULONG i;
|
||||
FxRegisterResourceInfo* entry = NULL;
|
||||
|
||||
//
|
||||
// make sure driver has unmapped its resources. No need to
|
||||
// acquire the resource validation table lock as this is called in
|
||||
// ReleaseHardware pnp callback and cannot race with another framework
|
||||
// pnp callback that updates this table (PrepareHardware) so no invalid
|
||||
// access. If a driver thread unmaps after ReleaseHardware return then also
|
||||
// it will be a valid access of table entry.
|
||||
//
|
||||
|
||||
for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
|
||||
entry = &m_RegisterResourceTable[i];
|
||||
|
||||
FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Driver did not unmap its "
|
||||
"register resources", (entry->m_StartSystemVa == NULL)), GetDriverGlobals()->Public.DriverName);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FxCmResList::ValidatePortAddressRange(
|
||||
__in PVOID Address,
|
||||
__in SIZE_T Length
|
||||
)
|
||||
{
|
||||
ULONG i;
|
||||
HRESULT hr;
|
||||
ULONGLONG driverStartPa, driverEndPa, systemStartPa, systemEndPa;
|
||||
ULONGLONG tmp;
|
||||
FxPortResourceInfo* entry = NULL;
|
||||
|
||||
driverStartPa = (ULONGLONG)Address;
|
||||
|
||||
//
|
||||
// driverEndPa = driverStartPa + Length - 1;
|
||||
//
|
||||
hr = ULongLongAdd(driverStartPa, Length, &tmp);
|
||||
FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred"
|
||||
"when computing port address range", SUCCEEDED(hr)),
|
||||
GetDriverGlobals()->Public.DriverName);
|
||||
|
||||
driverEndPa = tmp - 1;
|
||||
|
||||
for (i = 0; i < m_PortResourceTableSizeCe; i++) {
|
||||
entry = &m_PortResourceTable[i];
|
||||
|
||||
systemStartPa = entry->m_StartPa.QuadPart;
|
||||
systemEndPa = entry->m_EndPa.QuadPart;
|
||||
|
||||
if (driverStartPa >= systemStartPa &&
|
||||
driverEndPa <= systemEndPa) {
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxCmResList::CheckForConnectionResources(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG i;
|
||||
ULONG count;
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
count = GetCount();
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
pDescriptor = GetDescriptor(i);
|
||||
if (pDescriptor == NULL) {
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
||||
"Resource Descriptor not found %!STATUS!", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (pDescriptor->Type == CmResourceTypeConnection) {
|
||||
m_HasConnectionResources = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
|
44
sdk/lib/drivers/wdf/shared/support/um/fxsupportpchum.hpp
Normal file
44
sdk/lib/drivers/wdf/shared/support/um/fxsupportpchum.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
fxsupportpchum.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains header definitions and include files needed by all
|
||||
modules in fx\support
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
User mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __FX_SUPPORT_PCH_UM_HPP__
|
||||
#define __FX_SUPPORT_PCH_UM_HPP__
|
||||
|
||||
extern "C" {
|
||||
#include "mx.h"
|
||||
}
|
||||
|
||||
#include "fxmin.hpp"
|
||||
|
||||
#include "FxPagedObject.hpp"
|
||||
#include "FxRegKey.hpp"
|
||||
#include "FxCollection.hpp"
|
||||
#include "FxString.hpp"
|
||||
#include "StringUtil.hpp"
|
||||
|
||||
#include "FxDeviceText.hpp"
|
||||
|
||||
#include <WdfResource.h>
|
||||
#include <FxResource.hpp>
|
||||
|
||||
|
||||
#endif // __FX_SUPPORT_PCH_UM_HPP__
|
426
sdk/lib/drivers/wdf/shared/support/um/fxtelemetryum.cpp
Normal file
426
sdk/lib/drivers/wdf/shared/support/um/fxtelemetryum.cpp
Normal file
|
@ -0,0 +1,426 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
FxTelemetryUm.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements a telemetry methods.
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
User mode only
|
||||
|
||||
Revision History:
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
#include "fxsupportpch.hpp"
|
||||
#include "DriverFrameworks-UserMode-UmEvents.h"
|
||||
#include "FxldrUm.h"
|
||||
#include <winmeta.h>
|
||||
#include <TraceLoggingProvider.h>
|
||||
#include <telemetry\MicrosoftTelemetry.h>
|
||||
#include <rpc.h>
|
||||
#include <rpcndr.h>
|
||||
|
||||
extern "C" {
|
||||
#if defined(EVENT_TRACING)
|
||||
#include "FxTelemetryUm.tmh"
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 8ad60765-a021-4494-8594-9346970cf50f */
|
||||
TRACELOGGING_DEFINE_PROVIDER(g_TelemetryProvider,
|
||||
UMDF_FX_TRACE_LOGGING_PROVIDER_NAME,
|
||||
(0x8ad60765, 0xa021, 0x4494, 0x85, 0x94, 0x93, 0x46, 0x97, 0x0c, 0xf5, 0x0f),
|
||||
TraceLoggingOptionMicrosoftTelemetry());
|
||||
|
||||
VOID
|
||||
AllocAndInitializeTelemetryContext(
|
||||
_In_ PFX_TELEMETRY_CONTEXT* TelemetryContext
|
||||
)
|
||||
{
|
||||
PFX_TELEMETRY_CONTEXT context = NULL;
|
||||
RPC_STATUS status;
|
||||
|
||||
context = (PFX_TELEMETRY_CONTEXT)MxMemory::MxAllocatePoolWithTag(NonPagedPool,
|
||||
sizeof(FX_TELEMETRY_CONTEXT),
|
||||
FX_TAG);
|
||||
if (NULL == context) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = UuidCreate(&(context->DriverSessionGUID));
|
||||
if ((status != RPC_S_OK) && (status != RPC_S_UUID_LOCAL_ONLY)) {
|
||||
MxMemory::MxFreePool(context);
|
||||
context = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
context->DoOnceFlagsBitmap = 0;
|
||||
exit:
|
||||
*TelemetryContext = context;
|
||||
}
|
||||
|
||||
VOID
|
||||
RegisterTelemetryProvider(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EventRegisterMicrosoft_Windows_DriverFrameworks_UserMode();
|
||||
|
||||
TraceLoggingRegister(g_TelemetryProvider);
|
||||
}
|
||||
|
||||
VOID
|
||||
UnregisterTelemetryProvider(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EventUnregisterMicrosoft_Windows_DriverFrameworks_UserMode();
|
||||
|
||||
TraceLoggingUnregister(g_TelemetryProvider);
|
||||
}
|
||||
|
||||
VOID
|
||||
LogDeviceStartTelemetryEvent(
|
||||
_In_ PFX_DRIVER_GLOBALS Globals,
|
||||
_In_opt_ FxDevice* Fdo
|
||||
)
|
||||
{
|
||||
// If provider is not enabled we're done.
|
||||
if (FALSE == FX_TELEMETRY_ENABLED(g_TelemetryProvider, Globals)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// If we already fired an event during PnP start we are done. This avoids
|
||||
// repeatedly firing events during PnP rebalance.
|
||||
//
|
||||
if (InterlockedBitTestAndSet(
|
||||
&Globals->TelemetryContext->DoOnceFlagsBitmap,
|
||||
DeviceStartEventBit) == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// log the DriverInfo stream.
|
||||
//
|
||||
LogDriverInfoStream(Globals, Fdo);
|
||||
}
|
||||
|
||||
VOID
|
||||
LogDriverInfoStream(
|
||||
_In_ PFX_DRIVER_GLOBALS DriverGlobals,
|
||||
_In_ FxDevice* Fdo
|
||||
)
|
||||
{
|
||||
LONG error = ERROR_SUCCESS;
|
||||
PWCHAR str = NULL;
|
||||
UFxTelemetryDriverInfo driverInfo = {0};
|
||||
LPCWSTR hardwareIds = NULL;
|
||||
LPCWSTR setupClass = NULL;
|
||||
LPCWSTR busEnum = NULL;
|
||||
LPCWSTR manufacturer = NULL;
|
||||
UMDF_DRIVER_REGSITRY_INFO devRegInfo = {0};
|
||||
PCWSTR groupId = NULL;
|
||||
IWudfDeviceStack* devStack = NULL;
|
||||
|
||||
if (Fdo == NULL) {
|
||||
//
|
||||
// Telemetry events are logged during DriverEntry as well to capture non-pnp
|
||||
// and class extension (which are non-pnp drivers) driver info. Although
|
||||
// current UMDF datapoint doesn't have a separate flag for non-pnp driver,
|
||||
// we still want to log the driver name and its properies if available.
|
||||
//
|
||||
devStack = DriverGlobals->Driver->GetDriverObject()->WudfDevStack;
|
||||
if (devStack != NULL) {
|
||||
devStack->GetPdoProperties(&hardwareIds,
|
||||
&setupClass,
|
||||
&busEnum,
|
||||
&manufacturer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
devStack = Fdo->GetDeviceStack();
|
||||
devStack->GetPdoProperties(&hardwareIds,
|
||||
&setupClass,
|
||||
&busEnum,
|
||||
&manufacturer);
|
||||
|
||||
Fdo->RetrieveDeviceInfoRegistrySettings(&groupId, &devRegInfo);
|
||||
}
|
||||
|
||||
//
|
||||
// Log Driver info
|
||||
//
|
||||
if (Fdo != NULL) {
|
||||
GetDriverInfo(Fdo, &devRegInfo, &driverInfo);
|
||||
}
|
||||
|
||||
UMDF_CENSUS_EVT_WRITE_DEVICE_START(g_TelemetryProvider,
|
||||
DriverGlobals,
|
||||
driverInfo,
|
||||
setupClass,
|
||||
busEnum,
|
||||
hardwareIds,
|
||||
manufacturer);
|
||||
|
||||
if (groupId != NULL) {
|
||||
delete [] groupId;
|
||||
groupId = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
GetDriverInfo(
|
||||
_In_ FxDevice* Fdo,
|
||||
_In_ PUMDF_DRIVER_REGSITRY_INFO RegInfo,
|
||||
_Out_ UFxTelemetryDriverInfo* DriverInfo
|
||||
)
|
||||
{
|
||||
FxPkgPnp* pnpPkg;
|
||||
USHORT devInfo = 0;
|
||||
WDF_DEVICE_IO_TYPE readWritePreference;
|
||||
WDF_DEVICE_IO_TYPE ioControlPreference;
|
||||
UMDF_DRIVER_REGSITRY_INFO devRegInfo = {0};
|
||||
PWSTR groupId = NULL;
|
||||
|
||||
pnpPkg = (FxPkgPnp*)Fdo->GetFdoPkg();
|
||||
devInfo = Fdo->GetDeviceTelemetryInfoFlags();
|
||||
Fdo->GetDeviceStackIoType(&readWritePreference, &ioControlPreference);
|
||||
|
||||
DriverInfo->bitmap.IsFilter = Fdo->IsFilter();
|
||||
DriverInfo->bitmap.IsPowerPolicyOwner = pnpPkg->IsPowerPolicyOwner();
|
||||
DriverInfo->bitmap.IsS0IdleWakeFromS0Enabled = pnpPkg->IsS0IdleWakeFromS0Enabled();
|
||||
DriverInfo->bitmap.IsS0IdleUsbSSEnabled = pnpPkg->IsS0IdleUsbSSEnabled();
|
||||
DriverInfo->bitmap.IsS0IdleSystemManaged = pnpPkg->IsS0IdleSystemManaged();
|
||||
DriverInfo->bitmap.IsSxWakeEnabled = pnpPkg->IsSxWakeEnabled();
|
||||
DriverInfo->bitmap.IsUsingLevelTriggeredLineInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoLineBasedLevelTriggeredInterrupt);
|
||||
DriverInfo->bitmap.IsUsingEdgeTriggeredLineInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoLineBasedEdgeTriggeredInterrupt);
|
||||
DriverInfo->bitmap.IsUsingMsiXOrSingleMsi22Interrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoMsiXOrSingleMsi22Interrupt);
|
||||
DriverInfo->bitmap.IsUsingMsi22MultiMessageInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoMsi22MultiMessageInterrupt);
|
||||
DriverInfo->bitmap.IsUsingMultipleInterrupt = pnpPkg->HasMultipleInterrupts();
|
||||
DriverInfo->bitmap.IsDirectHardwareAccessAllowed = Fdo->IsDirectHardwareAccessAllowed();
|
||||
DriverInfo->bitmap.IsUsingUserModemappingAccessMode = Fdo->AreRegistersMappedToUsermode();
|
||||
DriverInfo->bitmap.IsKernelModeClientAllowed = RegInfo->IsKernelModeClientAllowed;
|
||||
DriverInfo->bitmap.IsNullFileObjectAllowed = RegInfo->IsNullFileObjectAllowed;
|
||||
DriverInfo->bitmap.IsPoolingDisabled = RegInfo->IsHostProcessSharingDisabled;
|
||||
DriverInfo->bitmap.IsMethodNeitherActionCopy = RegInfo->IsMethodNeitherActionCopy;
|
||||
DriverInfo->bitmap.IsUsingDirectIoForReadWrite = (readWritePreference == WdfDeviceIoDirect);
|
||||
DriverInfo->bitmap.IsUsingDirectIoForIoctl = (ioControlPreference == WdfDeviceIoDirect);
|
||||
DriverInfo->bitmap.IsUsingDriverWppRecorder = Fdo->GetDriver()->IsDriverObjectFlagSet(DriverObjectUmFlagsLoggingEnabled);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
GetImageName(
|
||||
_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
_Out_ PUNICODE_STRING ImageName
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Retrieve the ImageName value from the named Service registry key.
|
||||
|
||||
Caller is responsible for freeing the buffer allocated in ImageName::Buffer.
|
||||
|
||||
Arguments:
|
||||
DriverGlobals - pointer to FX_DRIVER_GLOBALS
|
||||
|
||||
ImageeName - Pointer to a UNICODE_STRING which will receive the image name
|
||||
upon a return value of NT_SUCCESS()
|
||||
|
||||
Return Value:
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
NTSTATUS status;
|
||||
FxAutoRegKey hKey;
|
||||
DECLARE_CONST_UNICODE_STRING(valueName, L"ImagePath");
|
||||
UNICODE_STRING imagePath = {0};
|
||||
UNICODE_STRING imageName = {0};
|
||||
PKEY_VALUE_PARTIAL_INFORMATION value = NULL;
|
||||
USHORT size;
|
||||
ULONG length, type;
|
||||
PVOID dataBuffer;
|
||||
|
||||
type = REG_SZ;
|
||||
length = 0;
|
||||
|
||||
ASSERT(ImageName != NULL);
|
||||
RtlZeroMemory(ImageName, sizeof(UNICODE_STRING));
|
||||
|
||||
//
|
||||
// Open driver's Service base key
|
||||
//
|
||||
status = FxRegKey::_OpenKey(NULL,
|
||||
FxDriverGlobals->Driver->GetRegistryPathUnicodeString(),
|
||||
&hKey.m_Key,
|
||||
KEY_READ);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Unable to open driver's service key, %!STATUS!", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Find out how big a buffer we need to allocate if the value is present
|
||||
//
|
||||
status = FxRegKey::_QueryValue(FxDriverGlobals,
|
||||
hKey.m_Key,
|
||||
&valueName,
|
||||
length,
|
||||
NULL,
|
||||
&length,
|
||||
&type);
|
||||
|
||||
//
|
||||
// We expect the list to be bigger then a standard partial, so if it is
|
||||
// not, just bail now.
|
||||
//
|
||||
if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) {
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
//
|
||||
// Pool can be paged b/c we are running at PASSIVE_LEVEL and we are going
|
||||
// to free it at the end of this function.
|
||||
//
|
||||
dataBuffer = FxPoolAllocate(FxDriverGlobals, PagedPool, length);
|
||||
if (dataBuffer == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Failed to allocate memory for image path string, %!STATUS!",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Requery now that we have a big enough buffer
|
||||
//
|
||||
status = FxRegKey::_QueryValue(FxDriverGlobals,
|
||||
hKey.m_Key,
|
||||
&valueName,
|
||||
length,
|
||||
dataBuffer,
|
||||
&length,
|
||||
&type);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"Failed to get Image name from service key, %!STATUS!",
|
||||
status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
//
|
||||
// Verify that the data from the registry is a valid string.
|
||||
//
|
||||
if (type != REG_SZ && type != REG_EXPAND_SZ) {
|
||||
return STATUS_OBJECT_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
if (length == 0 || length > USHORT_MAX) {
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// string must be NULL-terminated
|
||||
//
|
||||
PWCHAR str = (PWCHAR) dataBuffer;
|
||||
if (str[(length/sizeof(WCHAR)) - 1] != UNICODE_NULL) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"ERROR: string not terminated with NULL, %!status!\n",
|
||||
status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&imagePath, (PCWSTR) dataBuffer);
|
||||
|
||||
//
|
||||
// Now read the "ImagePath" and extract just the driver filename as a new
|
||||
// unicode string.
|
||||
//
|
||||
GetNameFromPath(&imagePath, &imageName);
|
||||
|
||||
if (imageName.Length == 0x0) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"ERROR: GetNameFromPath could not find a name, %!status!\n",
|
||||
status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for interger overflow for length before we allocate memory
|
||||
// size = path->Length + sizeof(UNICODE_NULL);
|
||||
// len is used below to compute the string size including the NULL, so
|
||||
// compute len to include the terminating NULL.
|
||||
//
|
||||
status = RtlUShortAdd(imageName.Length, sizeof(UNICODE_NULL), &size);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"ERROR: size computation failed, %!status!\n", status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
//
|
||||
// allocate a buffer to hold Unicode string + null char.
|
||||
//
|
||||
ImageName->Buffer = (PWCH) FxPoolAllocate(FxDriverGlobals, PagedPool, size);
|
||||
|
||||
if (ImageName->Buffer == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"ERROR: ExAllocatePoolWithTag failed, %!status!\n", status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
RtlZeroMemory(ImageName->Buffer, size);
|
||||
ImageName->Length = 0x0;
|
||||
ImageName->MaximumLength = size;
|
||||
|
||||
HRESULT hr = StringCbCopy(ImageName->Buffer, size, imageName.Buffer);
|
||||
if (FAILED(hr)) {
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
|
||||
"ERROR: failed to copy string buffer, HRESULT 0x%x, %!status!\n",
|
||||
hr, status);
|
||||
goto cleanUp;
|
||||
}
|
||||
|
||||
//
|
||||
// The copy cannot fail since we setup the buffer to hold enough space for
|
||||
// the contents of the ImagePath value.
|
||||
//
|
||||
ASSERT(NT_SUCCESS(status));
|
||||
|
||||
cleanUp:
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (ImageName->Buffer != NULL) {
|
||||
FxPoolFree(ImageName->Buffer);
|
||||
RtlInitUnicodeString(ImageName, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (dataBuffer != NULL) {
|
||||
FxPoolFree(dataBuffer);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
838
sdk/lib/drivers/wdf/shared/support/um/tracingum.cpp
Normal file
838
sdk/lib/drivers/wdf/shared/support/um/tracingum.cpp
Normal file
|
@ -0,0 +1,838 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
Tracing.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
This module implements tracing for the driver frameworks
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "FxSupportPch.hpp"
|
||||
#include "fxldrum.h"
|
||||
|
||||
extern "C" {
|
||||
#if defined(EVENT_TRACING)
|
||||
#include "TracingUM.tmh"
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <strsafe.h>
|
||||
#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.
|
||||
//
|
||||
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
|
||||
|
||||
--*/
|
||||
{
|
||||
WPP_CLEANUP(NULL);
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiQueryTraceInformation(
|
||||
__in TRACE_INFORMATION_CLASS /* TraceInformationClass */,
|
||||
__out_bcount(TraceInformationLength) PVOID /* TraceInformation */,
|
||||
__in ULONG /* TraceInformationLength */,
|
||||
__out_opt PULONG /* RequiredLength */,
|
||||
__in_opt PVOID /* Buffer */
|
||||
)
|
||||
{
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxWmiTraceMessage(
|
||||
__in TRACEHANDLE LoggerHandle,
|
||||
__in ULONG MessageFlags,
|
||||
__in LPGUID MessageGuid,
|
||||
__in USHORT MessageNumber,
|
||||
...
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
va_list va;
|
||||
va_start(va, MessageNumber);
|
||||
//
|
||||
// UMDF is supported only on XP and newer OS so no need to support w2k
|
||||
// tracing (which requires using a different tracing api, see kmdf impl)
|
||||
//
|
||||
#pragma prefast(suppress:__WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean");
|
||||
status = TraceMessageVa(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;
|
||||
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 "log", so use tha term when
|
||||
// overriding the size via the registry.
|
||||
//
|
||||
DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf");
|
||||
DECLARE_CONST_UNICODE_STRING(valueName, L"LogPages");
|
||||
|
||||
//
|
||||
// UMDF may not provide this registry path
|
||||
//
|
||||
if (NULL == RegistryPath) {
|
||||
goto defaultValues;
|
||||
}
|
||||
|
||||
status = FxRegKey::_OpenKey(NULL,
|
||||
(PCUNICODE_STRING)RegistryPath,
|
||||
&service.m_Key,
|
||||
KEY_READ);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto defaultValues;
|
||||
}
|
||||
|
||||
status = FxRegKey::_OpenKey(service.m_Key,
|
||||
(PCUNICODE_STRING)¶metersPath,
|
||||
¶meters.m_Key,
|
||||
KEY_READ);
|
||||
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:
|
||||
//
|
||||
// This behavior is different from KMDF. KMDF would allocate Average page count (5)
|
||||
// if Verifier is on otherwise 1 page if the request is large.
|
||||
// Since for UMDF the memory is coming from WudfRd, which does not know about verifier
|
||||
// we will give it max pages here.
|
||||
//
|
||||
if (numPages > FxIFRMaxLogPages) {
|
||||
numPages = FxIFRMaxLogPages;
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
Arguments:
|
||||
|
||||
Returns:
|
||||
|
||||
--*/
|
||||
{
|
||||
PWDF_IFR_HEADER pHeader;
|
||||
ULONG pageCount;
|
||||
ULONG sizeCb;
|
||||
HRESULT hr;
|
||||
IWudfDeviceStack2 *pDeviceStack2;
|
||||
PDRIVER_OBJECT_UM umDriverObject;
|
||||
PWCHAR serviceName;
|
||||
size_t bufferLengthCch;
|
||||
ULONG allocatedBufferLengthCb;
|
||||
LONG i;
|
||||
|
||||
//
|
||||
// Return early if IFR is disabled.
|
||||
//
|
||||
if (FxLibraryGlobals.IfrDisabled) {
|
||||
ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
WDFCASSERT(FxIFRRecordSignature == WDF_IFR_RECORD_SIGNATURE);
|
||||
|
||||
if (FxDriverGlobals == NULL || FxDriverGlobals->WdfLogHeader != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// It is safe to use StringCchLength here as WudfHost makes sure that this
|
||||
// RegistryPath is null terminated
|
||||
//
|
||||
hr = StringCchLength(RegistryPath->Buffer,
|
||||
RegistryPath->MaximumLength/sizeof(WCHAR),
|
||||
&bufferLengthCch);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Lets find the last '\' that will mark the begining of the service name
|
||||
//
|
||||
for (i = (ULONG)bufferLengthCch - 1;
|
||||
i >= 0 && RegistryPath->Buffer[i] != '\\';
|
||||
i--);
|
||||
|
||||
//
|
||||
// We did not find the service name
|
||||
//
|
||||
if (i < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
serviceName = &RegistryPath->Buffer[i+1];
|
||||
|
||||
sizeCb = FxIFRGetSize(FxDriverGlobals, RegistryPath);
|
||||
pageCount = sizeCb / PAGE_SIZE;
|
||||
|
||||
//
|
||||
// Get the IWudfDeviceStack interface
|
||||
//
|
||||
umDriverObject = (PDRIVER_OBJECT_UM)DriverObject;
|
||||
|
||||
pDeviceStack2 = (IWudfDeviceStack2 *)umDriverObject->WudfDevStack;
|
||||
|
||||
if(pDeviceStack2 == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
allocatedBufferLengthCb = 0;
|
||||
hr = pDeviceStack2->AllocateIfrMemory(serviceName,
|
||||
pageCount,
|
||||
FALSE,
|
||||
TRUE,
|
||||
(PVOID *)&pHeader,
|
||||
&allocatedBufferLengthCb);
|
||||
|
||||
if (pHeader == NULL || allocatedBufferLengthCb <= sizeof(WDF_IFR_HEADER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 = allocatedBufferLengthCb - sizeof(WDF_IFR_HEADER);
|
||||
|
||||
pHeader->Offset.u.s.Current = 0;
|
||||
pHeader->Offset.u.s.Previous = 0;
|
||||
pHeader->SequenceNumberPointer = &(DriverObject->IfrSequenceNumber);
|
||||
|
||||
StringCchCopyA(pHeader->DriverName, WDF_IFR_HEADER_NAME_LEN, FxDriverGlobals->Public.DriverName);
|
||||
|
||||
FxDriverGlobals->WdfLogHeader = pHeader;
|
||||
|
||||
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
|
||||
"FxIFR logging started" );
|
||||
|
||||
if (sizeCb > 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!",
|
||||
sizeCb, sizeCb/PAGE_SIZE);
|
||||
}
|
||||
|
||||
if (sizeCb != allocatedBufferLengthCb) {
|
||||
ASSERTMSG("FxIFR requested buffer size could not be allocated",FALSE);
|
||||
DoTraceLevelMessage(
|
||||
FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDRIVER,
|
||||
"FxIFR requested an allocation of size 0x%x bytes, "
|
||||
"Allocated memory was of size 0x%x bytes",
|
||||
sizeCb, allocatedBufferLengthCb);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FxIFRStop(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine stops the In-Flight Recorder (IFR).
|
||||
|
||||
For UMDF FxIFRStop is no longer required as WudfRd manages the buffer's lifetime
|
||||
The buffer is kept alive till WudfRd unloads to aid in debugging in cases of
|
||||
WudfHost crash or in dumps with WudfHost paged out or not captured
|
||||
|
||||
Arguments:
|
||||
|
||||
Returns:
|
||||
|
||||
--*/
|
||||
{
|
||||
UNREFERENCED_PARAMETER(FxDriverGlobals);
|
||||
|
||||
//
|
||||
// Uncomment the code below if you add any logic to this function.
|
||||
//
|
||||
// if (FxLibraryGlobals.IfrDisabled) {
|
||||
// ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
FxIFR(
|
||||
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
||||
__in UCHAR MessageLevel,
|
||||
__in ULONG MessageFlags,
|
||||
__in LPGUID MessageGuid,
|
||||
__in USHORT MessageNumber,
|
||||
...
|
||||
)
|
||||
/*++
|
||||
|
||||
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;
|
||||
|
||||
UNREFERENCED_PARAMETER( MessageLevel );
|
||||
|
||||
//
|
||||
// Return early if IFR is disabled.
|
||||
//
|
||||
if (FxLibraryGlobals.IfrDisabled) {
|
||||
ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if ( FxDriverGlobals->WdfLogHeader == NULL) {
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
UNREFERENCED_PARAMETER( MessageFlags );
|
||||
|
||||
|
||||
//
|
||||
// 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
|
||||
//
|
||||
{
|
||||
PWDF_IFR_HEADER header;
|
||||
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;
|
||||
ASSERT(header->Size < FxIFRMaxLogSize); // size doesn't include header.
|
||||
ASSERT(header->Size >= header->Offset.u.s.Current);
|
||||
ASSERT(header->Size >= header->Offset.u.s.Previous);
|
||||
|
||||
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->SequenceNumberPointer);
|
||||
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);
|
||||
#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean");
|
||||
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);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
{
|
||||
//
|
||||
// Increment sequence number to indicate dropped message
|
||||
//
|
||||
drop_message:
|
||||
PWDF_IFR_HEADER header;
|
||||
header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader;
|
||||
InterlockedIncrement(header->SequenceNumberPointer);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue