xref: /reactos/ntoskrnl/io/iomgr/iorsrce.c (revision 84b4a80b)
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