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