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