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