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