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