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