xref: /reactos/ntoskrnl/io/pnpmgr/pnpmap.c (revision 7d5e1591)
1 /*
2  * PROJECT:     ReactOS Kernel
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     PnP manager Firmware Mapper functions
5  * COPYRIGHT:   Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
6  *              Copyright 2008-2011 Cameron Gutman <cameron.gutman@reactos.org>
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* TYPES *********************************************************************/
16 
17 typedef struct _PNP_MAPPER_DEVICE_ID
18 {
19     PCWSTR TypeName;
20     PWSTR PnPId;
21 } PNP_MAPPER_DEVICE_ID, *PPNP_MAPPER_DEVICE_ID;
22 
23 typedef struct _PNP_DETECT_IDENTIFIER_MAP
24 {
25     PCWSTR DetectId;
26     PWSTR PnPId;
27     PPNP_MAPPER_DEVICE_ID PeripheralMap;
28     ULONG Counter;
29 } PNP_DETECT_IDENTIFIER_MAP;
30 
31 /* DATA **********************************************************************/
32 
33 static UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
34 static UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
35 static UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
36 static UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
37 static UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
38 
39 /* FIXME: Trailing \0 in structures below are hacks, should be removed.
40  * Hardware identifiers also can be mapped using "LegacyXlate" sections
41  * of driver INF files. */
42 
43 DATA_SEG("INITDATA")
44 static
45 PNP_MAPPER_DEVICE_ID KeyboardMap[] =
46 {
47     { L"XT_83KEY", L"*PNP0300\0" },
48     { L"PCAT_86KEY", L"*PNP0301\0" },
49     { L"PCXT_84KEY", L"*PNP0302\0" },
50     { L"XT_84KEY", L"*PNP0302\0" },
51     { L"101-KEY", L"*PNP0303\0" },
52     { L"OLI_83KEY", L"*PNP0304\0" },
53     { L"ATT_301", L"*PNP0304\0" },
54     { L"OLI_102KEY", L"*PNP0305\0" },
55     { L"OLI_86KEY", L"*PNP0306\0" },
56     { L"OLI_A101_102KEY", L"*PNP0309\0" },
57     { L"ATT_302", L"*PNP030a\0" },
58     { L"PCAT_ENHANCED", L"*PNP030b\0" },
59     { L"PC98_106KEY", L"*nEC1300\0" },
60     { L"PC98_LaptopKEY", L"*nEC1300\0" },
61     { L"PC98_N106KEY", L"*PNP0303\0" },
62     { NULL, NULL }
63 };
64 
65 DATA_SEG("INITDATA")
66 static
67 PNP_MAPPER_DEVICE_ID PointerMap[] =
68 {
69     { L"PS2 MOUSE", L"*PNP0F0E\0" },
70     { L"SERIAL MOUSE", L"*PNP0F0C\0" },
71     { L"MICROSOFT PS2 MOUSE", L"*PNP0F03\0" },
72     { L"LOGITECH PS2 MOUSE", L"*PNP0F12\0" },
73     { L"MICROSOFT INPORT MOUSE", L"*PNP0F02\0" },
74     { L"MICROSOFT SERIAL MOUSE", L"*PNP0F01\0" },
75     { L"MICROSOFT BALLPOINT SERIAL MOUSE", L"*PNP0F09\0" },
76     { L"LOGITECH SERIAL MOUSE", L"*PNP0F08\0" },
77     { L"MICROSOFT BUS MOUSE", L"*PNP0F00\0" },
78     { L"NEC PC-9800 BUS MOUSE", L"*nEC1F00\0" },
79     { NULL, NULL }
80 };
81 
82 DATA_SEG("INITDATA")
83 static
84 PNP_DETECT_IDENTIFIER_MAP PnPMap[] =
85 {
86     { L"SerialController", L"*PNP0501\0", NULL, 0 },
87     //{ L"KeyboardController", L"*PNP0303\0", NULL, 0 },
88     //{ L"PointerController", L"*PNP0F13\0", NULL, 0 },
89     { L"KeyboardPeripheral", NULL, KeyboardMap, 0 },
90     { L"PointerPeripheral", NULL, PointerMap, 0 },
91     { L"ParallelController", L"*PNP0400\0", NULL, 0 },
92     { L"FloppyDiskPeripheral", L"*PNP0700\0", NULL, 0 },
93     { NULL, NULL, NULL, 0 }
94 };
95 
96 /* FUNCTIONS *****************************************************************/
97 
98 static
99 CODE_SEG("INIT")
100 PWSTR
IopMapPeripheralId(_In_ PCUNICODE_STRING Value,_In_ PPNP_MAPPER_DEVICE_ID DeviceList)101 IopMapPeripheralId(
102     _In_ PCUNICODE_STRING Value,
103     _In_ PPNP_MAPPER_DEVICE_ID DeviceList)
104 {
105     ULONG i;
106     UNICODE_STRING CmpId;
107 
108     for (i = 0; DeviceList[i].TypeName; i++)
109     {
110         RtlInitUnicodeString(&CmpId, DeviceList[i].TypeName);
111 
112         if (RtlCompareUnicodeString(Value, &CmpId, FALSE) == 0)
113             break;
114     }
115 
116     return DeviceList[i].PnPId;
117 }
118 
119 static
120 CODE_SEG("INIT")
121 PWSTR
IopMapDetectedDeviceId(_In_ PUNICODE_STRING DetectId,_In_ PUNICODE_STRING Value,_Out_ PULONG DeviceIndex)122 IopMapDetectedDeviceId(
123     _In_ PUNICODE_STRING DetectId,
124     _In_ PUNICODE_STRING Value,
125     _Out_ PULONG DeviceIndex)
126 {
127     ULONG i;
128     UNICODE_STRING CmpId;
129 
130     if (!DetectId)
131         return NULL;
132 
133     for (i = 0; PnPMap[i].DetectId; i++)
134     {
135         RtlInitUnicodeString(&CmpId, PnPMap[i].DetectId);
136 
137         if (RtlCompareUnicodeString(DetectId, &CmpId, FALSE) == 0)
138         {
139             *DeviceIndex = PnPMap[i].Counter++;
140 
141             if (PnPMap[i].PeripheralMap)
142                 return IopMapPeripheralId(Value, PnPMap[i].PeripheralMap);
143             break;
144         }
145     }
146 
147     return PnPMap[i].PnPId;
148 }
149 
150 static
151 CODE_SEG("INIT")
152 NTSTATUS
IopEnumerateDetectedDevices(_In_ HANDLE hBaseKey,_In_opt_ PUNICODE_STRING RelativePath,_In_ HANDLE hRootKey,_In_ BOOLEAN EnumerateSubKeys,_In_opt_ PCM_FULL_RESOURCE_DESCRIPTOR BootResources,_In_opt_ ULONG BootResourcesLength,_In_ PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,_In_ ULONG ParentBootResourcesLength)153 IopEnumerateDetectedDevices(
154     _In_ HANDLE hBaseKey,
155     _In_opt_ PUNICODE_STRING RelativePath,
156     _In_ HANDLE hRootKey,
157     _In_ BOOLEAN EnumerateSubKeys,
158     _In_opt_ PCM_FULL_RESOURCE_DESCRIPTOR BootResources,
159     _In_opt_ ULONG BootResourcesLength,
160     _In_ PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
161     _In_ ULONG ParentBootResourcesLength)
162 {
163     HANDLE hDevicesKey = NULL;
164     ULONG KeyIndex = 0;
165     PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
166     ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
167     NTSTATUS Status;
168 
169     if (!BootResources && RelativePath)
170     {
171         Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
172 
173         if (!NT_SUCCESS(Status))
174         {
175             DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
176             goto cleanup;
177         }
178     }
179     else
180         hDevicesKey = hBaseKey;
181 
182     pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
183     if (!pDeviceInformation)
184     {
185         DPRINT("ExAllocatePool() failed\n");
186         Status = STATUS_NO_MEMORY;
187         goto cleanup;
188     }
189 
190     while (TRUE)
191     {
192         OBJECT_ATTRIBUTES ObjectAttributes;
193         HANDLE hDeviceKey = NULL;
194         HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
195         UNICODE_STRING Level2NameU;
196         WCHAR Level2Name[5];
197         PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
198         ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
199         UNICODE_STRING DeviceName, ValueName;
200         ULONG RequiredSize;
201 
202         UNICODE_STRING HardwareIdKey;
203         PWSTR pHardwareId;
204         ULONG DeviceIndex = 0;
205 
206         Status = ZwEnumerateKey(hDevicesKey,
207                                 KeyIndex,
208                                 KeyBasicInformation,
209                                 pDeviceInformation,
210                                 DeviceInfoLength,
211                                 &RequiredSize);
212 
213         if (Status == STATUS_NO_MORE_ENTRIES)
214             break;
215         else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
216         {
217             ExFreePool(pDeviceInformation);
218             DeviceInfoLength = RequiredSize;
219             pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
220 
221             if (!pDeviceInformation)
222             {
223                 DPRINT("ExAllocatePool() failed\n");
224                 Status = STATUS_NO_MEMORY;
225                 goto cleanup;
226             }
227 
228             Status = ZwEnumerateKey(hDevicesKey,
229                                     KeyIndex,
230                                     KeyBasicInformation,
231                                     pDeviceInformation,
232                                     DeviceInfoLength,
233                                     &RequiredSize);
234         }
235 
236         if (!NT_SUCCESS(Status))
237         {
238             DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
239             goto cleanup;
240         }
241         KeyIndex++;
242 
243         /* Open device key */
244         DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
245         DeviceName.Buffer = pDeviceInformation->Name;
246 
247         if (BootResources)
248         {
249             Status = IopEnumerateDetectedDevices(
250                 hDevicesKey,
251                 &DeviceName,
252                 hRootKey,
253                 TRUE,
254                 NULL,
255                 0,
256                 BootResources,
257                 BootResourcesLength);
258 
259             if (!NT_SUCCESS(Status))
260                 goto cleanup;
261 
262             continue;
263         }
264 
265         pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
266         if (!pValueInformation)
267         {
268             DPRINT("ExAllocatePool() failed\n");
269             Status = STATUS_NO_MEMORY;
270             goto cleanup;
271         }
272 
273         Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
274             KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
275 
276         if (!NT_SUCCESS(Status))
277         {
278             DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
279             goto cleanup;
280         }
281 
282         /* Read boot resources, and add then to parent ones */
283         Status = ZwQueryValueKey(hDeviceKey,
284                                  &ConfigurationDataU,
285                                  KeyValuePartialInformation,
286                                  pValueInformation,
287                                  ValueInfoLength,
288                                  &RequiredSize);
289 
290         if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
291         {
292             ExFreePool(pValueInformation);
293             ValueInfoLength = RequiredSize;
294             pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
295 
296             if (!pValueInformation)
297             {
298                 DPRINT("ExAllocatePool() failed\n");
299                 ZwDeleteKey(hLevel2Key);
300                 Status = STATUS_NO_MEMORY;
301                 goto cleanup;
302             }
303 
304             Status = ZwQueryValueKey(hDeviceKey,
305                                      &ConfigurationDataU,
306                                      KeyValuePartialInformation,
307                                      pValueInformation,
308                                      ValueInfoLength,
309                                      &RequiredSize);
310         }
311 
312         if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
313         {
314             BootResources = ParentBootResources;
315             BootResourcesLength = ParentBootResourcesLength;
316         }
317         else if (!NT_SUCCESS(Status))
318         {
319             DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
320             goto nextdevice;
321         }
322         else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
323         {
324             DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
325             goto nextdevice;
326         }
327         else
328         {
329             static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
330 
331             /* Concatenate current resources and parent ones */
332             if (ParentBootResourcesLength == 0)
333                 BootResourcesLength = pValueInformation->DataLength;
334             else
335                 BootResourcesLength = ParentBootResourcesLength
336                     + pValueInformation->DataLength
337                     - Header;
338 
339             BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
340             if (!BootResources)
341             {
342                 DPRINT("ExAllocatePool() failed\n");
343                 goto nextdevice;
344             }
345 
346             if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
347             {
348                 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
349             }
350             else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
351             {
352                 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
353                 RtlCopyMemory(
354                     (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
355                     (PVOID)((ULONG_PTR)ParentBootResources + Header),
356                     ParentBootResourcesLength - Header);
357                 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
358             }
359             else
360             {
361                 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
362                 RtlCopyMemory(
363                     (PVOID)((ULONG_PTR)BootResources + Header),
364                     (PVOID)((ULONG_PTR)ParentBootResources + Header),
365                     ParentBootResourcesLength - Header);
366                 RtlCopyMemory(
367                     (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
368                     pValueInformation->Data + Header,
369                     pValueInformation->DataLength - Header);
370                 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
371             }
372         }
373 
374         if (EnumerateSubKeys)
375         {
376             Status = IopEnumerateDetectedDevices(
377                 hDeviceKey,
378                 RelativePath,
379                 hRootKey,
380                 TRUE,
381                 BootResources,
382                 BootResourcesLength,
383                 ParentBootResources,
384                 ParentBootResourcesLength);
385 
386             if (!NT_SUCCESS(Status))
387                 goto cleanup;
388         }
389 
390         /* Read identifier */
391         Status = ZwQueryValueKey(hDeviceKey,
392                                  &IdentifierU,
393                                  KeyValuePartialInformation,
394                                  pValueInformation,
395                                  ValueInfoLength,
396                                  &RequiredSize);
397 
398         if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
399         {
400             ExFreePool(pValueInformation);
401             ValueInfoLength = RequiredSize;
402             pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
403 
404             if (!pValueInformation)
405             {
406                 DPRINT("ExAllocatePool() failed\n");
407                 Status = STATUS_NO_MEMORY;
408                 goto cleanup;
409             }
410 
411             Status = ZwQueryValueKey(hDeviceKey,
412                                      &IdentifierU,
413                                      KeyValuePartialInformation,
414                                      pValueInformation,
415                                      ValueInfoLength,
416                                      &RequiredSize);
417         }
418 
419         if (!NT_SUCCESS(Status))
420         {
421             if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
422             {
423                 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
424                 goto nextdevice;
425             }
426             ValueName.Length = ValueName.MaximumLength = 0;
427         }
428         else if (pValueInformation->Type != REG_SZ)
429         {
430             DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
431             goto nextdevice;
432         }
433         else
434         {
435             /* Assign hardware id to this device */
436             ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
437             ValueName.Buffer = (PWCHAR)pValueInformation->Data;
438             if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
439                 ValueName.Length -= sizeof(WCHAR);
440         }
441 
442         pHardwareId = IopMapDetectedDeviceId(RelativePath, &ValueName, &DeviceIndex);
443         if (!pHardwareId)
444         {
445             /* Unknown key path */
446             DPRINT("Unknown key path '%wZ' value '%wZ'\n", RelativePath, &ValueName);
447             goto nextdevice;
448         }
449 
450         /* Prepare hardware id key (hardware id value without final \0) */
451         HardwareIdKey.Length = (USHORT)wcslen(pHardwareId) * sizeof(WCHAR);
452         HardwareIdKey.MaximumLength = HardwareIdKey.Length + sizeof(UNICODE_NULL) * 2;
453         HardwareIdKey.Buffer = pHardwareId;
454 
455         /* Add the detected device to Root key */
456         InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
457 
458         Status = ZwCreateKey(
459             &hLevel1Key,
460             KEY_CREATE_SUB_KEY,
461             &ObjectAttributes,
462             0,
463             NULL,
464             REG_OPTION_NON_VOLATILE,
465             NULL);
466 
467         if (!NT_SUCCESS(Status))
468         {
469             DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
470             goto nextdevice;
471         }
472 
473         swprintf(Level2Name, L"%04lu", DeviceIndex);
474         RtlInitUnicodeString(&Level2NameU, Level2Name);
475         InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
476 
477         Status = ZwCreateKey(
478             &hLevel2Key,
479             KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
480             &ObjectAttributes,
481             0,
482             NULL,
483             REG_OPTION_NON_VOLATILE,
484             NULL);
485 
486         ZwClose(hLevel1Key);
487         if (!NT_SUCCESS(Status))
488         {
489             DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
490             goto nextdevice;
491         }
492 
493         DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
494         Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, HardwareIdKey.Buffer, HardwareIdKey.MaximumLength);
495 
496         if (!NT_SUCCESS(Status))
497         {
498             DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
499             ZwDeleteKey(hLevel2Key);
500             goto nextdevice;
501         }
502 
503         /* Create 'LogConf' subkey */
504         InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
505 
506         Status = ZwCreateKey(
507             &hLogConf,
508             KEY_SET_VALUE,
509             &ObjectAttributes,
510             0,
511             NULL,
512             REG_OPTION_VOLATILE,
513             NULL);
514 
515         if (!NT_SUCCESS(Status))
516         {
517             DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
518             ZwDeleteKey(hLevel2Key);
519             goto nextdevice;
520         }
521 
522         if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
523         {
524             PUCHAR CmResourceList;
525             ULONG ListCount;
526 
527             CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
528             if (!CmResourceList)
529             {
530                 ZwClose(hLogConf);
531                 ZwDeleteKey(hLevel2Key);
532                 goto nextdevice;
533             }
534 
535             /* Add the list count (1st member of CM_RESOURCE_LIST) */
536             ListCount = 1;
537             RtlCopyMemory(CmResourceList,
538                           &ListCount,
539                           sizeof(ULONG));
540 
541             /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
542             RtlCopyMemory(CmResourceList + sizeof(ULONG),
543                           BootResources,
544                           BootResourcesLength);
545 
546             /* Save boot resources to 'LogConf\BootConfig' */
547             Status = ZwSetValueKey(hLogConf,
548                                    &BootConfigU,
549                                    0,
550                                    REG_RESOURCE_LIST,
551                                    CmResourceList,
552                                    BootResourcesLength + sizeof(ULONG));
553 
554             ExFreePool(CmResourceList);
555 
556             if (!NT_SUCCESS(Status))
557             {
558                 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
559                 ZwClose(hLogConf);
560                 ZwDeleteKey(hLevel2Key);
561                 goto nextdevice;
562             }
563         }
564         ZwClose(hLogConf);
565 
566 nextdevice:
567         if (BootResources && BootResources != ParentBootResources)
568         {
569             ExFreePool(BootResources);
570             BootResources = NULL;
571         }
572         if (hLevel2Key)
573         {
574             ZwClose(hLevel2Key);
575             hLevel2Key = NULL;
576         }
577         if (hDeviceKey)
578         {
579             ZwClose(hDeviceKey);
580             hDeviceKey = NULL;
581         }
582         if (pValueInformation)
583             ExFreePool(pValueInformation);
584     }
585 
586     Status = STATUS_SUCCESS;
587 
588 cleanup:
589     if (hDevicesKey && hDevicesKey != hBaseKey)
590         ZwClose(hDevicesKey);
591     if (pDeviceInformation)
592         ExFreePool(pDeviceInformation);
593 
594     return Status;
595 }
596 
597 static
598 CODE_SEG("INIT")
599 BOOLEAN
IopIsFirmwareMapperDisabled(VOID)600 IopIsFirmwareMapperDisabled(VOID)
601 {
602     UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
603     UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
604     OBJECT_ATTRIBUTES ObjectAttributes;
605     HANDLE hPnpKey;
606     PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
607     ULONG DesiredLength, Length;
608     ULONG KeyValue = 0;
609     NTSTATUS Status;
610 
611     InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
612     Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
613     if (NT_SUCCESS(Status))
614     {
615         Status = ZwQueryValueKey(hPnpKey,
616                                  &KeyNameU,
617                                  KeyValuePartialInformation,
618                                  NULL,
619                                  0,
620                                  &DesiredLength);
621         if ((Status == STATUS_BUFFER_TOO_SMALL) ||
622             (Status == STATUS_BUFFER_OVERFLOW))
623         {
624             Length = DesiredLength;
625             KeyInformation = ExAllocatePool(PagedPool, Length);
626             if (KeyInformation)
627             {
628                 Status = ZwQueryValueKey(hPnpKey,
629                                          &KeyNameU,
630                                          KeyValuePartialInformation,
631                                          KeyInformation,
632                                          Length,
633                                          &DesiredLength);
634                 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
635                 {
636                     KeyValue = (ULONG)(*KeyInformation->Data);
637                 }
638                 else
639                 {
640                     DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
641                 }
642 
643                 ExFreePool(KeyInformation);
644             }
645             else
646             {
647                 DPRINT1("Failed to allocate memory for registry query\n");
648             }
649         }
650         else
651         {
652             DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
653         }
654 
655         ZwClose(hPnpKey);
656     }
657     else
658     {
659         DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
660     }
661 
662     DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
663 
664     return (KeyValue != 0) ? TRUE : FALSE;
665 }
666 
667 CODE_SEG("INIT")
668 NTSTATUS
669 NTAPI
IopUpdateRootKey(VOID)670 IopUpdateRootKey(VOID)
671 {
672     UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
673     UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
674     UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
675     OBJECT_ATTRIBUTES ObjectAttributes;
676     HANDLE hEnum, hRoot;
677     NTSTATUS Status;
678 
679     InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
680     Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
681     if (!NT_SUCCESS(Status))
682     {
683         DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
684         return Status;
685     }
686 
687     InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
688     Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
689     ZwClose(hEnum);
690     if (!NT_SUCCESS(Status))
691     {
692         DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
693         return Status;
694     }
695 
696     if (!IopIsFirmwareMapperDisabled())
697     {
698         Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
699         if (!NT_SUCCESS(Status))
700         {
701             /* Nothing to do, don't return with an error status */
702             DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
703             ZwClose(hRoot);
704             return STATUS_SUCCESS;
705         }
706         Status = IopEnumerateDetectedDevices(
707             hEnum,
708             NULL,
709             hRoot,
710             TRUE,
711             NULL,
712             0,
713             NULL,
714             0);
715         ZwClose(hEnum);
716     }
717     else
718     {
719         /* Enumeration is disabled */
720         Status = STATUS_SUCCESS;
721     }
722 
723     ZwClose(hRoot);
724 
725     return Status;
726 }
727