1 /* 2 * PROJECT: ReactOS Kernel 3 * COPYRIGHT: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/io/pnpmgr/pnpres.c 5 * PURPOSE: Resource handling code 6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) 7 * ReactOS Portable Systems Group 8 */ 9 10 #include <ntoskrnl.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 15 FORCEINLINE 16 PIO_RESOURCE_LIST 17 IopGetNextResourceList( 18 _In_ const IO_RESOURCE_LIST *ResourceList) 19 { 20 ASSERT((ResourceList->Count > 0) && (ResourceList->Count < 1000)); 21 return (PIO_RESOURCE_LIST)( 22 &ResourceList->Descriptors[ResourceList->Count]); 23 } 24 25 static 26 BOOLEAN 27 IopCheckDescriptorForConflict( 28 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, 29 OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor) 30 { 31 CM_RESOURCE_LIST CmList; 32 NTSTATUS Status; 33 34 CmList.Count = 1; 35 CmList.List[0].InterfaceType = InterfaceTypeUndefined; 36 CmList.List[0].BusNumber = 0; 37 CmList.List[0].PartialResourceList.Version = 1; 38 CmList.List[0].PartialResourceList.Revision = 1; 39 CmList.List[0].PartialResourceList.Count = 1; 40 CmList.List[0].PartialResourceList.PartialDescriptors[0] = *CmDesc; 41 42 Status = IopDetectResourceConflict(&CmList, TRUE, ConflictingDescriptor); 43 if (Status == STATUS_CONFLICTING_ADDRESSES) 44 return TRUE; 45 46 return FALSE; 47 } 48 49 static 50 BOOLEAN 51 IopFindBusNumberResource( 52 IN PIO_RESOURCE_DESCRIPTOR IoDesc, 53 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc) 54 { 55 ULONG Start; 56 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc; 57 58 ASSERT(IoDesc->Type == CmDesc->Type); 59 ASSERT(IoDesc->Type == CmResourceTypeBusNumber); 60 61 for (Start = IoDesc->u.BusNumber.MinBusNumber; 62 Start <= IoDesc->u.BusNumber.MaxBusNumber - IoDesc->u.BusNumber.Length + 1; 63 Start++) 64 { 65 CmDesc->u.BusNumber.Length = IoDesc->u.BusNumber.Length; 66 CmDesc->u.BusNumber.Start = Start; 67 68 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc)) 69 { 70 Start += ConflictingDesc.u.BusNumber.Start + ConflictingDesc.u.BusNumber.Length; 71 } 72 else 73 { 74 DPRINT1("Satisfying bus number requirement with 0x%x (length: 0x%x)\n", Start, CmDesc->u.BusNumber.Length); 75 return TRUE; 76 } 77 } 78 79 return FALSE; 80 } 81 82 static 83 BOOLEAN 84 IopFindMemoryResource( 85 IN PIO_RESOURCE_DESCRIPTOR IoDesc, 86 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc) 87 { 88 ULONGLONG Start; 89 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc; 90 91 ASSERT(IoDesc->Type == CmDesc->Type); 92 ASSERT(IoDesc->Type == CmResourceTypeMemory); 93 94 /* HACK */ 95 if (IoDesc->u.Memory.Alignment == 0) 96 IoDesc->u.Memory.Alignment = 1; 97 98 for (Start = (ULONGLONG)IoDesc->u.Memory.MinimumAddress.QuadPart; 99 Start <= (ULONGLONG)IoDesc->u.Memory.MaximumAddress.QuadPart - IoDesc->u.Memory.Length + 1; 100 Start += IoDesc->u.Memory.Alignment) 101 { 102 CmDesc->u.Memory.Length = IoDesc->u.Memory.Length; 103 CmDesc->u.Memory.Start.QuadPart = (LONGLONG)Start; 104 105 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc)) 106 { 107 Start += (ULONGLONG)ConflictingDesc.u.Memory.Start.QuadPart + 108 ConflictingDesc.u.Memory.Length; 109 } 110 else 111 { 112 DPRINT1("Satisfying memory requirement with 0x%I64x (length: 0x%x)\n", Start, CmDesc->u.Memory.Length); 113 return TRUE; 114 } 115 } 116 117 return FALSE; 118 } 119 120 static 121 BOOLEAN 122 IopFindPortResource( 123 IN PIO_RESOURCE_DESCRIPTOR IoDesc, 124 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc) 125 { 126 ULONGLONG Start; 127 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc; 128 129 ASSERT(IoDesc->Type == CmDesc->Type); 130 ASSERT(IoDesc->Type == CmResourceTypePort); 131 132 /* HACK */ 133 if (IoDesc->u.Port.Alignment == 0) 134 IoDesc->u.Port.Alignment = 1; 135 136 for (Start = (ULONGLONG)IoDesc->u.Port.MinimumAddress.QuadPart; 137 Start <= (ULONGLONG)IoDesc->u.Port.MaximumAddress.QuadPart - IoDesc->u.Port.Length + 1; 138 Start += IoDesc->u.Port.Alignment) 139 { 140 CmDesc->u.Port.Length = IoDesc->u.Port.Length; 141 CmDesc->u.Port.Start.QuadPart = (LONGLONG)Start; 142 143 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc)) 144 { 145 Start += (ULONGLONG)ConflictingDesc.u.Port.Start.QuadPart + ConflictingDesc.u.Port.Length; 146 } 147 else 148 { 149 DPRINT("Satisfying port requirement with 0x%I64x (length: 0x%x)\n", Start, CmDesc->u.Port.Length); 150 return TRUE; 151 } 152 } 153 154 DPRINT1("IopFindPortResource failed!\n"); 155 return FALSE; 156 } 157 158 static 159 BOOLEAN 160 IopFindDmaResource( 161 IN PIO_RESOURCE_DESCRIPTOR IoDesc, 162 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc) 163 { 164 ULONG Channel; 165 166 ASSERT(IoDesc->Type == CmDesc->Type); 167 ASSERT(IoDesc->Type == CmResourceTypeDma); 168 169 for (Channel = IoDesc->u.Dma.MinimumChannel; 170 Channel <= IoDesc->u.Dma.MaximumChannel; 171 Channel++) 172 { 173 CmDesc->u.Dma.Channel = Channel; 174 CmDesc->u.Dma.Port = 0; 175 176 if (!IopCheckDescriptorForConflict(CmDesc, NULL)) 177 { 178 DPRINT1("Satisfying DMA requirement with channel 0x%x\n", Channel); 179 return TRUE; 180 } 181 } 182 183 return FALSE; 184 } 185 186 static 187 BOOLEAN 188 IopFindInterruptResource( 189 IN PIO_RESOURCE_DESCRIPTOR IoDesc, 190 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc) 191 { 192 ULONG Vector; 193 194 ASSERT(IoDesc->Type == CmDesc->Type); 195 ASSERT(IoDesc->Type == CmResourceTypeInterrupt); 196 197 for (Vector = IoDesc->u.Interrupt.MinimumVector; 198 Vector <= IoDesc->u.Interrupt.MaximumVector; 199 Vector++) 200 { 201 CmDesc->u.Interrupt.Vector = Vector; 202 CmDesc->u.Interrupt.Level = Vector; 203 CmDesc->u.Interrupt.Affinity = (KAFFINITY)-1; 204 205 if (!IopCheckDescriptorForConflict(CmDesc, NULL)) 206 { 207 DPRINT1("Satisfying interrupt requirement with IRQ 0x%x\n", Vector); 208 return TRUE; 209 } 210 } 211 212 DPRINT1("Failed to satisfy interrupt requirement with IRQ 0x%x-0x%x\n", 213 IoDesc->u.Interrupt.MinimumVector, 214 IoDesc->u.Interrupt.MaximumVector); 215 return FALSE; 216 } 217 218 NTSTATUS NTAPI 219 IopFixupResourceListWithRequirements( 220 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList, 221 OUT PCM_RESOURCE_LIST *ResourceList) 222 { 223 ULONG i, OldCount; 224 BOOLEAN AlternateRequired = FALSE; 225 PIO_RESOURCE_LIST ResList; 226 227 /* Save the initial resource count when we got here so we can restore if an alternate fails */ 228 if (*ResourceList != NULL) 229 OldCount = (*ResourceList)->List[0].PartialResourceList.Count; 230 else 231 OldCount = 0; 232 233 ResList = &RequirementsList->List[0]; 234 for (i = 0; i < RequirementsList->AlternativeLists; i++, ResList = IopGetNextResourceList(ResList)) 235 { 236 ULONG ii; 237 238 /* We need to get back to where we were before processing the last alternative list */ 239 if (OldCount == 0 && *ResourceList != NULL) 240 { 241 /* Just free it and kill the pointer */ 242 ExFreePool(*ResourceList); 243 *ResourceList = NULL; 244 } 245 else if (OldCount != 0) 246 { 247 PCM_RESOURCE_LIST NewList; 248 249 /* Let's resize it */ 250 (*ResourceList)->List[0].PartialResourceList.Count = OldCount; 251 252 /* Allocate the new smaller list */ 253 NewList = ExAllocatePool(PagedPool, PnpDetermineResourceListSize(*ResourceList)); 254 if (!NewList) 255 return STATUS_NO_MEMORY; 256 257 /* Copy the old stuff back */ 258 RtlCopyMemory(NewList, *ResourceList, PnpDetermineResourceListSize(*ResourceList)); 259 260 /* Free the old one */ 261 ExFreePool(*ResourceList); 262 263 /* Store the pointer to the new one */ 264 *ResourceList = NewList; 265 } 266 267 for (ii = 0; ii < ResList->Count; ii++) 268 { 269 ULONG iii; 270 PCM_PARTIAL_RESOURCE_LIST PartialList = (*ResourceList) ? &(*ResourceList)->List[0].PartialResourceList : NULL; 271 PIO_RESOURCE_DESCRIPTOR IoDesc = &ResList->Descriptors[ii]; 272 BOOLEAN Matched = FALSE; 273 274 /* Skip alternates if we don't need one */ 275 if (!AlternateRequired && (IoDesc->Option & IO_RESOURCE_ALTERNATIVE)) 276 { 277 DPRINT("Skipping unneeded alternate\n"); 278 continue; 279 } 280 281 /* Check if we couldn't satsify a requirement or its alternates */ 282 if (AlternateRequired && !(IoDesc->Option & IO_RESOURCE_ALTERNATIVE)) 283 { 284 DPRINT1("Unable to satisfy preferred resource or alternates in list %lu\n", i); 285 286 /* Break out of this loop and try the next list */ 287 break; 288 } 289 290 for (iii = 0; PartialList && iii < PartialList->Count && !Matched; iii++) 291 { 292 /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific), 293 but only one is allowed and it must be the last one in the list! */ 294 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc = &PartialList->PartialDescriptors[iii]; 295 296 /* First check types */ 297 if (IoDesc->Type != CmDesc->Type) 298 continue; 299 300 switch (IoDesc->Type) 301 { 302 case CmResourceTypeInterrupt: 303 /* Make sure it satisfies our vector range */ 304 if (CmDesc->u.Interrupt.Vector >= IoDesc->u.Interrupt.MinimumVector && 305 CmDesc->u.Interrupt.Vector <= IoDesc->u.Interrupt.MaximumVector) 306 { 307 /* Found it */ 308 Matched = TRUE; 309 } 310 else 311 { 312 DPRINT("Interrupt - Not a match! 0x%x not inside 0x%x to 0x%x\n", 313 CmDesc->u.Interrupt.Vector, 314 IoDesc->u.Interrupt.MinimumVector, 315 IoDesc->u.Interrupt.MaximumVector); 316 } 317 break; 318 319 case CmResourceTypeMemory: 320 case CmResourceTypePort: 321 /* Make sure the length matches and it satisfies our address range */ 322 if (CmDesc->u.Memory.Length == IoDesc->u.Memory.Length && 323 (ULONGLONG)CmDesc->u.Memory.Start.QuadPart >= (ULONGLONG)IoDesc->u.Memory.MinimumAddress.QuadPart && 324 (ULONGLONG)CmDesc->u.Memory.Start.QuadPart + CmDesc->u.Memory.Length - 1 <= (ULONGLONG)IoDesc->u.Memory.MaximumAddress.QuadPart) 325 { 326 /* Found it */ 327 Matched = TRUE; 328 } 329 else 330 { 331 DPRINT("Memory/Port - Not a match! 0x%I64x with length 0x%x not inside 0x%I64x to 0x%I64x with length 0x%x\n", 332 CmDesc->u.Memory.Start.QuadPart, 333 CmDesc->u.Memory.Length, 334 IoDesc->u.Memory.MinimumAddress.QuadPart, 335 IoDesc->u.Memory.MaximumAddress.QuadPart, 336 IoDesc->u.Memory.Length); 337 } 338 break; 339 340 case CmResourceTypeBusNumber: 341 /* Make sure the length matches and it satisfies our bus number range */ 342 if (CmDesc->u.BusNumber.Length == IoDesc->u.BusNumber.Length && 343 CmDesc->u.BusNumber.Start >= IoDesc->u.BusNumber.MinBusNumber && 344 CmDesc->u.BusNumber.Start + CmDesc->u.BusNumber.Length - 1 <= IoDesc->u.BusNumber.MaxBusNumber) 345 { 346 /* Found it */ 347 Matched = TRUE; 348 } 349 else 350 { 351 DPRINT("Bus Number - Not a match! 0x%x with length 0x%x not inside 0x%x to 0x%x with length 0x%x\n", 352 CmDesc->u.BusNumber.Start, 353 CmDesc->u.BusNumber.Length, 354 IoDesc->u.BusNumber.MinBusNumber, 355 IoDesc->u.BusNumber.MaxBusNumber, 356 IoDesc->u.BusNumber.Length); 357 } 358 break; 359 360 case CmResourceTypeDma: 361 /* Make sure it fits in our channel range */ 362 if (CmDesc->u.Dma.Channel >= IoDesc->u.Dma.MinimumChannel && 363 CmDesc->u.Dma.Channel <= IoDesc->u.Dma.MaximumChannel) 364 { 365 /* Found it */ 366 Matched = TRUE; 367 } 368 else 369 { 370 DPRINT("DMA - Not a match! 0x%x not inside 0x%x to 0x%x\n", 371 CmDesc->u.Dma.Channel, 372 IoDesc->u.Dma.MinimumChannel, 373 IoDesc->u.Dma.MaximumChannel); 374 } 375 break; 376 377 default: 378 /* Other stuff is fine */ 379 Matched = TRUE; 380 break; 381 } 382 } 383 384 /* Check if we found a matching descriptor */ 385 if (!Matched) 386 { 387 PCM_RESOURCE_LIST NewList; 388 CM_PARTIAL_RESOURCE_DESCRIPTOR NewDesc; 389 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescPtr; 390 BOOLEAN FoundResource = TRUE; 391 392 /* Setup the new CM descriptor */ 393 NewDesc.Type = IoDesc->Type; 394 NewDesc.Flags = IoDesc->Flags; 395 NewDesc.ShareDisposition = IoDesc->ShareDisposition; 396 397 /* Let'se see if we can find a resource to satisfy this */ 398 switch (IoDesc->Type) 399 { 400 case CmResourceTypeInterrupt: 401 /* Find an available interrupt */ 402 if (!IopFindInterruptResource(IoDesc, &NewDesc)) 403 { 404 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n", 405 IoDesc->u.Interrupt.MinimumVector, IoDesc->u.Interrupt.MaximumVector); 406 407 FoundResource = FALSE; 408 } 409 break; 410 411 case CmResourceTypePort: 412 /* Find an available port range */ 413 if (!IopFindPortResource(IoDesc, &NewDesc)) 414 { 415 DPRINT1("Failed to find an available port resource (0x%I64x to 0x%I64x length: 0x%x)\n", 416 IoDesc->u.Port.MinimumAddress.QuadPart, IoDesc->u.Port.MaximumAddress.QuadPart, 417 IoDesc->u.Port.Length); 418 419 FoundResource = FALSE; 420 } 421 break; 422 423 case CmResourceTypeMemory: 424 /* Find an available memory range */ 425 if (!IopFindMemoryResource(IoDesc, &NewDesc)) 426 { 427 DPRINT1("Failed to find an available memory resource (0x%I64x to 0x%I64x length: 0x%x)\n", 428 IoDesc->u.Memory.MinimumAddress.QuadPart, IoDesc->u.Memory.MaximumAddress.QuadPart, 429 IoDesc->u.Memory.Length); 430 431 FoundResource = FALSE; 432 } 433 break; 434 435 case CmResourceTypeBusNumber: 436 /* Find an available bus address range */ 437 if (!IopFindBusNumberResource(IoDesc, &NewDesc)) 438 { 439 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n", 440 IoDesc->u.BusNumber.MinBusNumber, IoDesc->u.BusNumber.MaxBusNumber, 441 IoDesc->u.BusNumber.Length); 442 443 FoundResource = FALSE; 444 } 445 break; 446 447 case CmResourceTypeDma: 448 /* Find an available DMA channel */ 449 if (!IopFindDmaResource(IoDesc, &NewDesc)) 450 { 451 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n", 452 IoDesc->u.Dma.MinimumChannel, IoDesc->u.Dma.MaximumChannel); 453 454 FoundResource = FALSE; 455 } 456 break; 457 458 default: 459 DPRINT1("Unsupported resource type: %x\n", IoDesc->Type); 460 FoundResource = FALSE; 461 break; 462 } 463 464 /* Check if it's missing and required */ 465 if (!FoundResource && IoDesc->Option == 0) 466 { 467 /* Break out of this loop and try the next list */ 468 DPRINT1("Unable to satisfy required resource in list %lu\n", i); 469 break; 470 } 471 else if (!FoundResource) 472 { 473 /* Try an alternate for this preferred descriptor */ 474 AlternateRequired = TRUE; 475 continue; 476 } 477 else 478 { 479 /* Move on to the next preferred or required descriptor after this one */ 480 AlternateRequired = FALSE; 481 } 482 483 /* Figure out what we need */ 484 if (PartialList == NULL) 485 { 486 /* We need a new list */ 487 NewList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST)); 488 if (!NewList) 489 return STATUS_NO_MEMORY; 490 491 /* Set it up */ 492 NewList->Count = 1; 493 NewList->List[0].InterfaceType = RequirementsList->InterfaceType; 494 NewList->List[0].BusNumber = RequirementsList->BusNumber; 495 NewList->List[0].PartialResourceList.Version = 1; 496 NewList->List[0].PartialResourceList.Revision = 1; 497 NewList->List[0].PartialResourceList.Count = 1; 498 499 /* Set our pointer */ 500 DescPtr = &NewList->List[0].PartialResourceList.PartialDescriptors[0]; 501 } 502 else 503 { 504 /* Allocate the new larger list */ 505 NewList = ExAllocatePool(PagedPool, PnpDetermineResourceListSize(*ResourceList) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); 506 if (!NewList) 507 return STATUS_NO_MEMORY; 508 509 /* Copy the old stuff back */ 510 RtlCopyMemory(NewList, *ResourceList, PnpDetermineResourceListSize(*ResourceList)); 511 512 /* Set our pointer */ 513 DescPtr = &NewList->List[0].PartialResourceList.PartialDescriptors[NewList->List[0].PartialResourceList.Count]; 514 515 /* Increment the descriptor count */ 516 NewList->List[0].PartialResourceList.Count++; 517 518 /* Free the old list */ 519 ExFreePool(*ResourceList); 520 } 521 522 /* Copy the descriptor in */ 523 *DescPtr = NewDesc; 524 525 /* Store the new list */ 526 *ResourceList = NewList; 527 } 528 } 529 530 /* Check if we need an alternate with no resources left */ 531 if (AlternateRequired) 532 { 533 DPRINT1("Unable to satisfy preferred resource or alternates in list %lu\n", i); 534 535 /* Try the next alternate list */ 536 continue; 537 } 538 539 /* We're done because we satisfied one of the alternate lists */ 540 return STATUS_SUCCESS; 541 } 542 543 /* We ran out of alternates */ 544 DPRINT1("Out of alternate lists!\n"); 545 546 /* Free the list */ 547 if (*ResourceList) 548 { 549 ExFreePool(*ResourceList); 550 *ResourceList = NULL; 551 } 552 553 /* Fail */ 554 return STATUS_CONFLICTING_ADDRESSES; 555 } 556 557 static 558 BOOLEAN 559 IopCheckResourceDescriptor( 560 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc, 561 IN PCM_RESOURCE_LIST ResourceList, 562 IN BOOLEAN Silent, 563 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor) 564 { 565 ULONG i, ii; 566 BOOLEAN Result = FALSE; 567 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 568 569 FullDescriptor = &ResourceList->List[0]; 570 for (i = 0; i < ResourceList->Count; i++) 571 { 572 PCM_PARTIAL_RESOURCE_LIST ResList = &FullDescriptor->PartialResourceList; 573 FullDescriptor = CmiGetNextResourceDescriptor(FullDescriptor); 574 575 for (ii = 0; ii < ResList->Count; ii++) 576 { 577 /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific), 578 but only one is allowed and it must be the last one in the list! */ 579 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList->PartialDescriptors[ii]; 580 581 /* We don't care about shared resources */ 582 if (ResDesc->ShareDisposition == CmResourceShareShared && 583 ResDesc2->ShareDisposition == CmResourceShareShared) 584 continue; 585 586 /* Make sure we're comparing the same types */ 587 if (ResDesc->Type != ResDesc2->Type) 588 continue; 589 590 switch (ResDesc->Type) 591 { 592 case CmResourceTypeMemory: 593 { 594 /* NOTE: ranges are in a form [x1;x2) */ 595 UINT64 rStart = (UINT64)ResDesc->u.Memory.Start.QuadPart; 596 UINT64 rEnd = (UINT64)ResDesc->u.Memory.Start.QuadPart 597 + ResDesc->u.Memory.Length; 598 UINT64 r2Start = (UINT64)ResDesc2->u.Memory.Start.QuadPart; 599 UINT64 r2End = (UINT64)ResDesc2->u.Memory.Start.QuadPart 600 + ResDesc2->u.Memory.Length; 601 602 if (rStart < r2End && r2Start < rEnd) 603 { 604 if (!Silent) 605 { 606 DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n", 607 rStart, rEnd, r2Start, r2End); 608 } 609 610 Result = TRUE; 611 612 goto ByeBye; 613 } 614 break; 615 } 616 case CmResourceTypePort: 617 { 618 /* NOTE: ranges are in a form [x1;x2) */ 619 UINT64 rStart = (UINT64)ResDesc->u.Port.Start.QuadPart; 620 UINT64 rEnd = (UINT64)ResDesc->u.Port.Start.QuadPart 621 + ResDesc->u.Port.Length; 622 UINT64 r2Start = (UINT64)ResDesc2->u.Port.Start.QuadPart; 623 UINT64 r2End = (UINT64)ResDesc2->u.Port.Start.QuadPart 624 + ResDesc2->u.Port.Length; 625 626 if (rStart < r2End && r2Start < rEnd) 627 { 628 if (!Silent) 629 { 630 DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n", 631 rStart, rEnd, r2Start, r2End); 632 } 633 634 Result = TRUE; 635 636 goto ByeBye; 637 } 638 break; 639 } 640 case CmResourceTypeInterrupt: 641 { 642 if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector) 643 { 644 if (!Silent) 645 { 646 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n", 647 ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level, 648 ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level); 649 } 650 651 Result = TRUE; 652 653 goto ByeBye; 654 } 655 break; 656 } 657 case CmResourceTypeBusNumber: 658 { 659 /* NOTE: ranges are in a form [x1;x2) */ 660 UINT32 rStart = ResDesc->u.BusNumber.Start; 661 UINT32 rEnd = ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length; 662 UINT32 r2Start = ResDesc2->u.BusNumber.Start; 663 UINT32 r2End = ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length; 664 665 if (rStart < r2End && r2Start < rEnd) 666 { 667 if (!Silent) 668 { 669 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n", 670 rStart, rEnd, r2Start, r2End); 671 } 672 673 Result = TRUE; 674 675 goto ByeBye; 676 } 677 break; 678 } 679 case CmResourceTypeDma: 680 { 681 if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel) 682 { 683 if (!Silent) 684 { 685 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n", 686 ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port, 687 ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port); 688 } 689 690 Result = TRUE; 691 692 goto ByeBye; 693 } 694 break; 695 } 696 } 697 } 698 } 699 700 ByeBye: 701 702 if (Result && ConflictingDescriptor) 703 { 704 RtlCopyMemory(ConflictingDescriptor, 705 ResDesc, 706 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); 707 } 708 709 // Hacked, because after fixing resource list parsing 710 // we actually detect resource conflicts 711 return Silent ? Result : FALSE; // Result; 712 } 713 714 static 715 NTSTATUS 716 IopUpdateControlKeyWithResources( 717 IN PDEVICE_NODE DeviceNode) 718 { 719 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT); 720 UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control"); 721 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"AllocConfig"); 722 HANDLE EnumKey, InstanceKey, ControlKey; 723 NTSTATUS Status; 724 OBJECT_ATTRIBUTES ObjectAttributes; 725 726 /* Open the Enum key */ 727 Status = IopOpenRegistryKeyEx(&EnumKey, NULL, &EnumRoot, KEY_ENUMERATE_SUB_KEYS); 728 if (!NT_SUCCESS(Status)) 729 return Status; 730 731 /* Open the instance key (eg. Root\PNP0A03) */ 732 Status = IopOpenRegistryKeyEx(&InstanceKey, EnumKey, &DeviceNode->InstancePath, KEY_ENUMERATE_SUB_KEYS); 733 ZwClose(EnumKey); 734 735 if (!NT_SUCCESS(Status)) 736 return Status; 737 738 /* Create/Open the Control key */ 739 InitializeObjectAttributes(&ObjectAttributes, 740 &Control, 741 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 742 InstanceKey, 743 NULL); 744 Status = ZwCreateKey(&ControlKey, 745 KEY_SET_VALUE, 746 &ObjectAttributes, 747 0, 748 NULL, 749 REG_OPTION_VOLATILE, 750 NULL); 751 ZwClose(InstanceKey); 752 753 if (!NT_SUCCESS(Status)) 754 return Status; 755 756 /* Write the resource list */ 757 Status = ZwSetValueKey(ControlKey, 758 &ValueName, 759 0, 760 REG_RESOURCE_LIST, 761 DeviceNode->ResourceList, 762 PnpDetermineResourceListSize(DeviceNode->ResourceList)); 763 ZwClose(ControlKey); 764 765 if (!NT_SUCCESS(Status)) 766 return Status; 767 768 return STATUS_SUCCESS; 769 } 770 771 static 772 NTSTATUS 773 IopFilterResourceRequirements( 774 IN PDEVICE_NODE DeviceNode) 775 { 776 IO_STACK_LOCATION Stack; 777 IO_STATUS_BLOCK IoStatusBlock; 778 NTSTATUS Status; 779 780 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n"); 781 782 Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements; 783 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 784 &IoStatusBlock, 785 IRP_MN_FILTER_RESOURCE_REQUIREMENTS, 786 &Stack); 787 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED) 788 { 789 DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n"); 790 return Status; 791 } 792 else if (NT_SUCCESS(Status) && IoStatusBlock.Information) 793 { 794 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 795 } 796 797 return STATUS_SUCCESS; 798 } 799 800 801 NTSTATUS 802 IopUpdateResourceMap( 803 IN PDEVICE_NODE DeviceNode, 804 PWCHAR Level1Key, 805 PWCHAR Level2Key) 806 { 807 NTSTATUS Status; 808 ULONG Disposition; 809 HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey; 810 UNICODE_STRING KeyName; 811 OBJECT_ATTRIBUTES ObjectAttributes; 812 813 RtlInitUnicodeString(&KeyName, 814 L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP"); 815 InitializeObjectAttributes(&ObjectAttributes, 816 &KeyName, 817 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE, 818 NULL, 819 NULL); 820 Status = ZwCreateKey(&ResourceMapKey, 821 KEY_ALL_ACCESS, 822 &ObjectAttributes, 823 0, 824 NULL, 825 REG_OPTION_VOLATILE, 826 &Disposition); 827 if (!NT_SUCCESS(Status)) 828 return Status; 829 830 RtlInitUnicodeString(&KeyName, Level1Key); 831 InitializeObjectAttributes(&ObjectAttributes, 832 &KeyName, 833 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE, 834 ResourceMapKey, 835 NULL); 836 Status = ZwCreateKey(&PnpMgrLevel1, 837 KEY_ALL_ACCESS, 838 &ObjectAttributes, 839 0, 840 NULL, 841 REG_OPTION_VOLATILE, 842 &Disposition); 843 ZwClose(ResourceMapKey); 844 if (!NT_SUCCESS(Status)) 845 return Status; 846 847 RtlInitUnicodeString(&KeyName, Level2Key); 848 InitializeObjectAttributes(&ObjectAttributes, 849 &KeyName, 850 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE, 851 PnpMgrLevel1, 852 NULL); 853 Status = ZwCreateKey(&PnpMgrLevel2, 854 KEY_ALL_ACCESS, 855 &ObjectAttributes, 856 0, 857 NULL, 858 REG_OPTION_VOLATILE, 859 &Disposition); 860 ZwClose(PnpMgrLevel1); 861 if (!NT_SUCCESS(Status)) 862 return Status; 863 864 if (DeviceNode->ResourceList) 865 { 866 UNICODE_STRING NameU; 867 UNICODE_STRING RawSuffix, TranslatedSuffix; 868 ULONG OldLength = 0; 869 870 ASSERT(DeviceNode->ResourceListTranslated); 871 872 RtlInitUnicodeString(&TranslatedSuffix, L".Translated"); 873 RtlInitUnicodeString(&RawSuffix, L".Raw"); 874 875 Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject, 876 DevicePropertyPhysicalDeviceObjectName, 877 0, 878 NULL, 879 &OldLength); 880 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 881 { 882 ASSERT(OldLength); 883 884 NameU.Buffer = ExAllocatePool(PagedPool, OldLength + TranslatedSuffix.Length); 885 if (!NameU.Buffer) 886 { 887 ZwClose(PnpMgrLevel2); 888 return STATUS_INSUFFICIENT_RESOURCES; 889 } 890 891 NameU.Length = 0; 892 NameU.MaximumLength = (USHORT)OldLength + TranslatedSuffix.Length; 893 894 Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject, 895 DevicePropertyPhysicalDeviceObjectName, 896 NameU.MaximumLength, 897 NameU.Buffer, 898 &OldLength); 899 if (!NT_SUCCESS(Status)) 900 { 901 ZwClose(PnpMgrLevel2); 902 ExFreePool(NameU.Buffer); 903 return Status; 904 } 905 } 906 else if (!NT_SUCCESS(Status)) 907 { 908 /* Some failure */ 909 ZwClose(PnpMgrLevel2); 910 return Status; 911 } 912 else 913 { 914 /* This should never happen */ 915 ASSERT(FALSE); 916 } 917 918 NameU.Length = (USHORT)OldLength; 919 920 RtlAppendUnicodeStringToString(&NameU, &RawSuffix); 921 922 Status = ZwSetValueKey(PnpMgrLevel2, 923 &NameU, 924 0, 925 REG_RESOURCE_LIST, 926 DeviceNode->ResourceList, 927 PnpDetermineResourceListSize(DeviceNode->ResourceList)); 928 if (!NT_SUCCESS(Status)) 929 { 930 ZwClose(PnpMgrLevel2); 931 ExFreePool(NameU.Buffer); 932 return Status; 933 } 934 935 /* "Remove" the suffix by setting the length back to what it used to be */ 936 NameU.Length = (USHORT)OldLength; 937 938 RtlAppendUnicodeStringToString(&NameU, &TranslatedSuffix); 939 940 Status = ZwSetValueKey(PnpMgrLevel2, 941 &NameU, 942 0, 943 REG_RESOURCE_LIST, 944 DeviceNode->ResourceListTranslated, 945 PnpDetermineResourceListSize(DeviceNode->ResourceListTranslated)); 946 ZwClose(PnpMgrLevel2); 947 ExFreePool(NameU.Buffer); 948 949 if (!NT_SUCCESS(Status)) 950 return Status; 951 } 952 else 953 { 954 ZwClose(PnpMgrLevel2); 955 } 956 957 return STATUS_SUCCESS; 958 } 959 960 NTSTATUS 961 IopUpdateResourceMapForPnPDevice( 962 IN PDEVICE_NODE DeviceNode) 963 { 964 return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager"); 965 } 966 967 static 968 NTSTATUS 969 IopTranslateDeviceResources( 970 IN PDEVICE_NODE DeviceNode) 971 { 972 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList; 973 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated; 974 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 975 ULONG i, j, ListSize; 976 NTSTATUS Status; 977 978 if (!DeviceNode->ResourceList) 979 { 980 DeviceNode->ResourceListTranslated = NULL; 981 return STATUS_SUCCESS; 982 } 983 984 /* That's easy to translate a resource list. Just copy the 985 * untranslated one and change few fields in the copy 986 */ 987 ListSize = PnpDetermineResourceListSize(DeviceNode->ResourceList); 988 989 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, ListSize); 990 if (!DeviceNode->ResourceListTranslated) 991 { 992 Status = STATUS_NO_MEMORY; 993 goto cleanup; 994 } 995 RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, ListSize); 996 997 FullDescriptor = &DeviceNode->ResourceList->List[0]; 998 for (i = 0; i < DeviceNode->ResourceList->Count; i++) 999 { 1000 pPartialResourceList = &FullDescriptor->PartialResourceList; 1001 FullDescriptor = CmiGetNextResourceDescriptor(FullDescriptor); 1002 1003 for (j = 0; j < pPartialResourceList->Count; j++) 1004 { 1005 /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific), 1006 but only one is allowed and it must be the last one in the list! */ 1007 DescriptorRaw = &pPartialResourceList->PartialDescriptors[j]; 1008 1009 /* Calculate the location of the translated resource descriptor */ 1010 DescriptorTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)( 1011 (PUCHAR)DeviceNode->ResourceListTranslated + 1012 ((PUCHAR)DescriptorRaw - (PUCHAR)DeviceNode->ResourceList)); 1013 1014 switch (DescriptorRaw->Type) 1015 { 1016 case CmResourceTypePort: 1017 { 1018 ULONG AddressSpace = 1; /* IO space */ 1019 if (!HalTranslateBusAddress( 1020 DeviceNode->ResourceList->List[i].InterfaceType, 1021 DeviceNode->ResourceList->List[i].BusNumber, 1022 DescriptorRaw->u.Port.Start, 1023 &AddressSpace, 1024 &DescriptorTranslated->u.Port.Start)) 1025 { 1026 Status = STATUS_UNSUCCESSFUL; 1027 DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw->u.Port.Start.QuadPart); 1028 goto cleanup; 1029 } 1030 1031 if (AddressSpace == 0) 1032 { 1033 DPRINT1("Guessed incorrect address space: 1 -> 0\n"); 1034 1035 /* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are 1036 * invalid for this state but I'm not 100% sure */ 1037 DescriptorRaw->Flags = 1038 DescriptorTranslated->Flags = CM_RESOURCE_PORT_MEMORY; 1039 } 1040 break; 1041 } 1042 case CmResourceTypeInterrupt: 1043 { 1044 KIRQL Irql; 1045 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector( 1046 DeviceNode->ResourceList->List[i].InterfaceType, 1047 DeviceNode->ResourceList->List[i].BusNumber, 1048 DescriptorRaw->u.Interrupt.Level, 1049 DescriptorRaw->u.Interrupt.Vector, 1050 &Irql, 1051 &DescriptorTranslated->u.Interrupt.Affinity); 1052 DescriptorTranslated->u.Interrupt.Level = Irql; 1053 if (!DescriptorTranslated->u.Interrupt.Vector) 1054 { 1055 Status = STATUS_UNSUCCESSFUL; 1056 DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw->u.Interrupt.Vector, 1057 DescriptorRaw->u.Interrupt.Level); 1058 goto cleanup; 1059 } 1060 break; 1061 } 1062 case CmResourceTypeMemory: 1063 { 1064 ULONG AddressSpace = 0; /* Memory space */ 1065 if (!HalTranslateBusAddress( 1066 DeviceNode->ResourceList->List[i].InterfaceType, 1067 DeviceNode->ResourceList->List[i].BusNumber, 1068 DescriptorRaw->u.Memory.Start, 1069 &AddressSpace, 1070 &DescriptorTranslated->u.Memory.Start)) 1071 { 1072 Status = STATUS_UNSUCCESSFUL; 1073 DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw->u.Memory.Start.QuadPart); 1074 goto cleanup; 1075 } 1076 1077 if (AddressSpace != 0) 1078 { 1079 DPRINT1("Guessed incorrect address space: 0 -> 1\n"); 1080 1081 /* This should never happen for memory space */ 1082 ASSERT(FALSE); 1083 } 1084 } 1085 1086 case CmResourceTypeDma: 1087 case CmResourceTypeBusNumber: 1088 case CmResourceTypeDevicePrivate: 1089 case CmResourceTypeDeviceSpecific: 1090 /* Nothing to do */ 1091 break; 1092 default: 1093 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type); 1094 Status = STATUS_NOT_IMPLEMENTED; 1095 goto cleanup; 1096 } 1097 } 1098 } 1099 return STATUS_SUCCESS; 1100 1101 cleanup: 1102 /* Yes! Also delete ResourceList because ResourceList and 1103 * ResourceListTranslated should be a pair! */ 1104 ExFreePool(DeviceNode->ResourceList); 1105 DeviceNode->ResourceList = NULL; 1106 if (DeviceNode->ResourceListTranslated) 1107 { 1108 ExFreePool(DeviceNode->ResourceListTranslated); 1109 DeviceNode->ResourceList = NULL; 1110 } 1111 return Status; 1112 } 1113 1114 NTSTATUS 1115 NTAPI 1116 IopAssignDeviceResources( 1117 IN PDEVICE_NODE DeviceNode) 1118 { 1119 NTSTATUS Status; 1120 ULONG ListSize; 1121 1122 Status = IopFilterResourceRequirements(DeviceNode); 1123 if (!NT_SUCCESS(Status)) 1124 goto ByeBye; 1125 1126 if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements) 1127 { 1128 /* No resource needed for this device */ 1129 DeviceNode->ResourceList = NULL; 1130 DeviceNode->ResourceListTranslated = NULL; 1131 PiSetDevNodeState(DeviceNode, DeviceNodeResourcesAssigned); 1132 DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED; 1133 1134 return STATUS_SUCCESS; 1135 } 1136 1137 if (DeviceNode->BootResources) 1138 { 1139 ListSize = PnpDetermineResourceListSize(DeviceNode->BootResources); 1140 1141 DeviceNode->ResourceList = ExAllocatePool(PagedPool, ListSize); 1142 if (!DeviceNode->ResourceList) 1143 { 1144 Status = STATUS_NO_MEMORY; 1145 goto ByeBye; 1146 } 1147 1148 RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, ListSize); 1149 1150 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL); 1151 if (!NT_SUCCESS(Status)) 1152 { 1153 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath); 1154 ExFreePool(DeviceNode->ResourceList); 1155 DeviceNode->ResourceList = NULL; 1156 } 1157 } 1158 else 1159 { 1160 /* We'll make this from the requirements */ 1161 DeviceNode->ResourceList = NULL; 1162 } 1163 1164 /* No resources requirements */ 1165 if (!DeviceNode->ResourceRequirements) 1166 goto Finish; 1167 1168 /* Call HAL to fixup our resource requirements list */ 1169 HalAdjustResourceList(&DeviceNode->ResourceRequirements); 1170 1171 /* Add resource requirements that aren't in the list we already got */ 1172 Status = IopFixupResourceListWithRequirements(DeviceNode->ResourceRequirements, 1173 &DeviceNode->ResourceList); 1174 if (!NT_SUCCESS(Status)) 1175 { 1176 DPRINT1("Failed to fixup a resource list from supplied resources for %wZ\n", &DeviceNode->InstancePath); 1177 DeviceNode->Problem = CM_PROB_NORMAL_CONFLICT; 1178 goto ByeBye; 1179 } 1180 1181 /* IopFixupResourceListWithRequirements should NEVER give us a conflicting list */ 1182 ASSERT(IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL) != STATUS_CONFLICTING_ADDRESSES); 1183 1184 Finish: 1185 Status = IopTranslateDeviceResources(DeviceNode); 1186 if (!NT_SUCCESS(Status)) 1187 { 1188 DeviceNode->Problem = CM_PROB_TRANSLATION_FAILED; 1189 DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode->InstancePath); 1190 goto ByeBye; 1191 } 1192 1193 Status = IopUpdateResourceMapForPnPDevice(DeviceNode); 1194 if (!NT_SUCCESS(Status)) 1195 goto ByeBye; 1196 1197 Status = IopUpdateControlKeyWithResources(DeviceNode); 1198 if (!NT_SUCCESS(Status)) 1199 goto ByeBye; 1200 1201 PiSetDevNodeState(DeviceNode, DeviceNodeResourcesAssigned); 1202 1203 return STATUS_SUCCESS; 1204 1205 ByeBye: 1206 if (DeviceNode->ResourceList) 1207 { 1208 ExFreePool(DeviceNode->ResourceList); 1209 DeviceNode->ResourceList = NULL; 1210 } 1211 1212 DeviceNode->ResourceListTranslated = NULL; 1213 1214 return Status; 1215 } 1216 1217 static 1218 BOOLEAN 1219 IopCheckForResourceConflict( 1220 IN PCM_RESOURCE_LIST ResourceList1, 1221 IN PCM_RESOURCE_LIST ResourceList2, 1222 IN BOOLEAN Silent, 1223 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor) 1224 { 1225 ULONG i, ii; 1226 BOOLEAN Result = FALSE; 1227 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 1228 1229 FullDescriptor = &ResourceList1->List[0]; 1230 for (i = 0; i < ResourceList1->Count; i++) 1231 { 1232 PCM_PARTIAL_RESOURCE_LIST ResList = &FullDescriptor->PartialResourceList; 1233 FullDescriptor = CmiGetNextResourceDescriptor(FullDescriptor); 1234 1235 for (ii = 0; ii < ResList->Count; ii++) 1236 { 1237 /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific), 1238 but only one is allowed and it must be the last one in the list! */ 1239 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii]; 1240 1241 Result = IopCheckResourceDescriptor(ResDesc, 1242 ResourceList2, 1243 Silent, 1244 ConflictingDescriptor); 1245 if (Result) goto ByeBye; 1246 } 1247 } 1248 1249 ByeBye: 1250 1251 return Result; 1252 } 1253 1254 NTSTATUS NTAPI 1255 IopDetectResourceConflict( 1256 IN PCM_RESOURCE_LIST ResourceList, 1257 IN BOOLEAN Silent, 1258 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor) 1259 { 1260 OBJECT_ATTRIBUTES ObjectAttributes; 1261 UNICODE_STRING KeyName; 1262 HANDLE ResourceMapKey = NULL, ChildKey2 = NULL, ChildKey3 = NULL; 1263 ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength; 1264 PKEY_BASIC_INFORMATION KeyInformation; 1265 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; 1266 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation; 1267 ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0; 1268 NTSTATUS Status; 1269 1270 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP"); 1271 InitializeObjectAttributes(&ObjectAttributes, 1272 &KeyName, 1273 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1274 NULL, 1275 NULL); 1276 Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes); 1277 if (!NT_SUCCESS(Status)) 1278 { 1279 /* The key is missing which means we are the first device */ 1280 return STATUS_SUCCESS; 1281 } 1282 1283 while (TRUE) 1284 { 1285 Status = ZwEnumerateKey(ResourceMapKey, 1286 ChildKeyIndex1, 1287 KeyBasicInformation, 1288 NULL, 1289 0, 1290 &RequiredLength); 1291 if (Status == STATUS_NO_MORE_ENTRIES) 1292 break; 1293 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 1294 { 1295 KeyInformationLength = RequiredLength; 1296 KeyInformation = ExAllocatePoolWithTag(PagedPool, 1297 KeyInformationLength, 1298 TAG_IO); 1299 if (!KeyInformation) 1300 { 1301 Status = STATUS_INSUFFICIENT_RESOURCES; 1302 goto cleanup; 1303 } 1304 1305 Status = ZwEnumerateKey(ResourceMapKey, 1306 ChildKeyIndex1, 1307 KeyBasicInformation, 1308 KeyInformation, 1309 KeyInformationLength, 1310 &RequiredLength); 1311 } 1312 else 1313 goto cleanup; 1314 ChildKeyIndex1++; 1315 if (!NT_SUCCESS(Status)) 1316 { 1317 ExFreePoolWithTag(KeyInformation, TAG_IO); 1318 goto cleanup; 1319 } 1320 1321 KeyName.Buffer = KeyInformation->Name; 1322 KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength; 1323 InitializeObjectAttributes(&ObjectAttributes, 1324 &KeyName, 1325 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1326 ResourceMapKey, 1327 NULL); 1328 Status = ZwOpenKey(&ChildKey2, 1329 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, 1330 &ObjectAttributes); 1331 ExFreePoolWithTag(KeyInformation, TAG_IO); 1332 if (!NT_SUCCESS(Status)) 1333 goto cleanup; 1334 1335 while (TRUE) 1336 { 1337 Status = ZwEnumerateKey(ChildKey2, 1338 ChildKeyIndex2, 1339 KeyBasicInformation, 1340 NULL, 1341 0, 1342 &RequiredLength); 1343 if (Status == STATUS_NO_MORE_ENTRIES) 1344 break; 1345 else if (Status == STATUS_BUFFER_TOO_SMALL) 1346 { 1347 KeyInformationLength = RequiredLength; 1348 KeyInformation = ExAllocatePoolWithTag(PagedPool, 1349 KeyInformationLength, 1350 TAG_IO); 1351 if (!KeyInformation) 1352 { 1353 Status = STATUS_INSUFFICIENT_RESOURCES; 1354 goto cleanup; 1355 } 1356 1357 Status = ZwEnumerateKey(ChildKey2, 1358 ChildKeyIndex2, 1359 KeyBasicInformation, 1360 KeyInformation, 1361 KeyInformationLength, 1362 &RequiredLength); 1363 } 1364 else 1365 goto cleanup; 1366 ChildKeyIndex2++; 1367 if (!NT_SUCCESS(Status)) 1368 { 1369 ExFreePoolWithTag(KeyInformation, TAG_IO); 1370 goto cleanup; 1371 } 1372 1373 KeyName.Buffer = KeyInformation->Name; 1374 KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength; 1375 InitializeObjectAttributes(&ObjectAttributes, 1376 &KeyName, 1377 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1378 ChildKey2, 1379 NULL); 1380 Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes); 1381 ExFreePoolWithTag(KeyInformation, TAG_IO); 1382 if (!NT_SUCCESS(Status)) 1383 goto cleanup; 1384 1385 while (TRUE) 1386 { 1387 Status = ZwEnumerateValueKey(ChildKey3, 1388 ChildKeyIndex3, 1389 KeyValuePartialInformation, 1390 NULL, 1391 0, 1392 &RequiredLength); 1393 if (Status == STATUS_NO_MORE_ENTRIES) 1394 break; 1395 else if (Status == STATUS_BUFFER_TOO_SMALL) 1396 { 1397 KeyValueInformationLength = RequiredLength; 1398 KeyValueInformation = ExAllocatePoolWithTag(PagedPool, 1399 KeyValueInformationLength, 1400 TAG_IO); 1401 if (!KeyValueInformation) 1402 { 1403 Status = STATUS_INSUFFICIENT_RESOURCES; 1404 goto cleanup; 1405 } 1406 1407 Status = ZwEnumerateValueKey(ChildKey3, 1408 ChildKeyIndex3, 1409 KeyValuePartialInformation, 1410 KeyValueInformation, 1411 KeyValueInformationLength, 1412 &RequiredLength); 1413 } 1414 else 1415 goto cleanup; 1416 if (!NT_SUCCESS(Status)) 1417 { 1418 ExFreePoolWithTag(KeyValueInformation, TAG_IO); 1419 goto cleanup; 1420 } 1421 1422 Status = ZwEnumerateValueKey(ChildKey3, 1423 ChildKeyIndex3, 1424 KeyValueBasicInformation, 1425 NULL, 1426 0, 1427 &RequiredLength); 1428 if (Status == STATUS_BUFFER_TOO_SMALL) 1429 { 1430 KeyNameInformationLength = RequiredLength; 1431 KeyNameInformation = ExAllocatePoolWithTag(PagedPool, 1432 KeyNameInformationLength + sizeof(WCHAR), 1433 TAG_IO); 1434 if (!KeyNameInformation) 1435 { 1436 Status = STATUS_INSUFFICIENT_RESOURCES; 1437 goto cleanup; 1438 } 1439 1440 Status = ZwEnumerateValueKey(ChildKey3, 1441 ChildKeyIndex3, 1442 KeyValueBasicInformation, 1443 KeyNameInformation, 1444 KeyNameInformationLength, 1445 &RequiredLength); 1446 } 1447 else 1448 goto cleanup; 1449 ChildKeyIndex3++; 1450 if (!NT_SUCCESS(Status)) 1451 { 1452 ExFreePoolWithTag(KeyNameInformation, TAG_IO); 1453 goto cleanup; 1454 } 1455 1456 KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL; 1457 1458 /* Skip translated entries */ 1459 if (wcsstr(KeyNameInformation->Name, L".Translated")) 1460 { 1461 ExFreePoolWithTag(KeyNameInformation, TAG_IO); 1462 ExFreePoolWithTag(KeyValueInformation, TAG_IO); 1463 continue; 1464 } 1465 1466 ExFreePoolWithTag(KeyNameInformation, TAG_IO); 1467 1468 if (IopCheckForResourceConflict(ResourceList, 1469 (PCM_RESOURCE_LIST)KeyValueInformation->Data, 1470 Silent, 1471 ConflictingDescriptor)) 1472 { 1473 ExFreePoolWithTag(KeyValueInformation, TAG_IO); 1474 Status = STATUS_CONFLICTING_ADDRESSES; 1475 goto cleanup; 1476 } 1477 1478 ExFreePoolWithTag(KeyValueInformation, TAG_IO); 1479 } 1480 } 1481 } 1482 1483 cleanup: 1484 if (ResourceMapKey != NULL) 1485 ObCloseHandle(ResourceMapKey, KernelMode); 1486 if (ChildKey2 != NULL) 1487 ObCloseHandle(ChildKey2, KernelMode); 1488 if (ChildKey3 != NULL) 1489 ObCloseHandle(ChildKey3, KernelMode); 1490 1491 if (Status == STATUS_NO_MORE_ENTRIES) 1492 Status = STATUS_SUCCESS; 1493 1494 return Status; 1495 } 1496 1497