1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxResourceCollection.cpp 8 9 Abstract: 10 11 This module implements a base object for derived collection classes and 12 the derived collection classes. 13 14 Author: 15 16 17 18 Environment: 19 20 Both kernel and user mode 21 22 Revision History: 23 24 --*/ 25 26 #include "fxsupportpch.hpp" 27 28 extern "C" { 29 #if defined(EVENT_TRACING) 30 #include "FxResourceCollection.tmh" 31 #endif 32 } 33 34 BOOLEAN 35 FxResourceCollection::RemoveAndDelete( 36 __in ULONG Index 37 ) 38 /*++ 39 40 Routine Description: 41 Removes an entry from the collection and then deletes it if found. The 42 caller must have removal permissions to perform this action. 43 44 Arguments: 45 Index - zero based index into the collection at which to perform the removal 46 47 Return Value: 48 TRUE if the item was found and deleted, FALSE otherwise 49 50 --*/ 51 { 52 FxObject* pObject; 53 FxCollectionEntry* pEntry; 54 KIRQL irql; 55 56 if (IsRemoveAllowed() == FALSE) { 57 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 58 "Removes not allowed on handle %p, remove at index %d" 59 "failed", GetObjectHandle(), Index); 60 61 FxVerifierDbgBreakPoint(GetDriverGlobals()); 62 return FALSE; 63 } 64 65 pObject = NULL; 66 67 Lock(&irql); 68 69 pEntry = FindEntry(Index); 70 if (pEntry != NULL) { 71 72 // 73 // Mark the list as changed so when we go to create a WDM resource list we 74 // know if a new list is needed. 75 // 76 MarkChanged(); 77 78 pObject = pEntry->m_Object; 79 80 // 81 // Remove the entry 82 // 83 RemoveEntry(pEntry); 84 } 85 Unlock(irql); 86 87 if (pObject != NULL) { 88 // 89 // Delete the object since we created it 90 // 91 pObject->DeleteObject(); 92 pObject = NULL; 93 94 return TRUE; 95 } 96 else { 97 return FALSE; 98 } 99 } 100 101 _Must_inspect_result_ 102 NTSTATUS 103 FxResourceCollection::AddAt( 104 __in ULONG Index, 105 __in FxObject* Object 106 ) 107 /*++ 108 109 Routine Description: 110 Adds an object into the collection at the specified index. 111 112 Arguments: 113 Index - zero baesd index in which to insert into the list. WDF_INSERT_AT_END 114 is a special value which indicates that the insertion is an append. 115 116 Object - object to add 117 118 Return Value: 119 NTSTATUS 120 121 --*/ 122 { 123 FxCollectionEntry *pNew; 124 PLIST_ENTRY ple; 125 NTSTATUS status; 126 KIRQL irql; 127 128 if (IsAddAllowed() == FALSE) { 129 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 130 "Adds not allowed on handle %p, add at index %d" 131 "failed", GetObjectHandle(), Index); 132 133 FxVerifierDbgBreakPoint(GetDriverGlobals()); 134 135 return STATUS_ACCESS_DENIED; 136 } 137 138 Lock(&irql); 139 140 ple = NULL; 141 status = STATUS_SUCCESS; 142 143 pNew = AllocateEntry(GetDriverGlobals()); 144 145 if (pNew != NULL) { 146 // 147 // Inserting at the current count (i.e. one past the end) is the same 148 // as append. 149 // 150 if (Index == WDF_INSERT_AT_END || Index == Count()) { 151 ple = &m_ListHead; 152 } 153 else { 154 FxCollectionEntry* cur, *end; 155 ULONG i; 156 157 for (cur = Start(), end = End(), i = 0; 158 cur != end; 159 cur = cur->Next(), i++) { 160 if (i == Index) { 161 ple = &cur->m_ListEntry; 162 break; 163 } 164 } 165 166 if (ple == NULL) { 167 delete pNew; 168 status = STATUS_ARRAY_BOUNDS_EXCEEDED; 169 } 170 } 171 } 172 else { 173 status = STATUS_INSUFFICIENT_RESOURCES; 174 } 175 176 if (NT_SUCCESS(status)) { 177 PLIST_ENTRY blink; 178 179 // ple now points to the list entry which we will insert our node 180 // *before* 181 182 blink = ple->Blink; 183 184 // Link the previous with the new entry 185 blink->Flink = &pNew->m_ListEntry; 186 pNew->m_ListEntry.Blink = blink; 187 188 // Link the current with the new entry 189 pNew->m_ListEntry.Flink = ple; 190 ple->Blink = &pNew->m_ListEntry; 191 192 AddEntry(pNew, Object); 193 194 // 195 // Mark the list as changed so when we go to create a WDM resource list 196 // we know if a new list is needed. 197 // 198 MarkChanged(); 199 } 200 201 Unlock(irql); 202 203 if (!NT_SUCCESS(status)) { 204 Object->DeleteFromFailedCreate(); 205 } 206 207 return status; 208 } 209 210 _Must_inspect_result_ 211 NTSTATUS 212 FxIoResList::BuildFromWdmList( 213 __deref_in PIO_RESOURCE_LIST* WdmResourceList 214 ) 215 /*++ 216 217 Routine Description: 218 Builds up the collection with FxResourceIo objects based on the passed in 219 WDM io resource list 220 221 Arguments: 222 WdmResourceList - list which specifies the io resource objects to create 223 224 Return Value: 225 NTSTATUS 226 227 --*/ 228 { 229 PIO_RESOURCE_DESCRIPTOR pWdmDescriptor; 230 ULONG i, count; 231 NTSTATUS status; 232 233 pWdmDescriptor = &(*WdmResourceList)->Descriptors[0]; 234 count = (*WdmResourceList)->Count; 235 status = STATUS_SUCCESS; 236 237 for (i = 0; i < count; i++) { 238 // 239 // Now create a new resource object for each resource 240 // in our list. 241 // 242 FxResourceIo *pResource; 243 244 pResource = new(GetDriverGlobals()) 245 FxResourceIo(GetDriverGlobals(), pWdmDescriptor); 246 247 if (pResource == NULL) { 248 // 249 // We failed, clean up, and exit. Since we are only 250 // keeping references on the master collection, if 251 // we free this, everything else will go away too. 252 // 253 status = STATUS_INSUFFICIENT_RESOURCES; 254 } 255 256 if (NT_SUCCESS(status)) { 257 status = pResource->AssignParentObject(this); 258 259 // 260 // See notes in previous AssignParentObject as to why 261 // we are asserting. 262 // 263 ASSERT(NT_SUCCESS(status)); 264 UNREFERENCED_PARAMETER(status); 265 266 status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 267 } 268 269 if (!NT_SUCCESS(status)) { 270 break; 271 } 272 273 pWdmDescriptor++; 274 } 275 276 if (NT_SUCCESS(status)) { 277 status = m_OwningList->Add(this) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 278 } 279 280 if (NT_SUCCESS(status)) { 281 *WdmResourceList = (PIO_RESOURCE_LIST) pWdmDescriptor; 282 } 283 284 return status; 285 } 286 287 _Must_inspect_result_ 288 NTSTATUS 289 FxCmResList::BuildFromWdmList( 290 __in PCM_RESOURCE_LIST WdmResourceList, 291 __in UCHAR AccessFlags 292 ) 293 /*++ 294 295 Routine Description: 296 Builds up the collection with FxResourceCm objects based on the passed in 297 WDM io resource list. 298 299 Arguments: 300 WdmResourceList - list which specifies the io resource objects to create 301 302 AccessFlags - permissions to be associated with the list 303 304 Return Value: 305 NTSTATUS 306 307 --*/ 308 { 309 NTSTATUS status; 310 311 // 312 // Predispose to success 313 // 314 status = STATUS_SUCCESS; 315 316 Clear(); 317 318 m_AccessFlags = AccessFlags; 319 320 if (WdmResourceList != NULL) { 321 PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; 322 ULONG count, i; 323 324 // 325 // We only expect to see one full resource descriptor. 326 // 327 ASSERT(WdmResourceList->Count == 1); 328 329 count = WdmResourceList->List[0].PartialResourceList.Count; 330 pDescriptor = WdmResourceList->List[0].PartialResourceList.PartialDescriptors; 331 332 for(i = 0; i < count; i++, pDescriptor++) { 333 FxResourceCm *pResource; 334 335 pResource = new(GetDriverGlobals()) 336 FxResourceCm(GetDriverGlobals(), pDescriptor); 337 338 if (pResource == NULL) { 339 status = STATUS_INSUFFICIENT_RESOURCES; 340 } 341 342 if (NT_SUCCESS(status)) { 343 status = pResource->AssignParentObject(this); 344 345 // 346 // Since we control our own lifetime here, the assign should 347 // always work. 348 // 349 ASSERT(NT_SUCCESS(status)); 350 351 status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 352 } 353 354 if (!NT_SUCCESS(status)) { 355 Clear(); 356 break; 357 } 358 } 359 } 360 361 return status; 362 } 363 364 _Must_inspect_result_ 365 PCM_RESOURCE_LIST 366 FxCmResList::CreateWdmList( 367 __in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType 368 ) 369 /*++ 370 371 Routine Description: 372 Allocates and initializes a WDM CM resource list based off of the current 373 contents of this collection. 374 375 Arguments: 376 PoolType - the pool type from which to allocate the resource list 377 378 Return Value: 379 a new resource list upon success, NULL upon failure 380 381 --*/ 382 { 383 PCM_RESOURCE_LIST pWdmResourceList; 384 ULONG size; 385 PFX_DRIVER_GLOBALS pFxDriverGlobals; 386 387 pWdmResourceList = NULL; 388 pFxDriverGlobals = GetDriverGlobals(); 389 390 if (Count()) { 391 // 392 // NOTE: This function assumes all resources are on the same bus 393 // and therefore there is only one FULL_RESOURCE_DESCRIPTOR. 394 // 395 size = sizeof(CM_RESOURCE_LIST) + 396 (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count() - 1)); 397 398 pWdmResourceList = (PCM_RESOURCE_LIST) 399 MxMemory::MxAllocatePoolWithTag(PoolType, size, pFxDriverGlobals->Tag); 400 401 if (pWdmResourceList != NULL) { 402 PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; 403 FxCollectionEntry *cur, *end; 404 405 RtlZeroMemory(pWdmResourceList, size); 406 407 pWdmResourceList->Count = 1; // We only return one full descriptor 408 409 pWdmResourceList->List[0].PartialResourceList.Version = 1; 410 pWdmResourceList->List[0].PartialResourceList.Revision = 1; 411 pWdmResourceList->List[0].PartialResourceList.Count = Count(); 412 413 pDescriptor = 414 pWdmResourceList->List[0].PartialResourceList.PartialDescriptors; 415 416 end = End(); 417 for (cur = Start(); cur != end; cur = cur->Next()) { 418 FxResourceCm *pResource; 419 420 pResource = (FxResourceCm*) cur->m_Object; 421 422 RtlCopyMemory(pDescriptor, 423 &pResource->m_Descriptor, 424 sizeof(pResource->m_Descriptor)); 425 pDescriptor++; 426 } 427 } 428 } 429 430 return pWdmResourceList; 431 } 432 433 ULONG 434 FxCmResList::GetCount( 435 VOID 436 ) 437 { 438 ULONG count; 439 KIRQL irql; 440 441 Lock(&irql); 442 count = Count(); 443 Unlock(irql); 444 445 return count; 446 } 447 448 PCM_PARTIAL_RESOURCE_DESCRIPTOR 449 FxCmResList::GetDescriptor( 450 __in ULONG Index 451 ) 452 { 453 FxResourceCm* pObject; 454 KIRQL irql; 455 456 Lock(&irql); 457 pObject = (FxResourceCm*) GetItem(Index); 458 Unlock(irql); 459 460 if (pObject == NULL) { 461 return NULL; 462 } 463 else { 464 // 465 // Copy the current descriptor to the clone and return it 466 // 467 RtlCopyMemory(&pObject->m_DescriptorClone, 468 &pObject->m_Descriptor, 469 sizeof(pObject->m_Descriptor)); 470 471 return &pObject->m_DescriptorClone; 472 } 473 } 474 475 _Must_inspect_result_ 476 FxIoResReqList* 477 FxIoResReqList::_CreateFromWdmList( 478 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 479 __in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList, 480 __in UCHAR AccessFlags 481 ) 482 /*++ 483 484 Routine Description: 485 Allocates and populates an FxIoResReqList based on the WDM resource 486 requirements list. 487 488 Arguments: 489 WdmRequirementsList - a list of IO_RESOURCE_LISTs which will indicate how 490 to fill in the returned collection object 491 492 AccessFlags - permissions to associate with the newly created object 493 494 Return Value: 495 a new object upon success, NULL upon failure 496 497 --*/ 498 499 { 500 FxIoResReqList* pIoResReqList; 501 ULONG i; 502 503 pIoResReqList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) 504 FxIoResReqList(FxDriverGlobals, AccessFlags); 505 506 if (pIoResReqList != NULL) { 507 PIO_RESOURCE_LIST pWdmResourceList; 508 NTSTATUS status; 509 510 if (WdmRequirementsList == NULL) { 511 return pIoResReqList; 512 } 513 514 status = STATUS_SUCCESS; 515 pWdmResourceList = &WdmRequirementsList->List[0]; 516 517 pIoResReqList->m_InterfaceType = WdmRequirementsList->InterfaceType; 518 pIoResReqList->m_SlotNumber = WdmRequirementsList->SlotNumber; 519 520 for (i = 0; i < WdmRequirementsList->AlternativeLists; i++) { 521 FxIoResList *pResList; 522 523 pResList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) 524 FxIoResList(FxDriverGlobals, pIoResReqList); 525 526 if (pResList != NULL) { 527 status = pResList->AssignParentObject(pIoResReqList); 528 529 // 530 // Since we control our own lifetime, assigning the parent should 531 // never fail. 532 // 533 ASSERT(NT_SUCCESS(status)); 534 535 status = pResList->BuildFromWdmList(&pWdmResourceList); 536 } 537 else { 538 // 539 // We failed to allocate a child collection. Clean up 540 // and break out of the loop. 541 // 542 status = STATUS_INSUFFICIENT_RESOURCES; 543 } 544 545 if (!NT_SUCCESS(status)) { 546 break; 547 } 548 } 549 550 if (!NT_SUCCESS(status)) { 551 // 552 // Cleanup and return a NULL object 553 // 554 pIoResReqList->DeleteObject(); 555 pIoResReqList = NULL; 556 } 557 } 558 559 return pIoResReqList; 560 } 561 562 _Must_inspect_result_ 563 PIO_RESOURCE_REQUIREMENTS_LIST 564 FxIoResReqList::CreateWdmList( 565 VOID 566 ) 567 /*++ 568 569 Routine Description: 570 Creates a WDM io resource requirements list based off of the current 571 contents of the collection 572 573 Arguments: 574 None 575 576 Return Value: 577 new WDM io resource requirements list allocated out of paged pool upon success, 578 NULL upon failure or an empty list 579 580 --*/ 581 { 582 PIO_RESOURCE_REQUIREMENTS_LIST pRequirementsList; 583 FxCollectionEntry *cur, *end; 584 NTSTATUS status; 585 ULONG totalDescriptors; 586 ULONG size; 587 ULONG count; 588 ULONG tmp; 589 PFX_DRIVER_GLOBALS pFxDriverGlobals; 590 591 totalDescriptors = 0; 592 pRequirementsList = NULL; 593 594 count = Count(); 595 pFxDriverGlobals = GetDriverGlobals(); 596 597 if (count > 0) { 598 // 599 // The collection object should contain a set of child collections 600 // with each of the various requirement lists. Use the number of 601 // these collections to determine the size of our requirements 602 // list. 603 // 604 end = End(); 605 for (cur = Start(); cur != end; cur = cur->Next()) { 606 status = RtlULongAdd(totalDescriptors, 607 ((FxIoResList *) cur->m_Object)->Count(), 608 &totalDescriptors); 609 610 if (!NT_SUCCESS(status)) { 611 goto Overflow; 612 } 613 } 614 615 // 616 // We now have enough information to determine how much memory we 617 // need to allocate for our requirements list. 618 // 619 // size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + 620 // (sizeof(IO_RESOURCE_LIST) * (count - 1)) + 621 // (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors) - 622 // (sizeof(IO_RESOURCE_DESCRIPTOR) * count); 623 // 624 // sizeof(IO_RESOURCE_DESCRIPTOR) * count is subtracted off because 625 // each IO_RESOURCE_LIST has an embedded IO_RESOURCE_DESCRIPTOR in it 626 // and we don't want to overallocated. 627 // 628 629 // 630 // To handle overflow each mathematical operation is split out into an 631 // overflow safe call. 632 // 633 size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); 634 635 // sizeof(IO_RESOURCE_LIST) * (count - 1) 636 status = RtlULongMult(sizeof(IO_RESOURCE_LIST), count - 1, &tmp); 637 if (!NT_SUCCESS(status)) { 638 goto Overflow; 639 } 640 641 status = RtlULongAdd(size, tmp, &size); 642 if (!NT_SUCCESS(status)) { 643 goto Overflow; 644 } 645 646 // (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors) 647 status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR), 648 totalDescriptors, 649 &tmp); 650 if (!NT_SUCCESS(status)) { 651 goto Overflow; 652 } 653 654 status = RtlULongAdd(size, tmp, &size); 655 if (!NT_SUCCESS(status)) { 656 goto Overflow; 657 } 658 659 // - sizeof(IO_RESOURCE_DESCRIPTOR) * Count() (note the subtraction!) 660 status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR), count, &tmp); 661 if (!NT_SUCCESS(status)) { 662 goto Overflow; 663 } 664 665 // Sub, not Add! 666 status = RtlULongSub(size, tmp, &size); 667 if (!NT_SUCCESS(status)) { 668 goto Overflow; 669 } 670 671 pRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST) 672 MxMemory::MxAllocatePoolWithTag(PagedPool, size, pFxDriverGlobals->Tag); 673 674 if (pRequirementsList != NULL) { 675 PIO_RESOURCE_LIST pList; 676 FxResourceIo *pResource; 677 678 pList = pRequirementsList->List; 679 680 // 681 // Start by zero initializing our structure 682 // 683 RtlZeroMemory(pRequirementsList, size); 684 685 // 686 // InterfaceType and BusNumber are unused for WDM, but InterfaceType 687 // is used by the arbiters. 688 // 689 pRequirementsList->InterfaceType = m_InterfaceType; 690 691 pRequirementsList->SlotNumber = m_SlotNumber; 692 693 // 694 // Now populate the requirements list with the resources from 695 // our collections. 696 // 697 pRequirementsList->ListSize = size; 698 pRequirementsList->AlternativeLists = Count(); 699 700 end = End(); 701 for (cur = Start(); cur != end; cur = cur->Next()) { 702 FxIoResList* pIoResList; 703 PIO_RESOURCE_DESCRIPTOR pDescriptor; 704 FxCollectionEntry *pIoResCur, *pIoResEnd; 705 706 pIoResList = (FxIoResList*) cur->m_Object; 707 708 pList->Version = 1; 709 pList->Revision = 1; 710 pList->Count = pIoResList->Count(); 711 712 pDescriptor = pList->Descriptors; 713 714 pIoResEnd = pIoResList->End(); 715 for (pIoResCur = pIoResList->Start(); 716 pIoResCur != pIoResEnd; 717 pIoResCur = pIoResCur->Next()) { 718 719 pResource = (FxResourceIo *) pIoResCur->m_Object; 720 RtlCopyMemory(pDescriptor, 721 &pResource->m_Descriptor, 722 sizeof(pResource->m_Descriptor)); 723 pDescriptor++; 724 } 725 726 pList = (PIO_RESOURCE_LIST) pDescriptor; 727 } 728 } 729 } 730 731 return pRequirementsList; 732 733 Overflow: 734 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 735 "Integer overflow occured when computing size of " 736 "IO_RESOURCE_REQUIREMENTS_LIST"); 737 738 return NULL; 739 } 740