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