[WDF] Add Windows Driver Framework files

Takern from Microsoft GitHub repo:
d9c6040fe9

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

View file

@ -0,0 +1,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);
}
}

View 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

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

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

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

File diff suppressed because it is too large Load diff

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

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

File diff suppressed because it is too large Load diff

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

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

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

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

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

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

View 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

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

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

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

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

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

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

View file

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

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

View 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(&currentTime);
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,
&parametersPath,
&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,
&parametersPart,
&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(&currentTime);
status = Mx::MxSetValueKey(hWdf.m_Key,
&wdfTimeOfLastTelemetryLog,
0,
REG_QWORD,
&currentTime.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;
}

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

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

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

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

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

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

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

View 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)&parametersPath,
&parameters.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;
}
}