1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/io/iomgr/iorsrce.c 5 * PURPOSE: Hardware resource managment 6 * 7 * PROGRAMMERS: David Welch (welch@mcmail.com) 8 * Alex Ionescu (alex@relsoft.net) 9 * Pierre Schweitzer (pierre.schweitzer@reactos.org) 10 */ 11 12 /* INCLUDES *****************************************************************/ 13 14 #include <ntoskrnl.h> 15 #include <debug.h> 16 17 /* GLOBALS *******************************************************************/ 18 19 static CONFIGURATION_INFORMATION 20 _SystemConfigurationInformation = { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE, 0, 0 }; 21 22 /* API Parameters to Pass in IopQueryBusDescription */ 23 typedef struct IO_QUERY { 24 PINTERFACE_TYPE BusType; 25 PULONG BusNumber; 26 PCONFIGURATION_TYPE ControllerType; 27 PULONG ControllerNumber; 28 PCONFIGURATION_TYPE PeripheralType; 29 PULONG PeripheralNumber; 30 PIO_QUERY_DEVICE_ROUTINE CalloutRoutine; 31 PVOID Context; 32 } IO_QUERY, *PIO_QUERY; 33 34 PWSTR ArcTypes[42] = { 35 L"System", 36 L"CentralProcessor", 37 L"FloatingPointProcessor", 38 L"PrimaryICache", 39 L"PrimaryDCache", 40 L"SecondaryICache", 41 L"SecondaryDCache", 42 L"SecondaryCache", 43 L"EisaAdapter", 44 L"TcAdapter", 45 L"ScsiAdapter", 46 L"DtiAdapter", 47 L"MultifunctionAdapter", 48 L"DiskController", 49 L"TapeController", 50 L"CdRomController", 51 L"WormController", 52 L"SerialController", 53 L"NetworkController", 54 L"DisplayController", 55 L"ParallelController", 56 L"PointerController", 57 L"KeyboardController", 58 L"AudioController", 59 L"OtherController", 60 L"DiskPeripheral", 61 L"FloppyDiskPeripheral", 62 L"TapePeripheral", 63 L"ModemPeripheral", 64 L"MonitorPeripheral", 65 L"PrinterPeripheral", 66 L"PointerPeripheral", 67 L"KeyboardPeripheral", 68 L"TerminalPeripheral", 69 L"OtherPeripheral", 70 L"LinePeripheral", 71 L"NetworkPeripheral", 72 L"SystemMemory", 73 L"DockingInformation", 74 L"RealModeIrqRoutingTable", 75 L"RealModePCIEnumeration", 76 L"Undefined" 77 }; 78 79 /* PRIVATE FUNCTIONS **********************************************************/ 80 81 /* 82 * IopQueryDeviceDescription 83 * 84 * FUNCTION: 85 * Reads and returns Hardware information from the appropriate hardware 86 * registry key. Helper sub of IopQueryBusDescription. 87 * 88 * ARGUMENTS: 89 * Query - What the parent function wants. 90 * RootKey - Which key to look in 91 * RootKeyHandle - Handle to the key 92 * Bus - Bus Number. 93 * BusInformation - The Configuration Information Sent 94 * 95 * RETURNS: 96 * Status 97 */ 98 99 NTSTATUS NTAPI 100 IopQueryDeviceDescription( 101 PIO_QUERY Query, 102 UNICODE_STRING RootKey, 103 HANDLE RootKeyHandle, 104 ULONG Bus, 105 PKEY_VALUE_FULL_INFORMATION *BusInformation) 106 { 107 NTSTATUS Status = STATUS_SUCCESS; 108 109 /* Controller Stuff */ 110 UNICODE_STRING ControllerString; 111 UNICODE_STRING ControllerRootRegName = RootKey; 112 UNICODE_STRING ControllerRegName; 113 HANDLE ControllerKeyHandle; 114 PKEY_FULL_INFORMATION ControllerFullInformation = NULL; 115 PKEY_VALUE_FULL_INFORMATION ControllerInformation[3] = {NULL, NULL, NULL}; 116 ULONG ControllerNumber; 117 ULONG ControllerLoop; 118 ULONG MaximumControllerNumber; 119 120 /* Peripheral Stuff */ 121 UNICODE_STRING PeripheralString; 122 HANDLE PeripheralKeyHandle; 123 PKEY_FULL_INFORMATION PeripheralFullInformation; 124 PKEY_VALUE_FULL_INFORMATION PeripheralInformation[3] = {NULL, NULL, NULL}; 125 ULONG PeripheralNumber; 126 ULONG PeripheralLoop; 127 ULONG MaximumPeripheralNumber; 128 129 /* Global Registry Stuff */ 130 OBJECT_ATTRIBUTES ObjectAttributes; 131 ULONG LenFullInformation; 132 ULONG LenKeyFullInformation; 133 UNICODE_STRING TempString; 134 WCHAR TempBuffer[14]; 135 PWSTR Strings[3] = { 136 L"Identifier", 137 L"Configuration Data", 138 L"Component Information" 139 }; 140 141 /* Temporary String */ 142 TempString.MaximumLength = sizeof(TempBuffer); 143 TempString.Length = 0; 144 TempString.Buffer = TempBuffer; 145 146 /* Add Controller Name to String */ 147 RtlAppendUnicodeToString(&ControllerRootRegName, L"\\"); 148 RtlAppendUnicodeToString(&ControllerRootRegName, ArcTypes[*Query->ControllerType]); 149 150 /* Set the Controller Number if specified */ 151 if (Query->ControllerNumber && *(Query->ControllerNumber)) 152 { 153 ControllerNumber = *Query->ControllerNumber; 154 MaximumControllerNumber = ControllerNumber + 1; 155 } else { 156 /* Find out how many Controller Numbers there are */ 157 InitializeObjectAttributes( 158 &ObjectAttributes, 159 &ControllerRootRegName, 160 OBJ_CASE_INSENSITIVE, 161 NULL, 162 NULL); 163 164 Status = ZwOpenKey(&ControllerKeyHandle, KEY_READ, &ObjectAttributes); 165 if (NT_SUCCESS(Status)) 166 { 167 /* How much buffer space */ 168 ZwQueryKey(ControllerKeyHandle, KeyFullInformation, NULL, 0, &LenFullInformation); 169 170 /* Allocate it */ 171 ControllerFullInformation = ExAllocatePoolWithTag(PagedPool, LenFullInformation, TAG_IO_RESOURCE); 172 173 /* Get the Information */ 174 Status = ZwQueryKey(ControllerKeyHandle, KeyFullInformation, ControllerFullInformation, LenFullInformation, &LenFullInformation); 175 ZwClose(ControllerKeyHandle); 176 ControllerKeyHandle = NULL; 177 } 178 179 /* No controller was found, go back to function. */ 180 if (!NT_SUCCESS(Status)) 181 { 182 if (ControllerFullInformation != NULL) 183 ExFreePoolWithTag(ControllerFullInformation, TAG_IO_RESOURCE); 184 return Status; 185 } 186 187 /* Find out Controller Numbers */ 188 ControllerNumber = 0; 189 MaximumControllerNumber = ControllerFullInformation->SubKeys; 190 191 /* Free Memory */ 192 ExFreePoolWithTag(ControllerFullInformation, TAG_IO_RESOURCE); 193 ControllerFullInformation = NULL; 194 } 195 196 /* Save String */ 197 ControllerRegName = ControllerRootRegName; 198 199 /* Loop through controllers */ 200 for (; ControllerNumber < MaximumControllerNumber; ControllerNumber++) 201 { 202 /* Load String */ 203 ControllerRootRegName = ControllerRegName; 204 205 /* Controller Number to Registry String */ 206 Status = RtlIntegerToUnicodeString(ControllerNumber, 10, &TempString); 207 208 /* Create String */ 209 Status |= RtlAppendUnicodeToString(&ControllerRootRegName, L"\\"); 210 Status |= RtlAppendUnicodeStringToString(&ControllerRootRegName, &TempString); 211 212 /* Something messed up */ 213 if (!NT_SUCCESS(Status)) break; 214 215 /* Open the Registry Key */ 216 InitializeObjectAttributes( 217 &ObjectAttributes, 218 &ControllerRootRegName, 219 OBJ_CASE_INSENSITIVE, 220 NULL, 221 NULL); 222 223 Status = ZwOpenKey(&ControllerKeyHandle, KEY_READ, &ObjectAttributes); 224 225 /* Read the Configuration Data... */ 226 if (NT_SUCCESS(Status)) 227 { 228 for (ControllerLoop = 0; ControllerLoop < 3; ControllerLoop++) 229 { 230 /* Identifier String First */ 231 RtlInitUnicodeString(&ControllerString, Strings[ControllerLoop]); 232 233 /* How much buffer space */ 234 Status = ZwQueryValueKey(ControllerKeyHandle, &ControllerString, KeyValueFullInformation, NULL, 0, &LenKeyFullInformation); 235 236 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL && Status != STATUS_BUFFER_OVERFLOW) 237 continue; 238 239 /* Allocate it */ 240 ControllerInformation[ControllerLoop] = ExAllocatePoolWithTag(PagedPool, LenKeyFullInformation, TAG_IO_RESOURCE); 241 242 /* Get the Information */ 243 Status = ZwQueryValueKey(ControllerKeyHandle, &ControllerString, KeyValueFullInformation, ControllerInformation[ControllerLoop], LenKeyFullInformation, &LenKeyFullInformation); 244 } 245 246 /* Clean Up */ 247 ZwClose(ControllerKeyHandle); 248 ControllerKeyHandle = NULL; 249 } 250 251 /* Something messed up */ 252 if (!NT_SUCCESS(Status)) 253 goto EndLoop; 254 255 /* We now have Bus *AND* Controller Information.. is it enough? */ 256 if (!Query->PeripheralType || !(*Query->PeripheralType)) 257 { 258 Status = Query->CalloutRoutine( 259 Query->Context, 260 &ControllerRootRegName, 261 *Query->BusType, 262 Bus, 263 BusInformation, 264 *Query->ControllerType, 265 ControllerNumber, 266 ControllerInformation, 267 0, 268 0, 269 NULL); 270 goto EndLoop; 271 } 272 273 /* Not enough...caller also wants peripheral name */ 274 Status = RtlAppendUnicodeToString(&ControllerRootRegName, L"\\"); 275 Status |= RtlAppendUnicodeToString(&ControllerRootRegName, ArcTypes[*Query->PeripheralType]); 276 277 /* Something messed up */ 278 if (!NT_SUCCESS(Status)) goto EndLoop; 279 280 /* Set the Peripheral Number if specified */ 281 if (Query->PeripheralNumber && *Query->PeripheralNumber) 282 { 283 PeripheralNumber = *Query->PeripheralNumber; 284 MaximumPeripheralNumber = PeripheralNumber + 1; 285 } else { 286 /* Find out how many Peripheral Numbers there are */ 287 InitializeObjectAttributes( 288 &ObjectAttributes, 289 &ControllerRootRegName, 290 OBJ_CASE_INSENSITIVE, 291 NULL, 292 NULL); 293 294 Status = ZwOpenKey(&PeripheralKeyHandle, KEY_READ, &ObjectAttributes); 295 296 if (NT_SUCCESS(Status)) 297 { 298 /* How much buffer space */ 299 ZwQueryKey(PeripheralKeyHandle, KeyFullInformation, NULL, 0, &LenFullInformation); 300 301 /* Allocate it */ 302 PeripheralFullInformation = ExAllocatePoolWithTag(PagedPool, LenFullInformation, TAG_IO_RESOURCE); 303 304 /* Get the Information */ 305 Status = ZwQueryKey(PeripheralKeyHandle, KeyFullInformation, PeripheralFullInformation, LenFullInformation, &LenFullInformation); 306 ZwClose(PeripheralKeyHandle); 307 PeripheralKeyHandle = NULL; 308 } 309 310 /* No controller was found, go back to function but clean up first */ 311 if (!NT_SUCCESS(Status)) 312 { 313 Status = STATUS_SUCCESS; 314 goto EndLoop; 315 } 316 317 /* Find out Peripheral Number */ 318 PeripheralNumber = 0; 319 MaximumPeripheralNumber = PeripheralFullInformation->SubKeys; 320 321 /* Free Memory */ 322 ExFreePoolWithTag(PeripheralFullInformation, TAG_IO_RESOURCE); 323 PeripheralFullInformation = NULL; 324 } 325 326 /* Save Name */ 327 ControllerRegName = ControllerRootRegName; 328 329 /* Loop through Peripherals */ 330 for (; PeripheralNumber < MaximumPeripheralNumber; PeripheralNumber++) 331 { 332 /* Restore Name */ 333 ControllerRootRegName = ControllerRegName; 334 335 /* Peripheral Number to Registry String */ 336 Status = RtlIntegerToUnicodeString(PeripheralNumber, 10, &TempString); 337 338 /* Create String */ 339 Status |= RtlAppendUnicodeToString(&ControllerRootRegName, L"\\"); 340 Status |= RtlAppendUnicodeStringToString(&ControllerRootRegName, &TempString); 341 342 /* Something messed up */ 343 if (!NT_SUCCESS(Status)) break; 344 345 /* Open the Registry Key */ 346 InitializeObjectAttributes( 347 &ObjectAttributes, 348 &ControllerRootRegName, 349 OBJ_CASE_INSENSITIVE, 350 NULL, 351 NULL); 352 353 Status = ZwOpenKey(&PeripheralKeyHandle, KEY_READ, &ObjectAttributes); 354 355 if (NT_SUCCESS(Status)) 356 { 357 for (PeripheralLoop = 0; PeripheralLoop < 3; PeripheralLoop++) 358 { 359 /* Identifier String First */ 360 RtlInitUnicodeString(&PeripheralString, Strings[PeripheralLoop]); 361 362 /* How much buffer space */ 363 Status = ZwQueryValueKey(PeripheralKeyHandle, &PeripheralString, KeyValueFullInformation, NULL, 0, &LenKeyFullInformation); 364 365 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL && Status != STATUS_BUFFER_OVERFLOW) 366 { 367 PeripheralInformation[PeripheralLoop] = NULL; 368 continue; 369 } 370 371 /* Allocate it */ 372 PeripheralInformation[PeripheralLoop] = ExAllocatePoolWithTag(PagedPool, LenKeyFullInformation, TAG_IO_RESOURCE); 373 374 /* Get the Information */ 375 Status = ZwQueryValueKey(PeripheralKeyHandle, &PeripheralString, KeyValueFullInformation, PeripheralInformation[PeripheralLoop], LenKeyFullInformation, &LenKeyFullInformation); 376 } 377 378 /* Clean Up */ 379 ZwClose(PeripheralKeyHandle); 380 PeripheralKeyHandle = NULL; 381 382 /* We now have everything the caller could possibly want */ 383 if (NT_SUCCESS(Status)) 384 { 385 Status = Query->CalloutRoutine( 386 Query->Context, 387 &ControllerRootRegName, 388 *Query->BusType, 389 Bus, 390 BusInformation, 391 *Query->ControllerType, 392 ControllerNumber, 393 ControllerInformation, 394 *Query->PeripheralType, 395 PeripheralNumber, 396 PeripheralInformation); 397 } 398 399 /* Free the allocated memory */ 400 for (PeripheralLoop = 0; PeripheralLoop < 3; PeripheralLoop++) 401 { 402 if (PeripheralInformation[PeripheralLoop]) 403 { 404 ExFreePoolWithTag(PeripheralInformation[PeripheralLoop], TAG_IO_RESOURCE); 405 PeripheralInformation[PeripheralLoop] = NULL; 406 } 407 } 408 409 /* Something Messed up */ 410 if (!NT_SUCCESS(Status)) break; 411 } 412 } 413 414 EndLoop: 415 /* Free the allocated memory */ 416 for (ControllerLoop = 0; ControllerLoop < 3; ControllerLoop++) 417 { 418 if (ControllerInformation[ControllerLoop]) 419 { 420 ExFreePoolWithTag(ControllerInformation[ControllerLoop], TAG_IO_RESOURCE); 421 ControllerInformation[ControllerLoop] = NULL; 422 } 423 } 424 425 /* Something Messed up */ 426 if (!NT_SUCCESS(Status)) break; 427 } 428 429 return Status; 430 } 431 432 /* 433 * IopQueryBusDescription 434 * 435 * FUNCTION: 436 * Reads and returns Hardware information from the appropriate hardware 437 * registry key. Helper sub of IoQueryDeviceDescription. Has two modes 438 * of operation, either looking for Root Bus Types or for sub-Bus 439 * information. 440 * 441 * ARGUMENTS: 442 * Query - What the parent function wants. 443 * RootKey - Which key to look in 444 * RootKeyHandle - Handle to the key 445 * Bus - Bus Number. 446 * KeyIsRoot - Whether we are looking for Root Bus Types or 447 * information under them. 448 * 449 * RETURNS: 450 * Status 451 */ 452 453 NTSTATUS NTAPI 454 IopQueryBusDescription( 455 PIO_QUERY Query, 456 UNICODE_STRING RootKey, 457 HANDLE RootKeyHandle, 458 PULONG Bus, 459 BOOLEAN KeyIsRoot) 460 { 461 NTSTATUS Status; 462 ULONG BusLoop; 463 UNICODE_STRING SubRootRegName; 464 UNICODE_STRING BusString; 465 UNICODE_STRING SubBusString; 466 ULONG LenBasicInformation = 0; 467 ULONG LenFullInformation; 468 ULONG LenKeyFullInformation; 469 ULONG LenKey; 470 HANDLE SubRootKeyHandle; 471 PKEY_FULL_INFORMATION FullInformation; 472 PKEY_BASIC_INFORMATION BasicInformation = NULL; 473 OBJECT_ATTRIBUTES ObjectAttributes; 474 PKEY_VALUE_FULL_INFORMATION BusInformation[3] = {NULL, NULL, NULL}; 475 476 /* How much buffer space */ 477 Status = ZwQueryKey(RootKeyHandle, KeyFullInformation, NULL, 0, &LenFullInformation); 478 479 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL && Status != STATUS_BUFFER_OVERFLOW) 480 return Status; 481 482 /* Allocate it */ 483 FullInformation = ExAllocatePoolWithTag(PagedPool, LenFullInformation, TAG_IO_RESOURCE); 484 485 if (!FullInformation) 486 return STATUS_NO_MEMORY; 487 488 /* Get the Information */ 489 Status = ZwQueryKey(RootKeyHandle, KeyFullInformation, FullInformation, LenFullInformation, &LenFullInformation); 490 491 /* Everything was fine */ 492 if (NT_SUCCESS(Status)) 493 { 494 /* Buffer needed for all the keys under this one */ 495 LenBasicInformation = FullInformation->MaxNameLen + sizeof(KEY_BASIC_INFORMATION); 496 497 /* Allocate it */ 498 BasicInformation = ExAllocatePoolWithTag(PagedPool, LenBasicInformation, TAG_IO_RESOURCE); 499 } 500 501 /* Deallocate the old Buffer */ 502 ExFreePoolWithTag(FullInformation, TAG_IO_RESOURCE); 503 504 /* Try to find a Bus */ 505 for (BusLoop = 0; NT_SUCCESS(Status); BusLoop++) 506 { 507 /* Bus parameter was passed and number was matched */ 508 if ((Query->BusNumber) && (*(Query->BusNumber)) == *Bus) break; 509 510 /* Enumerate the Key */ 511 Status = ZwEnumerateKey( 512 RootKeyHandle, 513 BusLoop, 514 KeyBasicInformation, 515 BasicInformation, 516 LenBasicInformation, 517 &LenKey); 518 519 /* Everything enumerated */ 520 if (!NT_SUCCESS(Status)) break; 521 522 /* What Bus are we going to go down? (only check if this is a Root Key) */ 523 if (KeyIsRoot) 524 { 525 if (wcsncmp(BasicInformation->Name, L"MultifunctionAdapter", BasicInformation->NameLength / 2) && 526 wcsncmp(BasicInformation->Name, L"EisaAdapter", BasicInformation->NameLength / 2) && 527 wcsncmp(BasicInformation->Name, L"TcAdapter", BasicInformation->NameLength / 2)) 528 { 529 /* Nothing found, check next */ 530 continue; 531 } 532 } 533 534 /* Enumerate the Bus. */ 535 BusString.Buffer = BasicInformation->Name; 536 BusString.Length = (USHORT)BasicInformation->NameLength; 537 BusString.MaximumLength = (USHORT)BasicInformation->NameLength; 538 539 /* Open a handle to the Root Registry Key */ 540 InitializeObjectAttributes( 541 &ObjectAttributes, 542 &BusString, 543 OBJ_CASE_INSENSITIVE, 544 RootKeyHandle, 545 NULL); 546 547 Status = ZwOpenKey(&SubRootKeyHandle, KEY_READ, &ObjectAttributes); 548 549 /* Go on if we can't */ 550 if (!NT_SUCCESS(Status)) continue; 551 552 /* Key opened. Create the path */ 553 SubRootRegName = RootKey; 554 RtlAppendUnicodeToString(&SubRootRegName, L"\\"); 555 RtlAppendUnicodeStringToString(&SubRootRegName, &BusString); 556 557 if (!KeyIsRoot) 558 { 559 /* Parsing a SubBus-key */ 560 int SubBusLoop; 561 PWSTR Strings[3] = { 562 L"Identifier", 563 L"Configuration Data", 564 L"Component Information"}; 565 566 for (SubBusLoop = 0; SubBusLoop < 3; SubBusLoop++) 567 { 568 /* Identifier String First */ 569 RtlInitUnicodeString(&SubBusString, Strings[SubBusLoop]); 570 571 /* How much buffer space */ 572 ZwQueryValueKey(SubRootKeyHandle, &SubBusString, KeyValueFullInformation, NULL, 0, &LenKeyFullInformation); 573 574 /* Allocate it */ 575 BusInformation[SubBusLoop] = ExAllocatePoolWithTag(PagedPool, LenKeyFullInformation, TAG_IO_RESOURCE); 576 577 /* Get the Information */ 578 Status = ZwQueryValueKey(SubRootKeyHandle, &SubBusString, KeyValueFullInformation, BusInformation[SubBusLoop], LenKeyFullInformation, &LenKeyFullInformation); 579 } 580 581 if (NT_SUCCESS(Status)) 582 { 583 /* Do we have something */ 584 if (BusInformation[1] != NULL && 585 BusInformation[1]->DataLength != 0 && 586 /* Does it match what we want? */ 587 (((PCM_FULL_RESOURCE_DESCRIPTOR)((ULONG_PTR)BusInformation[1] + BusInformation[1]->DataOffset))->InterfaceType == *(Query->BusType))) 588 { 589 /* Found a bus */ 590 (*Bus)++; 591 592 /* Is it the bus we wanted */ 593 if (Query->BusNumber == NULL || *(Query->BusNumber) == *Bus) 594 { 595 /* If we don't want Controller Information, we're done... call the callback */ 596 if (Query->ControllerType == NULL) 597 { 598 Status = Query->CalloutRoutine( 599 Query->Context, 600 &SubRootRegName, 601 *(Query->BusType), 602 *Bus, 603 BusInformation, 604 0, 605 0, 606 NULL, 607 0, 608 0, 609 NULL); 610 } else { 611 /* We want Controller Info...get it */ 612 Status = IopQueryDeviceDescription(Query, SubRootRegName, RootKeyHandle, *Bus, (PKEY_VALUE_FULL_INFORMATION*)BusInformation); 613 } 614 } 615 } 616 } 617 618 /* Free the allocated memory */ 619 for (SubBusLoop = 0; SubBusLoop < 3; SubBusLoop++) 620 { 621 if (BusInformation[SubBusLoop]) 622 { 623 ExFreePoolWithTag(BusInformation[SubBusLoop], TAG_IO_RESOURCE); 624 BusInformation[SubBusLoop] = NULL; 625 } 626 } 627 628 /* Exit the Loop if we found the bus */ 629 if (Query->BusNumber != NULL && *(Query->BusNumber) == *Bus) 630 { 631 ZwClose(SubRootKeyHandle); 632 SubRootKeyHandle = NULL; 633 continue; 634 } 635 } 636 637 /* Enumerate the buses below us recursively if we haven't found the bus yet */ 638 Status = IopQueryBusDescription(Query, SubRootRegName, SubRootKeyHandle, Bus, !KeyIsRoot); 639 640 /* Everything enumerated */ 641 if (Status == STATUS_NO_MORE_ENTRIES) Status = STATUS_SUCCESS; 642 643 ZwClose(SubRootKeyHandle); 644 SubRootKeyHandle = NULL; 645 } 646 647 /* Free the last remaining Allocated Memory */ 648 if (BasicInformation) 649 ExFreePoolWithTag(BasicInformation, TAG_IO_RESOURCE); 650 651 return Status; 652 } 653 654 NTSTATUS 655 NTAPI 656 IopFetchConfigurationInformation(OUT PWSTR * SymbolicLinkList, 657 IN GUID Guid, 658 IN ULONG ExpectedInterfaces, 659 IN PULONG Interfaces) 660 { 661 NTSTATUS Status; 662 ULONG IntInterfaces = 0; 663 PWSTR IntSymbolicLinkList; 664 665 /* Get the associated enabled interfaces with the given GUID */ 666 Status = IoGetDeviceInterfaces(&Guid, NULL, 0, SymbolicLinkList); 667 if (!NT_SUCCESS(Status)) 668 { 669 /* Zero output and leave */ 670 if (SymbolicLinkList != 0) 671 { 672 *SymbolicLinkList = 0; 673 } 674 675 return STATUS_UNSUCCESSFUL; 676 } 677 678 IntSymbolicLinkList = *SymbolicLinkList; 679 680 /* Count the number of enabled interfaces by counting the number of symbolic links */ 681 while (*IntSymbolicLinkList != UNICODE_NULL) 682 { 683 IntInterfaces++; 684 IntSymbolicLinkList += wcslen(IntSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR)); 685 } 686 687 /* Matching result will define the result */ 688 Status = (IntInterfaces >= ExpectedInterfaces) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; 689 /* Finally, give back to the caller the number of found interfaces */ 690 *Interfaces = IntInterfaces; 691 692 return Status; 693 } 694 695 VOID 696 NTAPI 697 IopStoreSystemPartitionInformation(IN PUNICODE_STRING NtSystemPartitionDeviceName, 698 IN PUNICODE_STRING OsLoaderPathName) 699 { 700 NTSTATUS Status; 701 UNICODE_STRING LinkTarget, KeyName; 702 OBJECT_ATTRIBUTES ObjectAttributes; 703 HANDLE LinkHandle, RegistryHandle, KeyHandle; 704 WCHAR LinkTargetBuffer[256]; 705 UNICODE_STRING CmRegistryMachineSystemName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM"); 706 707 ASSERT(NtSystemPartitionDeviceName->MaximumLength >= NtSystemPartitionDeviceName->Length + sizeof(WCHAR)); 708 ASSERT(NtSystemPartitionDeviceName->Buffer[NtSystemPartitionDeviceName->Length / sizeof(WCHAR)] == UNICODE_NULL); 709 ASSERT(OsLoaderPathName->MaximumLength >= OsLoaderPathName->Length + sizeof(WCHAR)); 710 ASSERT(OsLoaderPathName->Buffer[OsLoaderPathName->Length / sizeof(WCHAR)] == UNICODE_NULL); 711 712 /* First define needed stuff to open NtSystemPartitionDeviceName symbolic link */ 713 InitializeObjectAttributes(&ObjectAttributes, 714 NtSystemPartitionDeviceName, 715 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 716 NULL, 717 NULL); 718 719 /* Open NtSystemPartitionDeviceName symbolic link */ 720 Status = ZwOpenSymbolicLinkObject(&LinkHandle, 721 SYMBOLIC_LINK_QUERY, 722 &ObjectAttributes); 723 if (!NT_SUCCESS(Status)) 724 { 725 DPRINT("Failed to open symlink %wZ, Status=%lx\n", NtSystemPartitionDeviceName, Status); 726 return; 727 } 728 729 /* Prepare the string that will receive where symbolic link points to */ 730 LinkTarget.Length = 0; 731 /* We will zero the end of the string after having received it */ 732 LinkTarget.MaximumLength = sizeof(LinkTargetBuffer) - sizeof(UNICODE_NULL); 733 LinkTarget.Buffer = LinkTargetBuffer; 734 735 /* Query target */ 736 Status = ZwQuerySymbolicLinkObject(LinkHandle, 737 &LinkTarget, 738 NULL); 739 740 /* We are done with symbolic link */ 741 ObCloseHandle(LinkHandle, KernelMode); 742 743 if (!NT_SUCCESS(Status)) 744 { 745 DPRINT("Failed querying symlink %wZ, Status=%lx\n", NtSystemPartitionDeviceName, Status); 746 return; 747 } 748 749 /* As promised, we zero the end */ 750 LinkTarget.Buffer[LinkTarget.Length / sizeof(WCHAR)] = UNICODE_NULL; 751 752 /* Open registry to save data (HKLM\SYSTEM) */ 753 Status = IopOpenRegistryKeyEx(&RegistryHandle, 754 NULL, 755 &CmRegistryMachineSystemName, 756 KEY_ALL_ACCESS); 757 if (!NT_SUCCESS(Status)) 758 { 759 DPRINT("Failed to open HKLM\\SYSTEM, Status=%lx\n", Status); 760 return; 761 } 762 763 /* Open or create the Setup subkey where we'll store in */ 764 RtlInitUnicodeString(&KeyName, L"Setup"); 765 766 Status = IopCreateRegistryKeyEx(&KeyHandle, 767 RegistryHandle, 768 &KeyName, 769 KEY_ALL_ACCESS, 770 REG_OPTION_NON_VOLATILE, 771 NULL); 772 773 /* We're done with HKLM\SYSTEM */ 774 ObCloseHandle(RegistryHandle, KernelMode); 775 776 if (!NT_SUCCESS(Status)) 777 { 778 DPRINT("Failed opening/creating Setup key, Status=%lx\n", Status); 779 return; 780 } 781 782 /* Prepare first data writing... */ 783 RtlInitUnicodeString(&KeyName, L"SystemPartition"); 784 785 /* Write SystemPartition value which is the target of the symbolic link */ 786 Status = ZwSetValueKey(KeyHandle, 787 &KeyName, 788 0, 789 REG_SZ, 790 LinkTarget.Buffer, 791 LinkTarget.Length + sizeof(WCHAR)); 792 if (!NT_SUCCESS(Status)) 793 { 794 DPRINT("Failed writing SystemPartition value, Status=%lx\n", Status); 795 } 796 797 /* Prepare for second data writing... */ 798 RtlInitUnicodeString(&KeyName, L"OsLoaderPath"); 799 800 /* Remove trailing slash if any (one slash only excepted) */ 801 if (OsLoaderPathName->Length > sizeof(WCHAR) && 802 OsLoaderPathName->Buffer[(OsLoaderPathName->Length / sizeof(WCHAR)) - 1] == OBJ_NAME_PATH_SEPARATOR) 803 { 804 OsLoaderPathName->Length -= sizeof(WCHAR); 805 OsLoaderPathName->Buffer[OsLoaderPathName->Length / sizeof(WCHAR)] = UNICODE_NULL; 806 } 807 808 /* Then, write down data */ 809 Status = ZwSetValueKey(KeyHandle, 810 &KeyName, 811 0, 812 REG_SZ, 813 OsLoaderPathName->Buffer, 814 OsLoaderPathName->Length + sizeof(UNICODE_NULL)); 815 if (!NT_SUCCESS(Status)) 816 { 817 DPRINT("Failed writing OsLoaderPath value, Status=%lx\n", Status); 818 } 819 820 /* We're finally done! */ 821 ObCloseHandle(KeyHandle, KernelMode); 822 } 823 824 /* PUBLIC FUNCTIONS ***********************************************************/ 825 826 /* 827 * @implemented 828 */ 829 PCONFIGURATION_INFORMATION NTAPI 830 IoGetConfigurationInformation(VOID) 831 { 832 return(&_SystemConfigurationInformation); 833 } 834 835 /* 836 * @halfplemented 837 */ 838 NTSTATUS NTAPI 839 IoReportResourceUsage(PUNICODE_STRING DriverClassName, 840 PDRIVER_OBJECT DriverObject, 841 PCM_RESOURCE_LIST DriverList, 842 ULONG DriverListSize, 843 PDEVICE_OBJECT DeviceObject, 844 PCM_RESOURCE_LIST DeviceList, 845 ULONG DeviceListSize, 846 BOOLEAN OverrideConflict, 847 PBOOLEAN ConflictDetected) 848 /* 849 * FUNCTION: Reports hardware resources in the 850 * \Registry\Machine\Hardware\ResourceMap tree, so that a subsequently 851 * loaded driver cannot attempt to use the same resources. 852 * ARGUMENTS: 853 * DriverClassName - The class of driver under which the resource 854 * information should be stored. 855 * DriverObject - The driver object that was input to the 856 * DriverEntry. 857 * DriverList - Resources that claimed for the driver rather than 858 * per-device. 859 * DriverListSize - Size in bytes of the DriverList. 860 * DeviceObject - The device object for which resources should be 861 * claimed. 862 * DeviceList - List of resources which should be claimed for the 863 * device. 864 * DeviceListSize - Size of the per-device resource list in bytes. 865 * OverrideConflict - True if the resources should be cliamed 866 * even if a conflict is found. 867 * ConflictDetected - Points to a variable that receives TRUE if 868 * a conflict is detected with another driver. 869 */ 870 { 871 NTSTATUS Status; 872 PCM_RESOURCE_LIST ResourceList; 873 874 DPRINT1("IoReportResourceUsage is halfplemented!\n"); 875 876 if (!DriverList && !DeviceList) 877 return STATUS_INVALID_PARAMETER; 878 879 if (DeviceList) 880 ResourceList = DeviceList; 881 else 882 ResourceList = DriverList; 883 884 Status = IopDetectResourceConflict(ResourceList, FALSE, NULL); 885 if (Status == STATUS_CONFLICTING_ADDRESSES) 886 { 887 *ConflictDetected = TRUE; 888 889 if (!OverrideConflict) 890 { 891 DPRINT1("Denying an attempt to claim resources currently in use by another device!\n"); 892 return STATUS_CONFLICTING_ADDRESSES; 893 } 894 else 895 { 896 DPRINT1("Proceeding with conflicting resources\n"); 897 } 898 } 899 else if (!NT_SUCCESS(Status)) 900 { 901 return Status; 902 } 903 904 /* TODO: Claim resources in registry */ 905 906 *ConflictDetected = FALSE; 907 908 return STATUS_SUCCESS; 909 } 910 911 NTSTATUS 912 NTAPI 913 IopLegacyResourceAllocation(IN ARBITER_REQUEST_SOURCE AllocationType, 914 IN PDRIVER_OBJECT DriverObject, 915 IN PDEVICE_OBJECT DeviceObject OPTIONAL, 916 IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements, 917 IN OUT PCM_RESOURCE_LIST *AllocatedResources) 918 { 919 NTSTATUS Status; 920 921 DPRINT1("IopLegacyResourceAllocation is halfplemented!\n"); 922 923 if (!ResourceRequirements) 924 { 925 /* We can get there by calling IoAssignResources() with RequestedResources = NULL. 926 * TODO: not sure what we should do, but we shouldn't crash. 927 * */ 928 UNIMPLEMENTED; 929 return STATUS_NOT_IMPLEMENTED; 930 } 931 932 Status = IopFixupResourceListWithRequirements(ResourceRequirements, 933 AllocatedResources); 934 if (!NT_SUCCESS(Status)) 935 { 936 if (Status == STATUS_CONFLICTING_ADDRESSES) 937 { 938 DPRINT1("Denying an attempt to claim resources currently in use by another device!\n"); 939 } 940 941 return Status; 942 } 943 944 /* TODO: Claim resources in registry */ 945 return STATUS_SUCCESS; 946 } 947 948 /* 949 * @implemented 950 */ 951 NTSTATUS 952 NTAPI 953 IoAssignResources(IN PUNICODE_STRING RegistryPath, 954 IN PUNICODE_STRING DriverClassName, 955 IN PDRIVER_OBJECT DriverObject, 956 IN PDEVICE_OBJECT DeviceObject, 957 IN PIO_RESOURCE_REQUIREMENTS_LIST RequestedResources, 958 IN OUT PCM_RESOURCE_LIST* AllocatedResources) 959 { 960 PDEVICE_NODE DeviceNode; 961 962 /* Do we have a DO? */ 963 if (DeviceObject) 964 { 965 /* Get its device node */ 966 DeviceNode = IopGetDeviceNode(DeviceObject); 967 if ((DeviceNode) && !(DeviceNode->Flags & DNF_LEGACY_RESOURCE_DEVICENODE)) 968 { 969 /* New drivers should not call this API */ 970 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 971 0, 972 0, 973 (ULONG_PTR)DeviceObject, 974 (ULONG_PTR)DriverObject); 975 } 976 } 977 978 /* Did the driver supply resources? */ 979 if (RequestedResources) 980 { 981 /* Make sure there's actually something useful in them */ 982 if (!(RequestedResources->AlternativeLists) || !(RequestedResources->List[0].Count)) 983 { 984 /* Empty resources are no resources */ 985 RequestedResources = NULL; 986 } 987 } 988 989 /* Initialize output if given */ 990 if (AllocatedResources) *AllocatedResources = NULL; 991 992 /* Call internal helper function */ 993 return IopLegacyResourceAllocation(ArbiterRequestLegacyAssigned, 994 DriverObject, 995 DeviceObject, 996 RequestedResources, 997 AllocatedResources); 998 } 999 1000 /* 1001 * FUNCTION: 1002 * Reads and returns Hardware information from the appropriate hardware registry key. 1003 * 1004 * ARGUMENTS: 1005 * BusType - MCA, ISA, EISA...specifies the Bus Type 1006 * BusNumber - Which bus of above should be queried 1007 * ControllerType - Specifices the Controller Type 1008 * ControllerNumber - Which of the controllers to query. 1009 * CalloutRoutine - Which function to call for each valid query. 1010 * Context - Value to pass to the callback. 1011 * 1012 * RETURNS: 1013 * Status 1014 * 1015 * STATUS: 1016 * @implemented 1017 */ 1018 1019 NTSTATUS NTAPI 1020 IoQueryDeviceDescription(PINTERFACE_TYPE BusType OPTIONAL, 1021 PULONG BusNumber OPTIONAL, 1022 PCONFIGURATION_TYPE ControllerType OPTIONAL, 1023 PULONG ControllerNumber OPTIONAL, 1024 PCONFIGURATION_TYPE PeripheralType OPTIONAL, 1025 PULONG PeripheralNumber OPTIONAL, 1026 PIO_QUERY_DEVICE_ROUTINE CalloutRoutine, 1027 PVOID Context) 1028 { 1029 NTSTATUS Status; 1030 ULONG BusLoopNumber = -1; /* Root Bus */ 1031 OBJECT_ATTRIBUTES ObjectAttributes; 1032 UNICODE_STRING RootRegKey; 1033 HANDLE RootRegHandle; 1034 IO_QUERY Query; 1035 1036 /* Set up the String */ 1037 RootRegKey.Length = 0; 1038 RootRegKey.MaximumLength = 2048; 1039 RootRegKey.Buffer = ExAllocatePoolWithTag(PagedPool, RootRegKey.MaximumLength, TAG_IO_RESOURCE); 1040 RtlAppendUnicodeToString(&RootRegKey, L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM"); 1041 1042 /* Open a handle to the Root Registry Key */ 1043 InitializeObjectAttributes( 1044 &ObjectAttributes, 1045 &RootRegKey, 1046 OBJ_CASE_INSENSITIVE, 1047 NULL, 1048 NULL); 1049 1050 Status = ZwOpenKey(&RootRegHandle, KEY_READ, &ObjectAttributes); 1051 1052 if (NT_SUCCESS(Status)) 1053 { 1054 /* Use a helper function to loop though this key and get the info */ 1055 Query.BusType = BusType; 1056 Query.BusNumber = BusNumber; 1057 Query.ControllerType = ControllerType; 1058 Query.ControllerNumber = ControllerNumber; 1059 Query.PeripheralType = PeripheralType; 1060 Query.PeripheralNumber = PeripheralNumber; 1061 Query.CalloutRoutine = CalloutRoutine; 1062 Query.Context = Context; 1063 Status = IopQueryBusDescription(&Query, RootRegKey, RootRegHandle, &BusLoopNumber, TRUE); 1064 1065 /* Close registry */ 1066 ZwClose(RootRegHandle); 1067 } 1068 1069 /* Free Memory */ 1070 ExFreePoolWithTag(RootRegKey.Buffer, TAG_IO_RESOURCE); 1071 1072 return Status; 1073 } 1074 1075 /* 1076 * @implemented 1077 */ 1078 NTSTATUS NTAPI 1079 IoReportHalResourceUsage(PUNICODE_STRING HalDescription, 1080 PCM_RESOURCE_LIST RawList, 1081 PCM_RESOURCE_LIST TranslatedList, 1082 ULONG ListSize) 1083 /* 1084 * FUNCTION: 1085 * Reports hardware resources of the HAL in the 1086 * \Registry\Machine\Hardware\ResourceMap tree. 1087 * ARGUMENTS: 1088 * HalDescription: Descriptive name of the HAL. 1089 * RawList: List of raw (bus specific) resources which should be 1090 * claimed for the HAL. 1091 * TranslatedList: List of translated (system wide) resources which 1092 * should be claimed for the HAL. 1093 * ListSize: Size in bytes of the raw and translated resource lists. 1094 * Both lists have the same size. 1095 * RETURNS: 1096 * Status. 1097 */ 1098 { 1099 OBJECT_ATTRIBUTES ObjectAttributes; 1100 UNICODE_STRING Name; 1101 ULONG Disposition; 1102 NTSTATUS Status; 1103 HANDLE ResourcemapKey; 1104 HANDLE HalKey; 1105 HANDLE DescriptionKey; 1106 1107 /* Open/Create 'RESOURCEMAP' key. */ 1108 RtlInitUnicodeString(&Name, 1109 L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP"); 1110 InitializeObjectAttributes(&ObjectAttributes, 1111 &Name, 1112 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 1113 0, 1114 NULL); 1115 Status = ZwCreateKey(&ResourcemapKey, 1116 KEY_ALL_ACCESS, 1117 &ObjectAttributes, 1118 0, 1119 NULL, 1120 REG_OPTION_VOLATILE, 1121 &Disposition); 1122 if (!NT_SUCCESS(Status)) 1123 return(Status); 1124 1125 /* Open/Create 'Hardware Abstraction Layer' key */ 1126 RtlInitUnicodeString(&Name, 1127 L"Hardware Abstraction Layer"); 1128 InitializeObjectAttributes(&ObjectAttributes, 1129 &Name, 1130 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 1131 ResourcemapKey, 1132 NULL); 1133 Status = ZwCreateKey(&HalKey, 1134 KEY_ALL_ACCESS, 1135 &ObjectAttributes, 1136 0, 1137 NULL, 1138 REG_OPTION_VOLATILE, 1139 &Disposition); 1140 ZwClose(ResourcemapKey); 1141 if (!NT_SUCCESS(Status)) 1142 return(Status); 1143 1144 /* Create 'HalDescription' key */ 1145 InitializeObjectAttributes(&ObjectAttributes, 1146 HalDescription, 1147 OBJ_CASE_INSENSITIVE, 1148 HalKey, 1149 NULL); 1150 Status = ZwCreateKey(&DescriptionKey, 1151 KEY_ALL_ACCESS, 1152 &ObjectAttributes, 1153 0, 1154 NULL, 1155 REG_OPTION_VOLATILE, 1156 &Disposition); 1157 ZwClose(HalKey); 1158 if (!NT_SUCCESS(Status)) 1159 return(Status); 1160 1161 /* Add '.Raw' value. */ 1162 RtlInitUnicodeString(&Name, 1163 L".Raw"); 1164 Status = ZwSetValueKey(DescriptionKey, 1165 &Name, 1166 0, 1167 REG_RESOURCE_LIST, 1168 RawList, 1169 ListSize); 1170 if (!NT_SUCCESS(Status)) 1171 { 1172 ZwClose(DescriptionKey); 1173 return(Status); 1174 } 1175 1176 /* Add '.Translated' value. */ 1177 RtlInitUnicodeString(&Name, 1178 L".Translated"); 1179 Status = ZwSetValueKey(DescriptionKey, 1180 &Name, 1181 0, 1182 REG_RESOURCE_LIST, 1183 TranslatedList, 1184 ListSize); 1185 ZwClose(DescriptionKey); 1186 1187 return(Status); 1188 } 1189 1190 /* EOF */ 1191