--- /dev/null
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+ FxResource.hpp
+
+Abstract:
+
+ This module implements the resource object.
+
+Author:
+
+
+
+Environment:
+
+ Both kernel and user mode
+
+Revision History:
+
+--*/
+
+#ifndef _FXRESOURCE_H_
+#define _FXRESOURCE_H_
+
+extern "C" {
+
+#if defined(EVENT_TRACING)
+#include "FxResource.hpp.tmh"
+#endif
+
+}
+
+#if (FX_CORE_MODE==FX_CORE_USER_MODE)
+
+struct FxRegisterResourceInfo : FxStump {
+ //
+ // start physical address of resource range assigned by pnp
+ //
+ PHYSICAL_ADDRESS m_StartPa;
+
+ //
+ // start of mapped system base address
+ //
+ PVOID m_StartSystemVa;
+
+ //
+ // end of mapped system base address
+ //
+ PVOID m_EndSystemVa;
+
+ //
+ // user-mode mapped address
+ //
+ PVOID m_StartUsermodeVa;
+
+ //
+ // Length of resource range assigned by pnp
+ //
+ SIZE_T m_Length;
+
+ //
+ // Length of mapped resource range
+ //
+ SIZE_T m_MappedLength;
+
+ static
+ NTSTATUS
+ _CreateAndInit(
+ _In_ PFX_DRIVER_GLOBALS DriverGlobals,
+ _In_ ULONG Count,
+ _Out_ FxRegisterResourceInfo** RegisterTable
+ )
+ {
+ NTSTATUS status;
+ FxRegisterResourceInfo* table;
+
+ ASSERT(RegisterTable != NULL);
+ *RegisterTable = NULL;
+
+ table = new (DriverGlobals) FxRegisterResourceInfo[Count];
+ if (table == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ DoTraceLevelMessage(
+ DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
+ "Failed to allocate Resource table %!STATUS!", status);
+ return status;
+ }
+
+ *RegisterTable = table;
+ status = STATUS_SUCCESS;
+
+ return status;
+ }
+
+ FxRegisterResourceInfo(
+ VOID
+ ):
+ m_StartSystemVa(NULL),
+ m_EndSystemVa(NULL),
+ m_StartUsermodeVa(NULL),
+ m_Length(0),
+ m_MappedLength(0)
+ {
+ m_StartPa.QuadPart = 0;
+ };
+
+ ~FxRegisterResourceInfo(){;};
+
+ VOID
+ SetPhysicalAddress(
+ __in PHYSICAL_ADDRESS StartPa,
+ __in SIZE_T Length
+ )
+ {
+ m_StartPa = StartPa;
+ m_Length = Length;
+ }
+
+ VOID
+ SetMappedAddress(
+ __in PVOID SystemBaseAddress,
+ __in SIZE_T MappedLength,
+ __in PVOID UsermodeBaseAddress
+ )
+ {
+ m_StartSystemVa = SystemBaseAddress;
+ m_MappedLength = MappedLength;
+ m_EndSystemVa = ((PUCHAR) m_StartSystemVa) + MappedLength - 1;
+ m_StartUsermodeVa = UsermodeBaseAddress;
+ };
+
+ VOID
+ ClearMappedAddress(
+ VOID
+ )
+ {
+ m_StartSystemVa = NULL;
+ m_EndSystemVa = NULL;
+ m_StartUsermodeVa = NULL;
+ m_MappedLength = 0;
+ };
+
+};
+
+struct FxPortResourceInfo : FxStump {
+ //
+ // start physical address
+ //
+ PHYSICAL_ADDRESS m_StartPa;
+
+ //
+ // end physical address
+ //
+ PHYSICAL_ADDRESS m_EndPa;
+
+ //
+ // Length of resource
+ //
+ SIZE_T m_Length;
+
+ static
+ NTSTATUS
+ _CreateAndInit(
+ _In_ PFX_DRIVER_GLOBALS DriverGlobals,
+ _In_ ULONG Count,
+ _Out_ FxPortResourceInfo** PortTable
+ )
+ {
+ NTSTATUS status;
+ FxPortResourceInfo* table;
+
+ ASSERT(PortTable != NULL);
+ *PortTable = NULL;
+
+ table = new (DriverGlobals) FxPortResourceInfo[Count];
+ if (table == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ DoTraceLevelMessage(
+ DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
+ "Failed to allocate Resource table %!STATUS!", status);
+ return status;
+ }
+
+ *PortTable = table;
+ status = STATUS_SUCCESS;
+
+ return status;
+ }
+
+ FxPortResourceInfo(
+ VOID
+ ):
+ m_Length(0)
+ {
+ m_StartPa.QuadPart = 0;
+ m_EndPa.QuadPart = 0;
+ };
+
+ ~FxPortResourceInfo(){;};
+
+ VOID
+ SetPhysicalAddress(
+ __in PHYSICAL_ADDRESS StartPa,
+ __in SIZE_T Length
+ )
+ {
+ m_StartPa = StartPa;
+ m_EndPa.QuadPart = StartPa.QuadPart + Length - 1;
+ m_Length = Length;
+ }
+};
+
+#endif
+
+//
+// Used in FilterResourceRequirements, and QueryResourceRequirements
+//
+
+class FxResourceIo : public FxObject {
+public:
+ IO_RESOURCE_DESCRIPTOR m_Descriptor;
+
+ //
+ // Clone of m_Descriptor which is returned to the driver writer when it
+ // requests a descriptor pointer. We clone the descriptor so that if the
+ // driver writer attempts to modify the pointer in place, they modify the
+ // clone and not the real descriptor.
+ //
+ IO_RESOURCE_DESCRIPTOR m_DescriptorClone;
+
+public:
+ FxResourceIo(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in PIO_RESOURCE_DESCRIPTOR Resource
+ ) : FxObject(FX_TYPE_RESOURCE_IO, 0, FxDriverGlobals)
+ {
+ RtlCopyMemory(&m_Descriptor, Resource, sizeof(m_Descriptor));
+ }
+
+ DECLARE_INTERNAL_NEW_OPERATOR();
+};
+
+//
+// Used in StartDevice
+//
+class FxResourceCm : public FxObject {
+public:
+ CM_PARTIAL_RESOURCE_DESCRIPTOR m_Descriptor;
+
+ //
+ // Clone of m_Descriptor which is returned to the driver writer when it
+ // requests a descriptor pointer. We clone the descriptor so that if the
+ // driver writer attempts to modify the pointer in place, they modify the
+ // clone and not the real descriptor.
+ //
+ CM_PARTIAL_RESOURCE_DESCRIPTOR m_DescriptorClone;
+
+public:
+ FxResourceCm(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource
+ ) : FxObject(FX_TYPE_RESOURCE_CM, 0, FxDriverGlobals)
+ {
+ RtlCopyMemory(&m_Descriptor, Resource, sizeof(m_Descriptor));
+ }
+
+ DECLARE_INTERNAL_NEW_OPERATOR();
+};
+
+enum FxResourceAccessFlags {
+ FxResourceNoAccess = 0x0000,
+ FxResourceAddAllowed = 0x0001,
+ FxResourceRemoveAllowed = 0x0002,
+ FxResourceAllAccessAllowed = FxResourceAddAllowed | FxResourceRemoveAllowed,
+};
+
+class FxResourceCollection : public FxCollection {
+protected:
+ FxResourceCollection(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in WDFTYPE Type,
+ __in USHORT Size,
+ __in UCHAR AccessFlags = FxResourceNoAccess
+ ) : FxCollection(FxDriverGlobals, Type, Size),
+ m_AccessFlags(AccessFlags), m_Changed(FALSE)
+ {
+ //
+ // Driver cannot delete this or any of its derivations
+ //
+ MarkNoDeleteDDI();
+ }
+
+public:
+
+ BOOLEAN
+ RemoveAndDelete(
+ __in ULONG Index
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ AddAt(
+ __in ULONG Index,
+ __in FxObject* Object
+ );
+
+ BOOLEAN
+ IsRemoveAllowed(
+ VOID
+ )
+ {
+ return FLAG_TO_BOOL(m_AccessFlags, FxResourceRemoveAllowed);
+ }
+
+ BOOLEAN
+ IsAddAllowed(
+ VOID
+ )
+ {
+ return FLAG_TO_BOOL(m_AccessFlags, FxResourceAddAllowed);
+ }
+
+ VOID
+ MarkChanged(
+ VOID
+ )
+ {
+ m_Changed = TRUE;
+ }
+
+ BOOLEAN
+ IsChanged(
+ VOID
+ )
+ {
+ return m_Changed;
+ }
+
+public:
+ UCHAR m_AccessFlags;
+
+ BOOLEAN m_Changed;
+};
+
+class FxCmResList : public FxResourceCollection {
+
+#if (FX_CORE_MODE==FX_CORE_USER_MODE)
+protected:
+ //
+ // Table of mapped register resources
+ //
+ FxRegisterResourceInfo* m_RegisterResourceTable;
+ ULONG m_RegisterResourceTableSizeCe;
+
+ //
+ // Table of port resources
+ //
+ FxPortResourceInfo* m_PortResourceTable;
+ ULONG m_PortResourceTableSizeCe;
+
+ //
+ // TRUE if we have at least one CmResourceTypeConnection resource.
+ //
+ BOOLEAN m_HasConnectionResources;
+
+ //
+ // Lock to serialize access to port/register resource table
+ //
+ MxLock m_ResourceTableLock;
+
+#endif // FX_CORE_USER_MODE
+
+protected:
+ FxCmResList(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in UCHAR AccessFlags
+ ) : FxResourceCollection(FxDriverGlobals,
+ FX_TYPE_CM_RES_LIST,
+ sizeof(FxCmResList),
+ AccessFlags)
+ {
+#if (FX_CORE_MODE==FX_CORE_USER_MODE)
+ m_RegisterResourceTable = NULL;
+ m_PortResourceTable = NULL;
+ m_RegisterResourceTableSizeCe = 0;
+ m_PortResourceTableSizeCe = 0;
+ m_HasConnectionResources = FALSE;
+#endif // FX_CORE_USER_MODE
+ }
+
+ ~FxCmResList();
+
+public:
+ static
+ _Must_inspect_result_
+ NTSTATUS
+ _CreateAndInit(
+ __in FxCmResList** ResourceList,
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in CfxDevice * Device,
+ __in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes,
+ __in UCHAR AccessFlags
+ )
+ {
+ NTSTATUS ntStatus;
+ FxCmResList *resList = NULL;
+
+ UNREFERENCED_PARAMETER(Device);
+
+ //
+ // Initialize
+ //
+ *ResourceList = NULL;
+
+ //
+ // Allocate a new resource list object
+ //
+ resList = new(FxDriverGlobals, ListAttributes)
+ FxCmResList(FxDriverGlobals, AccessFlags);
+
+ if (resList == NULL) {
+
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR,
+ TRACINGDEVICE,
+ "Failed to allocate FxCmResList, "
+ "returning %!STATUS!",
+ ntStatus);
+ goto exit;
+ }
+
+ *ResourceList = resList;
+ ntStatus = STATUS_SUCCESS;
+
+ exit:
+ if (!NT_SUCCESS(ntStatus)) {
+ if (NULL != resList) {
+ resList->DeleteFromFailedCreate();
+ }
+ }
+ return ntStatus;
+ }
+
+ WDFCMRESLIST
+ GetHandle(
+ VOID
+ )
+ {
+ return (WDFCMRESLIST) GetObjectHandle();
+ }
+
+ _Must_inspect_result_
+ NTSTATUS
+ BuildFromWdmList(
+ __in PCM_RESOURCE_LIST ResourceList,
+ __in UCHAR AccessFlags
+ );
+
+ _Must_inspect_result_
+ PCM_RESOURCE_LIST
+ CreateWdmList(
+ __in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType = PagedPool
+ );
+
+ ULONG
+ GetCount(
+ VOID
+ );
+
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR
+ GetDescriptor(
+ __in ULONG Index
+ );
+
+#if (FX_CORE_MODE == FX_CORE_USER_MODE)
+
+ //
+ // Lock functions used internally
+ //
+ __inline
+ void
+#pragma prefast(suppress:__WARNING_UNEXPECTED_IRQL_CHANGE, "UM has no IRQL")
+ LockResourceTable(
+ )
+ {
+ KIRQL oldIrql;
+
+ m_ResourceTableLock.Acquire(&oldIrql);
+
+ UNREFERENCED_PARAMETER(oldIrql);
+ }
+
+ __inline
+ void
+#pragma prefast(suppress:__WARNING_UNEXPECTED_IRQL_CHANGE, "UM has no IRQL")
+ UnlockResourceTable(
+ )
+ {
+ m_ResourceTableLock.Release(PASSIVE_LEVEL);
+ }
+
+ NTSTATUS
+ BuildRegisterResourceTable(
+ VOID
+ );
+
+ NTSTATUS
+ BuildPortResourceTable(
+ VOID
+ );
+
+ VOID
+ UpdateRegisterResourceEntryLocked(
+ __in FxRegisterResourceInfo* Entry,
+ __in PVOID SystemMappedAddress,
+ __in SIZE_T NumberOfBytes,
+ __in PVOID UsermodeMappedAddress
+ );
+
+ VOID
+ ClearRegisterResourceEntryLocked(
+ __in FxRegisterResourceInfo* Entry
+ );
+
+ HRESULT
+ ValidateRegisterPhysicalAddressRange (
+ __in PHYSICAL_ADDRESS PhysicalAddress,
+ __in SIZE_T Size,
+ __out FxRegisterResourceInfo** TableEntry
+ );
+
+ HRESULT
+ ValidateRegisterSystemBaseAddress (
+ __in PVOID Address,
+ __out PVOID* UsermodeBaseAddress
+ );
+
+ HRESULT
+ ValidateRegisterSystemAddressRange (
+ __in PVOID SystemAddress,
+ __in SIZE_T Length,
+ __out_opt PVOID* UsermodeAddress
+ );
+
+ HRESULT
+ ValidateAndClearMapping(
+ __in PVOID Address,
+ __in SIZE_T Length
+ );
+
+ HRESULT
+ ValidatePortAddressRange(
+ __in PVOID Address,
+ __in SIZE_T Length
+ );
+
+ SIZE_T
+ GetResourceLength(
+ __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
+ __out_opt PHYSICAL_ADDRESS* Start
+ );
+
+ HRESULT
+ MapIoSpaceWorker(
+ __in PHYSICAL_ADDRESS PhysicalAddress,
+ __in SIZE_T NumberOfBytes,
+ __in MEMORY_CACHING_TYPE CacheType,
+ __deref_out VOID** PseudoBaseAddress
+ );
+
+ VOID
+ ValidateResourceUnmap(
+ VOID
+ );
+
+ VOID
+ DeleteRegisterResourceTable(
+ VOID
+ )
+ {
+ LockResourceTable();
+ if (m_RegisterResourceTable != NULL) {
+ delete [] m_RegisterResourceTable;
+ m_RegisterResourceTable = NULL;
+ m_RegisterResourceTableSizeCe = 0;
+ }
+ UnlockResourceTable();
+ }
+
+ VOID
+ DeletePortResourceTable(
+ VOID
+ )
+ {
+ LockResourceTable();
+ if (m_PortResourceTable != NULL) {
+ delete [] m_PortResourceTable;
+ m_PortResourceTable = NULL;
+ m_PortResourceTableSizeCe = 0;
+ }
+ UnlockResourceTable();
+ }
+
+ _Must_inspect_result_
+ NTSTATUS
+ CheckForConnectionResources(
+ VOID
+ );
+
+ BOOLEAN
+ HasConnectionResources(
+ VOID
+ )
+ {
+ return m_HasConnectionResources;
+ }
+
+#endif // FX_CORE_USER_MODE
+
+};
+
+class FxIoResReqList : public FxResourceCollection {
+protected:
+ FxIoResReqList(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in UCHAR AccessFlags = FxResourceNoAccess
+ ) :
+ FxResourceCollection(FxDriverGlobals,
+ FX_TYPE_IO_RES_REQ_LIST,
+ sizeof(FxIoResReqList),
+ AccessFlags),
+ m_SlotNumber(0), m_InterfaceType(Internal)
+ {
+ m_AccessFlags = AccessFlags;
+ }
+
+public:
+
+ static
+ _Must_inspect_result_
+ NTSTATUS
+ _CreateAndInit(
+ __in FxIoResReqList** ResourceReqList,
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes,
+ __in UCHAR AccessFlags
+ )
+ {
+ NTSTATUS ntStatus;
+ FxIoResReqList *resReqList = NULL;
+
+ //
+ // Initialize
+ //
+ *ResourceReqList = NULL;
+
+ //
+ // Allocate a new resource list object
+ //
+ resReqList = new(FxDriverGlobals, ListAttributes)
+ FxIoResReqList(FxDriverGlobals, AccessFlags);
+ if (resReqList == NULL) {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR,
+ TRACINGDEVICE,
+ "Failed to allocate FxIoResReqList, "
+ "returning %!STATUS!",
+ ntStatus);
+
+ goto exit;
+ }
+
+ *ResourceReqList = resReqList;
+ ntStatus = STATUS_SUCCESS;
+
+ exit:
+ if (!NT_SUCCESS(ntStatus)) {
+ if (NULL != resReqList) {
+ resReqList->DeleteFromFailedCreate();
+ }
+ }
+ return ntStatus;
+ }
+
+ WDFIORESREQLIST
+ GetHandle(
+ VOID
+ )
+ {
+ return (WDFIORESREQLIST) GetObjectHandle();
+ }
+
+ static
+ _Must_inspect_result_
+ FxIoResReqList*
+ _CreateFromWdmList(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList,
+ __in UCHAR AccessFlags
+ );
+
+ _Must_inspect_result_
+ PIO_RESOURCE_REQUIREMENTS_LIST
+ CreateWdmList(
+ VOID
+ );
+
+public:
+ ULONG m_SlotNumber;
+
+ INTERFACE_TYPE m_InterfaceType;
+};
+
+class FxIoResList : public FxResourceCollection {
+public:
+ FxIoResList(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in FxIoResReqList* RequirementsList
+ ) :
+ FxResourceCollection(FxDriverGlobals, FX_TYPE_IO_RES_LIST, sizeof(FxIoResList)),
+ m_OwningList(RequirementsList)
+ {
+ m_AccessFlags = RequirementsList->m_AccessFlags;
+ }
+
+ WDFIORESLIST
+ GetHandle(
+ VOID
+ )
+ {
+ return (WDFIORESLIST) GetObjectHandle();
+ }
+
+ _Must_inspect_result_
+ NTSTATUS
+ BuildFromWdmList(
+ __deref_in PIO_RESOURCE_LIST* WdmResourceList
+ );
+
+public:
+ FxIoResReqList* m_OwningList;
+};
+
+#endif // _FXRESOURCE_H_