1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxResource.hpp 8 9 Abstract: 10 11 This module implements the resource object. 12 13 Author: 14 15 16 17 Environment: 18 19 Both kernel and user mode 20 21 Revision History: 22 23 --*/ 24 25 #ifndef _FXRESOURCE_H_ 26 #define _FXRESOURCE_H_ 27 28 extern "C" { 29 30 #if defined(EVENT_TRACING) 31 #include "FxResource.hpp.tmh" 32 #endif 33 34 } 35 36 #if (FX_CORE_MODE==FX_CORE_USER_MODE) 37 38 struct FxRegisterResourceInfo : FxStump { 39 // 40 // start physical address of resource range assigned by pnp 41 // 42 PHYSICAL_ADDRESS m_StartPa; 43 44 // 45 // start of mapped system base address 46 // 47 PVOID m_StartSystemVa; 48 49 // 50 // end of mapped system base address 51 // 52 PVOID m_EndSystemVa; 53 54 // 55 // user-mode mapped address 56 // 57 PVOID m_StartUsermodeVa; 58 59 // 60 // Length of resource range assigned by pnp 61 // 62 SIZE_T m_Length; 63 64 // 65 // Length of mapped resource range 66 // 67 SIZE_T m_MappedLength; 68 69 static 70 NTSTATUS _CreateAndInitFxRegisterResourceInfo71 _CreateAndInit( 72 _In_ PFX_DRIVER_GLOBALS DriverGlobals, 73 _In_ ULONG Count, 74 _Out_ FxRegisterResourceInfo** RegisterTable 75 ) 76 { 77 NTSTATUS status; 78 FxRegisterResourceInfo* table; 79 80 ASSERT(RegisterTable != NULL); 81 *RegisterTable = NULL; 82 83 table = new (DriverGlobals) FxRegisterResourceInfo[Count]; 84 if (table == NULL) { 85 status = STATUS_INSUFFICIENT_RESOURCES; 86 DoTraceLevelMessage( 87 DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 88 "Failed to allocate Resource table %!STATUS!", status); 89 return status; 90 } 91 92 *RegisterTable = table; 93 status = STATUS_SUCCESS; 94 95 return status; 96 } 97 FxRegisterResourceInfoFxRegisterResourceInfo98 FxRegisterResourceInfo( 99 VOID 100 ): 101 m_StartSystemVa(NULL), 102 m_EndSystemVa(NULL), 103 m_StartUsermodeVa(NULL), 104 m_Length(0), 105 m_MappedLength(0) 106 { 107 m_StartPa.QuadPart = 0; 108 }; 109 ~FxRegisterResourceInfoFxRegisterResourceInfo110 ~FxRegisterResourceInfo(){;}; 111 112 VOID SetPhysicalAddressFxRegisterResourceInfo113 SetPhysicalAddress( 114 __in PHYSICAL_ADDRESS StartPa, 115 __in SIZE_T Length 116 ) 117 { 118 m_StartPa = StartPa; 119 m_Length = Length; 120 } 121 122 VOID SetMappedAddressFxRegisterResourceInfo123 SetMappedAddress( 124 __in PVOID SystemBaseAddress, 125 __in SIZE_T MappedLength, 126 __in PVOID UsermodeBaseAddress 127 ) 128 { 129 m_StartSystemVa = SystemBaseAddress; 130 m_MappedLength = MappedLength; 131 m_EndSystemVa = ((PUCHAR) m_StartSystemVa) + MappedLength - 1; 132 m_StartUsermodeVa = UsermodeBaseAddress; 133 }; 134 135 VOID ClearMappedAddressFxRegisterResourceInfo136 ClearMappedAddress( 137 VOID 138 ) 139 { 140 m_StartSystemVa = NULL; 141 m_EndSystemVa = NULL; 142 m_StartUsermodeVa = NULL; 143 m_MappedLength = 0; 144 }; 145 146 }; 147 148 struct FxPortResourceInfo : FxStump { 149 // 150 // start physical address 151 // 152 PHYSICAL_ADDRESS m_StartPa; 153 154 // 155 // end physical address 156 // 157 PHYSICAL_ADDRESS m_EndPa; 158 159 // 160 // Length of resource 161 // 162 SIZE_T m_Length; 163 164 static 165 NTSTATUS _CreateAndInitFxPortResourceInfo166 _CreateAndInit( 167 _In_ PFX_DRIVER_GLOBALS DriverGlobals, 168 _In_ ULONG Count, 169 _Out_ FxPortResourceInfo** PortTable 170 ) 171 { 172 NTSTATUS status; 173 FxPortResourceInfo* table; 174 175 ASSERT(PortTable != NULL); 176 *PortTable = NULL; 177 178 table = new (DriverGlobals) FxPortResourceInfo[Count]; 179 if (table == NULL) { 180 status = STATUS_INSUFFICIENT_RESOURCES; 181 DoTraceLevelMessage( 182 DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 183 "Failed to allocate Resource table %!STATUS!", status); 184 return status; 185 } 186 187 *PortTable = table; 188 status = STATUS_SUCCESS; 189 190 return status; 191 } 192 FxPortResourceInfoFxPortResourceInfo193 FxPortResourceInfo( 194 VOID 195 ): 196 m_Length(0) 197 { 198 m_StartPa.QuadPart = 0; 199 m_EndPa.QuadPart = 0; 200 }; 201 ~FxPortResourceInfoFxPortResourceInfo202 ~FxPortResourceInfo(){;}; 203 204 VOID SetPhysicalAddressFxPortResourceInfo205 SetPhysicalAddress( 206 __in PHYSICAL_ADDRESS StartPa, 207 __in SIZE_T Length 208 ) 209 { 210 m_StartPa = StartPa; 211 m_EndPa.QuadPart = StartPa.QuadPart + Length - 1; 212 m_Length = Length; 213 } 214 }; 215 216 #endif 217 218 // 219 // Used in FilterResourceRequirements, and QueryResourceRequirements 220 // 221 222 class FxResourceIo : public FxObject { 223 public: 224 IO_RESOURCE_DESCRIPTOR m_Descriptor; 225 226 // 227 // Clone of m_Descriptor which is returned to the driver writer when it 228 // requests a descriptor pointer. We clone the descriptor so that if the 229 // driver writer attempts to modify the pointer in place, they modify the 230 // clone and not the real descriptor. 231 // 232 IO_RESOURCE_DESCRIPTOR m_DescriptorClone; 233 234 public: FxResourceIo(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PIO_RESOURCE_DESCRIPTOR Resource)235 FxResourceIo( 236 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 237 __in PIO_RESOURCE_DESCRIPTOR Resource 238 ) : FxObject(FX_TYPE_RESOURCE_IO, 0, FxDriverGlobals) 239 { 240 RtlCopyMemory(&m_Descriptor, Resource, sizeof(m_Descriptor)); 241 } 242 243 DECLARE_INTERNAL_NEW_OPERATOR(); 244 }; 245 246 // 247 // Used in StartDevice 248 // 249 class FxResourceCm : public FxObject { 250 public: 251 CM_PARTIAL_RESOURCE_DESCRIPTOR m_Descriptor; 252 253 // 254 // Clone of m_Descriptor which is returned to the driver writer when it 255 // requests a descriptor pointer. We clone the descriptor so that if the 256 // driver writer attempts to modify the pointer in place, they modify the 257 // clone and not the real descriptor. 258 // 259 CM_PARTIAL_RESOURCE_DESCRIPTOR m_DescriptorClone; 260 261 public: FxResourceCm(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource)262 FxResourceCm( 263 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 264 __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource 265 ) : FxObject(FX_TYPE_RESOURCE_CM, 0, FxDriverGlobals) 266 { 267 RtlCopyMemory(&m_Descriptor, Resource, sizeof(m_Descriptor)); 268 } 269 270 DECLARE_INTERNAL_NEW_OPERATOR(); 271 }; 272 273 enum FxResourceAccessFlags { 274 FxResourceNoAccess = 0x0000, 275 FxResourceAddAllowed = 0x0001, 276 FxResourceRemoveAllowed = 0x0002, 277 FxResourceAllAccessAllowed = FxResourceAddAllowed | FxResourceRemoveAllowed, 278 }; 279 280 class FxResourceCollection : public FxCollection { 281 protected: FxResourceCollection(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in WDFTYPE Type,__in USHORT Size,__in UCHAR AccessFlags=FxResourceNoAccess)282 FxResourceCollection( 283 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 284 __in WDFTYPE Type, 285 __in USHORT Size, 286 __in UCHAR AccessFlags = FxResourceNoAccess 287 ) : FxCollection(FxDriverGlobals, Type, Size), 288 m_AccessFlags(AccessFlags), m_Changed(FALSE) 289 { 290 // 291 // Driver cannot delete this or any of its derivations 292 // 293 MarkNoDeleteDDI(); 294 } 295 296 public: 297 298 BOOLEAN 299 RemoveAndDelete( 300 __in ULONG Index 301 ); 302 303 _Must_inspect_result_ 304 NTSTATUS 305 AddAt( 306 __in ULONG Index, 307 __in FxObject* Object 308 ); 309 310 BOOLEAN IsRemoveAllowed(VOID)311 IsRemoveAllowed( 312 VOID 313 ) 314 { 315 return FLAG_TO_BOOL(m_AccessFlags, FxResourceRemoveAllowed); 316 } 317 318 BOOLEAN IsAddAllowed(VOID)319 IsAddAllowed( 320 VOID 321 ) 322 { 323 return FLAG_TO_BOOL(m_AccessFlags, FxResourceAddAllowed); 324 } 325 326 VOID MarkChanged(VOID)327 MarkChanged( 328 VOID 329 ) 330 { 331 m_Changed = TRUE; 332 } 333 334 BOOLEAN IsChanged(VOID)335 IsChanged( 336 VOID 337 ) 338 { 339 return m_Changed; 340 } 341 342 public: 343 UCHAR m_AccessFlags; 344 345 BOOLEAN m_Changed; 346 }; 347 348 class FxCmResList : public FxResourceCollection { 349 350 #if (FX_CORE_MODE==FX_CORE_USER_MODE) 351 protected: 352 // 353 // Table of mapped register resources 354 // 355 FxRegisterResourceInfo* m_RegisterResourceTable; 356 ULONG m_RegisterResourceTableSizeCe; 357 358 // 359 // Table of port resources 360 // 361 FxPortResourceInfo* m_PortResourceTable; 362 ULONG m_PortResourceTableSizeCe; 363 364 // 365 // TRUE if we have at least one CmResourceTypeConnection resource. 366 // 367 BOOLEAN m_HasConnectionResources; 368 369 // 370 // Lock to serialize access to port/register resource table 371 // 372 MxLock m_ResourceTableLock; 373 374 #endif // FX_CORE_USER_MODE 375 376 protected: FxCmResList(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in UCHAR AccessFlags)377 FxCmResList( 378 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 379 __in UCHAR AccessFlags 380 ) : FxResourceCollection(FxDriverGlobals, 381 FX_TYPE_CM_RES_LIST, 382 sizeof(FxCmResList), 383 AccessFlags) 384 { 385 #if (FX_CORE_MODE==FX_CORE_USER_MODE) 386 m_RegisterResourceTable = NULL; 387 m_PortResourceTable = NULL; 388 m_RegisterResourceTableSizeCe = 0; 389 m_PortResourceTableSizeCe = 0; 390 m_HasConnectionResources = FALSE; 391 #endif // FX_CORE_USER_MODE 392 } 393 394 ~FxCmResList(); 395 396 public: 397 static 398 _Must_inspect_result_ 399 NTSTATUS _CreateAndInit(__in FxCmResList ** ResourceList,__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in CfxDevice * Device,__in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes,__in UCHAR AccessFlags)400 _CreateAndInit( 401 __in FxCmResList** ResourceList, 402 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 403 __in CfxDevice * Device, 404 __in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes, 405 __in UCHAR AccessFlags 406 ) 407 { 408 NTSTATUS ntStatus; 409 FxCmResList *resList = NULL; 410 411 UNREFERENCED_PARAMETER(Device); 412 413 // 414 // Initialize 415 // 416 *ResourceList = NULL; 417 418 // 419 // Allocate a new resource list object 420 // 421 resList = new(FxDriverGlobals, ListAttributes) 422 FxCmResList(FxDriverGlobals, AccessFlags); 423 424 if (resList == NULL) { 425 426 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 427 428 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, 429 TRACINGDEVICE, 430 "Failed to allocate FxCmResList, " 431 "returning %!STATUS!", 432 ntStatus); 433 goto exit; 434 } 435 436 *ResourceList = resList; 437 ntStatus = STATUS_SUCCESS; 438 439 exit: 440 if (!NT_SUCCESS(ntStatus)) { 441 if (NULL != resList) { 442 resList->DeleteFromFailedCreate(); 443 } 444 } 445 return ntStatus; 446 } 447 448 WDFCMRESLIST GetHandle(VOID)449 GetHandle( 450 VOID 451 ) 452 { 453 return (WDFCMRESLIST) GetObjectHandle(); 454 } 455 456 _Must_inspect_result_ 457 NTSTATUS 458 BuildFromWdmList( 459 __in PCM_RESOURCE_LIST ResourceList, 460 __in UCHAR AccessFlags 461 ); 462 463 _Must_inspect_result_ 464 PCM_RESOURCE_LIST 465 CreateWdmList( 466 __in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType = PagedPool 467 ); 468 469 ULONG 470 GetCount( 471 VOID 472 ); 473 474 PCM_PARTIAL_RESOURCE_DESCRIPTOR 475 GetDescriptor( 476 __in ULONG Index 477 ); 478 479 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 480 481 // 482 // Lock functions used internally 483 // 484 __inline 485 void 486 #pragma prefast(suppress:__WARNING_UNEXPECTED_IRQL_CHANGE, "UM has no IRQL") LockResourceTable()487 LockResourceTable( 488 ) 489 { 490 KIRQL oldIrql; 491 492 m_ResourceTableLock.Acquire(&oldIrql); 493 494 UNREFERENCED_PARAMETER(oldIrql); 495 } 496 497 __inline 498 void 499 #pragma prefast(suppress:__WARNING_UNEXPECTED_IRQL_CHANGE, "UM has no IRQL") UnlockResourceTable()500 UnlockResourceTable( 501 ) 502 { 503 m_ResourceTableLock.Release(PASSIVE_LEVEL); 504 } 505 506 NTSTATUS 507 BuildRegisterResourceTable( 508 VOID 509 ); 510 511 NTSTATUS 512 BuildPortResourceTable( 513 VOID 514 ); 515 516 VOID 517 UpdateRegisterResourceEntryLocked( 518 __in FxRegisterResourceInfo* Entry, 519 __in PVOID SystemMappedAddress, 520 __in SIZE_T NumberOfBytes, 521 __in PVOID UsermodeMappedAddress 522 ); 523 524 VOID 525 ClearRegisterResourceEntryLocked( 526 __in FxRegisterResourceInfo* Entry 527 ); 528 529 HRESULT 530 ValidateRegisterPhysicalAddressRange ( 531 __in PHYSICAL_ADDRESS PhysicalAddress, 532 __in SIZE_T Size, 533 __out FxRegisterResourceInfo** TableEntry 534 ); 535 536 HRESULT 537 ValidateRegisterSystemBaseAddress ( 538 __in PVOID Address, 539 __out PVOID* UsermodeBaseAddress 540 ); 541 542 HRESULT 543 ValidateRegisterSystemAddressRange ( 544 __in PVOID SystemAddress, 545 __in SIZE_T Length, 546 __out_opt PVOID* UsermodeAddress 547 ); 548 549 HRESULT 550 ValidateAndClearMapping( 551 __in PVOID Address, 552 __in SIZE_T Length 553 ); 554 555 HRESULT 556 ValidatePortAddressRange( 557 __in PVOID Address, 558 __in SIZE_T Length 559 ); 560 561 SIZE_T 562 GetResourceLength( 563 __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, 564 __out_opt PHYSICAL_ADDRESS* Start 565 ); 566 567 HRESULT 568 MapIoSpaceWorker( 569 __in PHYSICAL_ADDRESS PhysicalAddress, 570 __in SIZE_T NumberOfBytes, 571 __in MEMORY_CACHING_TYPE CacheType, 572 __deref_out VOID** PseudoBaseAddress 573 ); 574 575 VOID 576 ValidateResourceUnmap( 577 VOID 578 ); 579 580 VOID DeleteRegisterResourceTable(VOID)581 DeleteRegisterResourceTable( 582 VOID 583 ) 584 { 585 LockResourceTable(); 586 if (m_RegisterResourceTable != NULL) { 587 delete [] m_RegisterResourceTable; 588 m_RegisterResourceTable = NULL; 589 m_RegisterResourceTableSizeCe = 0; 590 } 591 UnlockResourceTable(); 592 } 593 594 VOID DeletePortResourceTable(VOID)595 DeletePortResourceTable( 596 VOID 597 ) 598 { 599 LockResourceTable(); 600 if (m_PortResourceTable != NULL) { 601 delete [] m_PortResourceTable; 602 m_PortResourceTable = NULL; 603 m_PortResourceTableSizeCe = 0; 604 } 605 UnlockResourceTable(); 606 } 607 608 _Must_inspect_result_ 609 NTSTATUS 610 CheckForConnectionResources( 611 VOID 612 ); 613 614 BOOLEAN HasConnectionResources(VOID)615 HasConnectionResources( 616 VOID 617 ) 618 { 619 return m_HasConnectionResources; 620 } 621 622 #endif // FX_CORE_USER_MODE 623 624 }; 625 626 class FxIoResReqList : public FxResourceCollection { 627 protected: FxIoResReqList(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in UCHAR AccessFlags=FxResourceNoAccess)628 FxIoResReqList( 629 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 630 __in UCHAR AccessFlags = FxResourceNoAccess 631 ) : 632 FxResourceCollection(FxDriverGlobals, 633 FX_TYPE_IO_RES_REQ_LIST, 634 sizeof(FxIoResReqList), 635 AccessFlags), 636 m_SlotNumber(0), m_InterfaceType(Internal) 637 { 638 m_AccessFlags = AccessFlags; 639 } 640 641 public: 642 643 static 644 _Must_inspect_result_ 645 NTSTATUS _CreateAndInit(__in FxIoResReqList ** ResourceReqList,__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes,__in UCHAR AccessFlags)646 _CreateAndInit( 647 __in FxIoResReqList** ResourceReqList, 648 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 649 __in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes, 650 __in UCHAR AccessFlags 651 ) 652 { 653 NTSTATUS ntStatus; 654 FxIoResReqList *resReqList = NULL; 655 656 // 657 // Initialize 658 // 659 *ResourceReqList = NULL; 660 661 // 662 // Allocate a new resource list object 663 // 664 resReqList = new(FxDriverGlobals, ListAttributes) 665 FxIoResReqList(FxDriverGlobals, AccessFlags); 666 if (resReqList == NULL) { 667 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 668 669 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, 670 TRACINGDEVICE, 671 "Failed to allocate FxIoResReqList, " 672 "returning %!STATUS!", 673 ntStatus); 674 675 goto exit; 676 } 677 678 *ResourceReqList = resReqList; 679 ntStatus = STATUS_SUCCESS; 680 681 exit: 682 if (!NT_SUCCESS(ntStatus)) { 683 if (NULL != resReqList) { 684 resReqList->DeleteFromFailedCreate(); 685 } 686 } 687 return ntStatus; 688 } 689 690 WDFIORESREQLIST GetHandle(VOID)691 GetHandle( 692 VOID 693 ) 694 { 695 return (WDFIORESREQLIST) GetObjectHandle(); 696 } 697 698 static 699 _Must_inspect_result_ 700 FxIoResReqList* 701 _CreateFromWdmList( 702 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 703 __in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList, 704 __in UCHAR AccessFlags 705 ); 706 707 _Must_inspect_result_ 708 PIO_RESOURCE_REQUIREMENTS_LIST 709 CreateWdmList( 710 VOID 711 ); 712 713 public: 714 ULONG m_SlotNumber; 715 716 INTERFACE_TYPE m_InterfaceType; 717 }; 718 719 class FxIoResList : public FxResourceCollection { 720 public: FxIoResList(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxIoResReqList * RequirementsList)721 FxIoResList( 722 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 723 __in FxIoResReqList* RequirementsList 724 ) : 725 FxResourceCollection(FxDriverGlobals, FX_TYPE_IO_RES_LIST, sizeof(FxIoResList)), 726 m_OwningList(RequirementsList) 727 { 728 m_AccessFlags = RequirementsList->m_AccessFlags; 729 } 730 731 WDFIORESLIST GetHandle(VOID)732 GetHandle( 733 VOID 734 ) 735 { 736 return (WDFIORESLIST) GetObjectHandle(); 737 } 738 739 _Must_inspect_result_ 740 NTSTATUS 741 BuildFromWdmList( 742 __deref_in PIO_RESOURCE_LIST* WdmResourceList 743 ); 744 745 public: 746 FxIoResReqList* m_OwningList; 747 }; 748 749 #endif // _FXRESOURCE_H_ 750