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