1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 ERESOURCE PpRegistryDeviceResource;
19 KGUARDED_MUTEX PpDeviceReferenceTableLock;
20 RTL_AVL_TABLE PpDeviceReferenceTable;
21
22 extern ULONG ExpInitializationPhase;
23
24 /* DATA **********************************************************************/
25
26 PDRIVER_OBJECT IopRootDriverObject;
27 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
28
29 /* FUNCTIONS *****************************************************************/
30
31 VOID
IopFixupDeviceId(PWCHAR String)32 IopFixupDeviceId(PWCHAR String)
33 {
34 SIZE_T Length = wcslen(String), i;
35
36 for (i = 0; i < Length; i++)
37 {
38 if (String[i] == L'\\')
39 String[i] = L'#';
40 }
41 }
42
43 VOID
44 NTAPI
IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)45 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
46 {
47 NTSTATUS Status;
48 HANDLE CriticalDeviceKey, InstanceKey;
49 OBJECT_ATTRIBUTES ObjectAttributes;
50 UNICODE_STRING CriticalDeviceKeyU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
51 UNICODE_STRING CompatibleIdU = RTL_CONSTANT_STRING(L"CompatibleIDs");
52 UNICODE_STRING HardwareIdU = RTL_CONSTANT_STRING(L"HardwareID");
53 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service");
54 UNICODE_STRING ClassGuidU = RTL_CONSTANT_STRING(L"ClassGUID");
55 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
56 ULONG HidLength = 0, CidLength = 0, BufferLength;
57 PWCHAR IdBuffer, OriginalIdBuffer;
58
59 /* Open the device instance key */
60 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
61 if (Status != STATUS_SUCCESS)
62 return;
63
64 Status = ZwQueryValueKey(InstanceKey,
65 &HardwareIdU,
66 KeyValuePartialInformation,
67 NULL,
68 0,
69 &HidLength);
70 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
71 {
72 ZwClose(InstanceKey);
73 return;
74 }
75
76 Status = ZwQueryValueKey(InstanceKey,
77 &CompatibleIdU,
78 KeyValuePartialInformation,
79 NULL,
80 0,
81 &CidLength);
82 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
83 {
84 CidLength = 0;
85 }
86
87 BufferLength = HidLength + CidLength;
88 BufferLength -= (((CidLength != 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
89
90 /* Allocate a buffer to hold data from both */
91 OriginalIdBuffer = IdBuffer = ExAllocatePool(PagedPool, BufferLength);
92 if (!IdBuffer)
93 {
94 ZwClose(InstanceKey);
95 return;
96 }
97
98 /* Compute the buffer size */
99 if (HidLength > CidLength)
100 BufferLength = HidLength;
101 else
102 BufferLength = CidLength;
103
104 PartialInfo = ExAllocatePool(PagedPool, BufferLength);
105 if (!PartialInfo)
106 {
107 ZwClose(InstanceKey);
108 ExFreePool(OriginalIdBuffer);
109 return;
110 }
111
112 Status = ZwQueryValueKey(InstanceKey,
113 &HardwareIdU,
114 KeyValuePartialInformation,
115 PartialInfo,
116 HidLength,
117 &HidLength);
118 if (Status != STATUS_SUCCESS)
119 {
120 ExFreePool(PartialInfo);
121 ExFreePool(OriginalIdBuffer);
122 ZwClose(InstanceKey);
123 return;
124 }
125
126 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
127 HidLength = PartialInfo->DataLength - ((CidLength != 0) ? sizeof(WCHAR) : 0);
128 RtlCopyMemory(IdBuffer, PartialInfo->Data, HidLength);
129
130 if (CidLength != 0)
131 {
132 Status = ZwQueryValueKey(InstanceKey,
133 &CompatibleIdU,
134 KeyValuePartialInformation,
135 PartialInfo,
136 CidLength,
137 &CidLength);
138 if (Status != STATUS_SUCCESS)
139 {
140 ExFreePool(PartialInfo);
141 ExFreePool(OriginalIdBuffer);
142 ZwClose(InstanceKey);
143 return;
144 }
145
146 /* Copy CID next */
147 CidLength = PartialInfo->DataLength;
148 RtlCopyMemory(((PUCHAR)IdBuffer) + HidLength, PartialInfo->Data, CidLength);
149 }
150
151 /* Free our temp buffer */
152 ExFreePool(PartialInfo);
153
154 InitializeObjectAttributes(&ObjectAttributes,
155 &CriticalDeviceKeyU,
156 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
157 NULL,
158 NULL);
159 Status = ZwOpenKey(&CriticalDeviceKey,
160 KEY_ENUMERATE_SUB_KEYS,
161 &ObjectAttributes);
162 if (!NT_SUCCESS(Status))
163 {
164 /* The critical device database doesn't exist because
165 * we're probably in 1st stage setup, but it's ok */
166 ExFreePool(OriginalIdBuffer);
167 ZwClose(InstanceKey);
168 return;
169 }
170
171 while (*IdBuffer)
172 {
173 USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index;
174
175 IopFixupDeviceId(IdBuffer);
176
177 /* Look through all subkeys for a match */
178 for (Index = 0; TRUE; Index++)
179 {
180 ULONG NeededLength;
181 PKEY_BASIC_INFORMATION BasicInfo;
182
183 Status = ZwEnumerateKey(CriticalDeviceKey,
184 Index,
185 KeyBasicInformation,
186 NULL,
187 0,
188 &NeededLength);
189 if (Status == STATUS_NO_MORE_ENTRIES)
190 break;
191 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
192 {
193 UNICODE_STRING ChildIdNameU, RegKeyNameU;
194
195 BasicInfo = ExAllocatePool(PagedPool, NeededLength);
196 if (!BasicInfo)
197 {
198 /* No memory */
199 ExFreePool(OriginalIdBuffer);
200 ZwClose(CriticalDeviceKey);
201 ZwClose(InstanceKey);
202 return;
203 }
204
205 Status = ZwEnumerateKey(CriticalDeviceKey,
206 Index,
207 KeyBasicInformation,
208 BasicInfo,
209 NeededLength,
210 &NeededLength);
211 if (Status != STATUS_SUCCESS)
212 {
213 /* This shouldn't happen */
214 ExFreePool(BasicInfo);
215 continue;
216 }
217
218 ChildIdNameU.Buffer = IdBuffer;
219 ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR);
220 RegKeyNameU.Buffer = BasicInfo->Name;
221 RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength;
222
223 if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE))
224 {
225 HANDLE ChildKeyHandle;
226
227 InitializeObjectAttributes(&ObjectAttributes,
228 &ChildIdNameU,
229 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
230 CriticalDeviceKey,
231 NULL);
232
233 Status = ZwOpenKey(&ChildKeyHandle,
234 KEY_QUERY_VALUE,
235 &ObjectAttributes);
236 if (Status != STATUS_SUCCESS)
237 {
238 ExFreePool(BasicInfo);
239 continue;
240 }
241
242 /* Check if there's already a driver installed */
243 Status = ZwQueryValueKey(InstanceKey,
244 &ClassGuidU,
245 KeyValuePartialInformation,
246 NULL,
247 0,
248 &NeededLength);
249 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
250 {
251 ExFreePool(BasicInfo);
252 continue;
253 }
254
255 Status = ZwQueryValueKey(ChildKeyHandle,
256 &ClassGuidU,
257 KeyValuePartialInformation,
258 NULL,
259 0,
260 &NeededLength);
261 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
262 {
263 ExFreePool(BasicInfo);
264 continue;
265 }
266
267 PartialInfo = ExAllocatePool(PagedPool, NeededLength);
268 if (!PartialInfo)
269 {
270 ExFreePool(OriginalIdBuffer);
271 ExFreePool(BasicInfo);
272 ZwClose(InstanceKey);
273 ZwClose(ChildKeyHandle);
274 ZwClose(CriticalDeviceKey);
275 return;
276 }
277
278 /* Read ClassGUID entry in the CDDB */
279 Status = ZwQueryValueKey(ChildKeyHandle,
280 &ClassGuidU,
281 KeyValuePartialInformation,
282 PartialInfo,
283 NeededLength,
284 &NeededLength);
285 if (Status != STATUS_SUCCESS)
286 {
287 ExFreePool(BasicInfo);
288 continue;
289 }
290
291 /* Write it to the ENUM key */
292 Status = ZwSetValueKey(InstanceKey,
293 &ClassGuidU,
294 0,
295 REG_SZ,
296 PartialInfo->Data,
297 PartialInfo->DataLength);
298 if (Status != STATUS_SUCCESS)
299 {
300 ExFreePool(BasicInfo);
301 ExFreePool(PartialInfo);
302 ZwClose(ChildKeyHandle);
303 continue;
304 }
305
306 Status = ZwQueryValueKey(ChildKeyHandle,
307 &ServiceU,
308 KeyValuePartialInformation,
309 NULL,
310 0,
311 &NeededLength);
312 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
313 {
314 ExFreePool(PartialInfo);
315 PartialInfo = ExAllocatePool(PagedPool, NeededLength);
316 if (!PartialInfo)
317 {
318 ExFreePool(OriginalIdBuffer);
319 ExFreePool(BasicInfo);
320 ZwClose(InstanceKey);
321 ZwClose(ChildKeyHandle);
322 ZwClose(CriticalDeviceKey);
323 return;
324 }
325
326 /* Read the service entry from the CDDB */
327 Status = ZwQueryValueKey(ChildKeyHandle,
328 &ServiceU,
329 KeyValuePartialInformation,
330 PartialInfo,
331 NeededLength,
332 &NeededLength);
333 if (Status != STATUS_SUCCESS)
334 {
335 ExFreePool(BasicInfo);
336 ExFreePool(PartialInfo);
337 ZwClose(ChildKeyHandle);
338 continue;
339 }
340
341 /* Write it to the ENUM key */
342 Status = ZwSetValueKey(InstanceKey,
343 &ServiceU,
344 0,
345 REG_SZ,
346 PartialInfo->Data,
347 PartialInfo->DataLength);
348 if (Status != STATUS_SUCCESS)
349 {
350 ExFreePool(BasicInfo);
351 ExFreePool(PartialInfo);
352 ZwClose(ChildKeyHandle);
353 continue;
354 }
355
356 DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU);
357 }
358 else
359 {
360 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU);
361 }
362
363 ExFreePool(OriginalIdBuffer);
364 ExFreePool(PartialInfo);
365 ExFreePool(BasicInfo);
366 ZwClose(InstanceKey);
367 ZwClose(ChildKeyHandle);
368 ZwClose(CriticalDeviceKey);
369
370 /* That's it */
371 return;
372 }
373
374 ExFreePool(BasicInfo);
375 }
376 else
377 {
378 /* Umm, not sure what happened here */
379 continue;
380 }
381 }
382
383 /* Advance to the next ID */
384 IdBuffer += StringLength;
385 }
386
387 ExFreePool(OriginalIdBuffer);
388 ZwClose(InstanceKey);
389 ZwClose(CriticalDeviceKey);
390 }
391
392 NTSTATUS
IopGetSystemPowerDeviceObject(PDEVICE_OBJECT * DeviceObject)393 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
394 {
395 KIRQL OldIrql;
396
397 if (PopSystemPowerDeviceNode)
398 {
399 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
400 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
401 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
402
403 return STATUS_SUCCESS;
404 }
405
406 return STATUS_UNSUCCESSFUL;
407 }
408
409 USHORT
410 NTAPI
IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)411 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
412 {
413 USHORT i = 0, FoundIndex = 0xFFFF;
414 ULONG NewSize;
415 PVOID NewList;
416
417 /* Acquire the lock */
418 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
419
420 /* Loop all entries */
421 while (i < PnpBusTypeGuidList->GuidCount)
422 {
423 /* Try to find a match */
424 if (RtlCompareMemory(BusTypeGuid,
425 &PnpBusTypeGuidList->Guids[i],
426 sizeof(GUID)) == sizeof(GUID))
427 {
428 /* Found it */
429 FoundIndex = i;
430 goto Quickie;
431 }
432 i++;
433 }
434
435 /* Check if we have to grow the list */
436 if (PnpBusTypeGuidList->GuidCount)
437 {
438 /* Calculate the new size */
439 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
440 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
441
442 /* Allocate the new copy */
443 NewList = ExAllocatePool(PagedPool, NewSize);
444
445 if (!NewList)
446 {
447 /* Fail */
448 ExFreePool(PnpBusTypeGuidList);
449 goto Quickie;
450 }
451
452 /* Now copy them, decrease the size too */
453 NewSize -= sizeof(GUID);
454 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
455
456 /* Free the old list */
457 ExFreePool(PnpBusTypeGuidList);
458
459 /* Use the new buffer */
460 PnpBusTypeGuidList = NewList;
461 }
462
463 /* Copy the new GUID */
464 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
465 BusTypeGuid,
466 sizeof(GUID));
467
468 /* The new entry is the index */
469 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
470 PnpBusTypeGuidList->GuidCount++;
471
472 Quickie:
473 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
474 return FoundIndex;
475 }
476
477 NTSTATUS
478 NTAPI
IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,IN OUT PIO_STATUS_BLOCK IoStatusBlock,IN UCHAR MinorFunction,IN PIO_STACK_LOCATION Stack OPTIONAL)479 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
480 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
481 IN UCHAR MinorFunction,
482 IN PIO_STACK_LOCATION Stack OPTIONAL)
483 {
484 IO_STACK_LOCATION IoStackLocation;
485
486 /* Fill out the stack information */
487 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
488 IoStackLocation.MajorFunction = IRP_MJ_PNP;
489 IoStackLocation.MinorFunction = MinorFunction;
490 if (Stack)
491 {
492 /* Copy the rest */
493 RtlCopyMemory(&IoStackLocation.Parameters,
494 &Stack->Parameters,
495 sizeof(Stack->Parameters));
496 }
497
498 /* Do the PnP call */
499 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
500 &IoStackLocation,
501 (PVOID)&IoStatusBlock->Information);
502 return IoStatusBlock->Status;
503 }
504
505 /*
506 * IopCreateDeviceKeyPath
507 *
508 * Creates a registry key
509 *
510 * Parameters
511 * RegistryPath
512 * Name of the key to be created.
513 * Handle
514 * Handle to the newly created key
515 *
516 * Remarks
517 * This method can create nested trees, so parent of RegistryPath can
518 * be not existant, and will be created if needed.
519 */
520 NTSTATUS
521 NTAPI
IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,IN ULONG CreateOptions,OUT PHANDLE Handle)522 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
523 IN ULONG CreateOptions,
524 OUT PHANDLE Handle)
525 {
526 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
527 HANDLE hParent = NULL, hKey;
528 OBJECT_ATTRIBUTES ObjectAttributes;
529 UNICODE_STRING KeyName;
530 PCWSTR Current, Last;
531 USHORT Length;
532 NTSTATUS Status;
533
534 /* Assume failure */
535 *Handle = NULL;
536
537 /* Open root key for device instances */
538 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
539 if (!NT_SUCCESS(Status))
540 {
541 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
542 return Status;
543 }
544
545 Current = KeyName.Buffer = RegistryPath->Buffer;
546 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
547
548 /* Go up to the end of the string */
549 while (Current <= Last)
550 {
551 if (Current != Last && *Current != L'\\')
552 {
553 /* Not the end of the string and not a separator */
554 Current++;
555 continue;
556 }
557
558 /* Prepare relative key name */
559 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
560 KeyName.MaximumLength = KeyName.Length = Length;
561 DPRINT("Create '%wZ'\n", &KeyName);
562
563 /* Open key */
564 InitializeObjectAttributes(&ObjectAttributes,
565 &KeyName,
566 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
567 hParent,
568 NULL);
569 Status = ZwCreateKey(&hKey,
570 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
571 &ObjectAttributes,
572 0,
573 NULL,
574 CreateOptions,
575 NULL);
576
577 /* Close parent key handle, we don't need it anymore */
578 if (hParent)
579 ZwClose(hParent);
580
581 /* Key opening/creating failed? */
582 if (!NT_SUCCESS(Status))
583 {
584 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
585 return Status;
586 }
587
588 /* Check if it is the end of the string */
589 if (Current == Last)
590 {
591 /* Yes, return success */
592 *Handle = hKey;
593 return STATUS_SUCCESS;
594 }
595
596 /* Start with this new parent key */
597 hParent = hKey;
598 Current++;
599 KeyName.Buffer = (PWSTR)Current;
600 }
601
602 return STATUS_UNSUCCESSFUL;
603 }
604
605 NTSTATUS
IopSetDeviceInstanceData(HANDLE InstanceKey,PDEVICE_NODE DeviceNode)606 IopSetDeviceInstanceData(HANDLE InstanceKey,
607 PDEVICE_NODE DeviceNode)
608 {
609 OBJECT_ATTRIBUTES ObjectAttributes;
610 UNICODE_STRING KeyName;
611 HANDLE LogConfKey, ControlKey, DeviceParamsKey;
612 ULONG ResCount;
613 ULONG ResultLength;
614 NTSTATUS Status;
615
616 DPRINT("IopSetDeviceInstanceData() called\n");
617
618 /* Create the 'LogConf' key */
619 RtlInitUnicodeString(&KeyName, L"LogConf");
620 InitializeObjectAttributes(&ObjectAttributes,
621 &KeyName,
622 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
623 InstanceKey,
624 NULL);
625 Status = ZwCreateKey(&LogConfKey,
626 KEY_ALL_ACCESS,
627 &ObjectAttributes,
628 0,
629 NULL,
630 // FIXME? In r53694 it was silently turned from non-volatile into this,
631 // without any extra warning. Is this still needed??
632 REG_OPTION_VOLATILE,
633 NULL);
634 if (NT_SUCCESS(Status))
635 {
636 /* Set 'BootConfig' value */
637 if (DeviceNode->BootResources != NULL)
638 {
639 ResCount = DeviceNode->BootResources->Count;
640 if (ResCount != 0)
641 {
642 RtlInitUnicodeString(&KeyName, L"BootConfig");
643 Status = ZwSetValueKey(LogConfKey,
644 &KeyName,
645 0,
646 REG_RESOURCE_LIST,
647 DeviceNode->BootResources,
648 PnpDetermineResourceListSize(DeviceNode->BootResources));
649 }
650 }
651
652 /* Set 'BasicConfigVector' value */
653 if (DeviceNode->ResourceRequirements != NULL &&
654 DeviceNode->ResourceRequirements->ListSize != 0)
655 {
656 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
657 Status = ZwSetValueKey(LogConfKey,
658 &KeyName,
659 0,
660 REG_RESOURCE_REQUIREMENTS_LIST,
661 DeviceNode->ResourceRequirements,
662 DeviceNode->ResourceRequirements->ListSize);
663 }
664
665 ZwClose(LogConfKey);
666 }
667
668 /* Set the 'ConfigFlags' value */
669 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
670 Status = ZwQueryValueKey(InstanceKey,
671 &KeyName,
672 KeyValueBasicInformation,
673 NULL,
674 0,
675 &ResultLength);
676 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
677 {
678 /* Write the default value */
679 ULONG DefaultConfigFlags = 0;
680 Status = ZwSetValueKey(InstanceKey,
681 &KeyName,
682 0,
683 REG_DWORD,
684 &DefaultConfigFlags,
685 sizeof(DefaultConfigFlags));
686 }
687
688 /* Create the 'Control' key */
689 RtlInitUnicodeString(&KeyName, L"Control");
690 InitializeObjectAttributes(&ObjectAttributes,
691 &KeyName,
692 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
693 InstanceKey,
694 NULL);
695 Status = ZwCreateKey(&ControlKey,
696 0,
697 &ObjectAttributes,
698 0,
699 NULL,
700 REG_OPTION_VOLATILE,
701 NULL);
702 if (NT_SUCCESS(Status))
703 ZwClose(ControlKey);
704
705 /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
706 if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
707 {
708 RtlInitUnicodeString(&KeyName, L"Device Parameters");
709 InitializeObjectAttributes(&ObjectAttributes,
710 &KeyName,
711 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
712 InstanceKey,
713 NULL);
714 Status = ZwCreateKey(&DeviceParamsKey,
715 0,
716 &ObjectAttributes,
717 0,
718 NULL,
719 REG_OPTION_NON_VOLATILE,
720 NULL);
721 if (NT_SUCCESS(Status))
722 {
723 ULONG FirmwareIdentified = 1;
724 RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
725 Status = ZwSetValueKey(DeviceParamsKey,
726 &KeyName,
727 0,
728 REG_DWORD,
729 &FirmwareIdentified,
730 sizeof(FirmwareIdentified));
731
732 ZwClose(DeviceParamsKey);
733 }
734 }
735
736 DPRINT("IopSetDeviceInstanceData() done\n");
737
738 return Status;
739 }
740
741 /*
742 * IopGetParentIdPrefix
743 *
744 * Retrieve (or create) a string which identifies a device.
745 *
746 * Parameters
747 * DeviceNode
748 * Pointer to device node.
749 * ParentIdPrefix
750 * Pointer to the string where is returned the parent node identifier
751 *
752 * Remarks
753 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
754 * valid and its Buffer field is NULL-terminated. The caller needs to
755 * to free the string with RtlFreeUnicodeString when it is no longer
756 * needed.
757 */
758
759 NTSTATUS
IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,PUNICODE_STRING ParentIdPrefix)760 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
761 PUNICODE_STRING ParentIdPrefix)
762 {
763 const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
764 ULONG KeyNameBufferLength;
765 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
766 UNICODE_STRING KeyName = {0, 0, NULL};
767 UNICODE_STRING KeyValue;
768 UNICODE_STRING ValueName;
769 HANDLE hKey = NULL;
770 ULONG crc32;
771 NTSTATUS Status;
772
773 /* HACK: As long as some devices have a NULL device
774 * instance path, the following test is required :(
775 */
776 if (DeviceNode->Parent->InstancePath.Length == 0)
777 {
778 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
779 &DeviceNode->InstancePath);
780 return STATUS_UNSUCCESSFUL;
781 }
782
783 /* 1. Try to retrieve ParentIdPrefix from registry */
784 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
785 ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
786 KeyNameBufferLength + sizeof(UNICODE_NULL),
787 TAG_IO);
788 if (!ParentIdPrefixInformation)
789 {
790 return STATUS_INSUFFICIENT_RESOURCES;
791 }
792
793 KeyName.Length = 0;
794 KeyName.MaximumLength = EnumKeyPath.Length +
795 DeviceNode->Parent->InstancePath.Length +
796 sizeof(UNICODE_NULL);
797 KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
798 KeyName.MaximumLength,
799 TAG_IO);
800 if (!KeyName.Buffer)
801 {
802 Status = STATUS_INSUFFICIENT_RESOURCES;
803 goto cleanup;
804 }
805
806 RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
807 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
808
809 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
810 if (!NT_SUCCESS(Status))
811 {
812 goto cleanup;
813 }
814 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
815 Status = ZwQueryValueKey(hKey,
816 &ValueName,
817 KeyValuePartialInformation,
818 ParentIdPrefixInformation,
819 KeyNameBufferLength,
820 &KeyNameBufferLength);
821 if (NT_SUCCESS(Status))
822 {
823 if (ParentIdPrefixInformation->Type != REG_SZ)
824 {
825 Status = STATUS_UNSUCCESSFUL;
826 }
827 else
828 {
829 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
830 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
831 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
832 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
833 }
834 goto cleanup;
835 }
836 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
837 {
838 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
839 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
840 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
841 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
842 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
843 goto cleanup;
844 }
845
846 /* 2. Create the ParentIdPrefix value */
847 crc32 = RtlComputeCrc32(0,
848 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
849 DeviceNode->Parent->InstancePath.Length);
850
851 RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
852 KeyNameBufferLength,
853 L"%lx&%lx",
854 DeviceNode->Parent->Level,
855 crc32);
856 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
857
858 /* 3. Try to write the ParentIdPrefix to registry */
859 Status = ZwSetValueKey(hKey,
860 &ValueName,
861 0,
862 REG_SZ,
863 KeyValue.Buffer,
864 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
865
866 cleanup:
867 if (NT_SUCCESS(Status))
868 {
869 /* Duplicate the string to return it */
870 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
871 &KeyValue,
872 ParentIdPrefix);
873 }
874 ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
875 RtlFreeUnicodeString(&KeyName);
876 if (hKey != NULL)
877 {
878 ZwClose(hKey);
879 }
880 return Status;
881 }
882
883 NTSTATUS
884 NTAPI
IopOpenRegistryKeyEx(PHANDLE KeyHandle,HANDLE ParentKey,PUNICODE_STRING Name,ACCESS_MASK DesiredAccess)885 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
886 HANDLE ParentKey,
887 PUNICODE_STRING Name,
888 ACCESS_MASK DesiredAccess)
889 {
890 OBJECT_ATTRIBUTES ObjectAttributes;
891 NTSTATUS Status;
892
893 PAGED_CODE();
894
895 *KeyHandle = NULL;
896
897 InitializeObjectAttributes(&ObjectAttributes,
898 Name,
899 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
900 ParentKey,
901 NULL);
902
903 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
904
905 return Status;
906 }
907
908 NTSTATUS
909 NTAPI
IopCreateRegistryKeyEx(OUT PHANDLE Handle,IN HANDLE RootHandle OPTIONAL,IN PUNICODE_STRING KeyName,IN ACCESS_MASK DesiredAccess,IN ULONG CreateOptions,OUT PULONG Disposition OPTIONAL)910 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
911 IN HANDLE RootHandle OPTIONAL,
912 IN PUNICODE_STRING KeyName,
913 IN ACCESS_MASK DesiredAccess,
914 IN ULONG CreateOptions,
915 OUT PULONG Disposition OPTIONAL)
916 {
917 OBJECT_ATTRIBUTES ObjectAttributes;
918 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
919 USHORT Length;
920 HANDLE HandleArray[2];
921 BOOLEAN Recursing = TRUE;
922 PWCHAR pp, p, p1;
923 UNICODE_STRING KeyString;
924 NTSTATUS Status = STATUS_SUCCESS;
925 PAGED_CODE();
926
927 /* P1 is start, pp is end */
928 p1 = KeyName->Buffer;
929 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
930
931 /* Create the target key */
932 InitializeObjectAttributes(&ObjectAttributes,
933 KeyName,
934 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
935 RootHandle,
936 NULL);
937 Status = ZwCreateKey(&HandleArray[i],
938 DesiredAccess,
939 &ObjectAttributes,
940 0,
941 NULL,
942 CreateOptions,
943 &KeyDisposition);
944
945 /* Now we check if this failed */
946 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
947 {
948 /* Target key failed, so we'll need to create its parent. Setup array */
949 HandleArray[0] = NULL;
950 HandleArray[1] = RootHandle;
951
952 /* Keep recursing for each missing parent */
953 while (Recursing)
954 {
955 /* And if we're deep enough, close the last handle */
956 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
957
958 /* We're setup to ping-pong between the two handle array entries */
959 RootHandleIndex = i;
960 i = (i + 1) & 1;
961
962 /* Clear the one we're attempting to open now */
963 HandleArray[i] = NULL;
964
965 /* Process the parent key name */
966 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
967 Length = (USHORT)(p - p1) * sizeof(WCHAR);
968
969 /* Is there a parent name? */
970 if (Length)
971 {
972 /* Build the unicode string for it */
973 KeyString.Buffer = p1;
974 KeyString.Length = KeyString.MaximumLength = Length;
975
976 /* Now try opening the parent */
977 InitializeObjectAttributes(&ObjectAttributes,
978 &KeyString,
979 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
980 HandleArray[RootHandleIndex],
981 NULL);
982 Status = ZwCreateKey(&HandleArray[i],
983 DesiredAccess,
984 &ObjectAttributes,
985 0,
986 NULL,
987 CreateOptions,
988 &KeyDisposition);
989 if (NT_SUCCESS(Status))
990 {
991 /* It worked, we have one more handle */
992 NestedCloseLevel++;
993 }
994 else
995 {
996 /* Parent key creation failed, abandon loop */
997 Recursing = FALSE;
998 continue;
999 }
1000 }
1001 else
1002 {
1003 /* We don't have a parent name, probably corrupted key name */
1004 Status = STATUS_INVALID_PARAMETER;
1005 Recursing = FALSE;
1006 continue;
1007 }
1008
1009 /* Now see if there's more parents to create */
1010 p1 = p + 1;
1011 if ((p == pp) || (p1 == pp))
1012 {
1013 /* We're done, hopefully successfully, so stop */
1014 Recursing = FALSE;
1015 }
1016 }
1017
1018 /* Outer loop check for handle nesting that requires closing the top handle */
1019 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
1020 }
1021
1022 /* Check if we broke out of the loop due to success */
1023 if (NT_SUCCESS(Status))
1024 {
1025 /* Return the target handle (we closed all the parent ones) and disposition */
1026 *Handle = HandleArray[i];
1027 if (Disposition) *Disposition = KeyDisposition;
1028 }
1029
1030 /* Return the success state */
1031 return Status;
1032 }
1033
1034 NTSTATUS
1035 NTAPI
IopGetRegistryValue(IN HANDLE Handle,IN PWSTR ValueName,OUT PKEY_VALUE_FULL_INFORMATION * Information)1036 IopGetRegistryValue(IN HANDLE Handle,
1037 IN PWSTR ValueName,
1038 OUT PKEY_VALUE_FULL_INFORMATION *Information)
1039 {
1040 UNICODE_STRING ValueString;
1041 NTSTATUS Status;
1042 PKEY_VALUE_FULL_INFORMATION FullInformation;
1043 ULONG Size;
1044 PAGED_CODE();
1045
1046 RtlInitUnicodeString(&ValueString, ValueName);
1047
1048 Status = ZwQueryValueKey(Handle,
1049 &ValueString,
1050 KeyValueFullInformation,
1051 NULL,
1052 0,
1053 &Size);
1054 if ((Status != STATUS_BUFFER_OVERFLOW) &&
1055 (Status != STATUS_BUFFER_TOO_SMALL))
1056 {
1057 return Status;
1058 }
1059
1060 FullInformation = ExAllocatePool(NonPagedPool, Size);
1061 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
1062
1063 Status = ZwQueryValueKey(Handle,
1064 &ValueString,
1065 KeyValueFullInformation,
1066 FullInformation,
1067 Size,
1068 &Size);
1069 if (!NT_SUCCESS(Status))
1070 {
1071 ExFreePool(FullInformation);
1072 return Status;
1073 }
1074
1075 *Information = FullInformation;
1076 return STATUS_SUCCESS;
1077 }
1078
1079 RTL_GENERIC_COMPARE_RESULTS
1080 NTAPI
PiCompareInstancePath(IN PRTL_AVL_TABLE Table,IN PVOID FirstStruct,IN PVOID SecondStruct)1081 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
1082 IN PVOID FirstStruct,
1083 IN PVOID SecondStruct)
1084 {
1085 /* FIXME: TODO */
1086 ASSERT(FALSE);
1087 return 0;
1088 }
1089
1090 //
1091 // The allocation function is called by the generic table package whenever
1092 // it needs to allocate memory for the table.
1093 //
1094
1095 PVOID
1096 NTAPI
PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,IN CLONG ByteSize)1097 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
1098 IN CLONG ByteSize)
1099 {
1100 /* FIXME: TODO */
1101 ASSERT(FALSE);
1102 return NULL;
1103 }
1104
1105 VOID
1106 NTAPI
PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,IN PVOID Buffer)1107 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
1108 IN PVOID Buffer)
1109 {
1110 /* FIXME: TODO */
1111 ASSERT(FALSE);
1112 }
1113
1114 VOID
1115 NTAPI
PpInitializeDeviceReferenceTable(VOID)1116 PpInitializeDeviceReferenceTable(VOID)
1117 {
1118 /* Setup the guarded mutex and AVL table */
1119 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
1120 RtlInitializeGenericTableAvl(
1121 &PpDeviceReferenceTable,
1122 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
1123 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
1124 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
1125 NULL);
1126 }
1127
1128 BOOLEAN
1129 NTAPI
PiInitPhase0(VOID)1130 PiInitPhase0(VOID)
1131 {
1132 /* Initialize the resource when accessing device registry data */
1133 ExInitializeResourceLite(&PpRegistryDeviceResource);
1134
1135 /* Setup the device reference AVL table */
1136 PpInitializeDeviceReferenceTable();
1137 return TRUE;
1138 }
1139
1140 BOOLEAN
1141 NTAPI
PpInitSystem(VOID)1142 PpInitSystem(VOID)
1143 {
1144 /* Check the initialization phase */
1145 switch (ExpInitializationPhase)
1146 {
1147 case 0:
1148
1149 /* Do Phase 0 */
1150 return PiInitPhase0();
1151
1152 case 1:
1153
1154 /* Do Phase 1 */
1155 return TRUE;
1156 //return PiInitPhase1();
1157
1158 default:
1159
1160 /* Don't know any other phase! Bugcheck! */
1161 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
1162 return FALSE;
1163 }
1164 }
1165
1166 /* PUBLIC FUNCTIONS **********************************************************/
1167
1168 NTSTATUS
1169 NTAPI
PnpBusTypeGuidGet(IN USHORT Index,IN LPGUID BusTypeGuid)1170 PnpBusTypeGuidGet(IN USHORT Index,
1171 IN LPGUID BusTypeGuid)
1172 {
1173 NTSTATUS Status = STATUS_SUCCESS;
1174
1175 /* Acquire the lock */
1176 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
1177
1178 /* Validate size */
1179 if (Index < PnpBusTypeGuidList->GuidCount)
1180 {
1181 /* Copy the data */
1182 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
1183 }
1184 else
1185 {
1186 /* Failure path */
1187 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1188 }
1189
1190 /* Release lock and return status */
1191 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
1192 return Status;
1193 }
1194
1195 NTSTATUS
1196 NTAPI
PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,IN PHANDLE DeviceInstanceHandle,IN ACCESS_MASK DesiredAccess)1197 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
1198 IN PHANDLE DeviceInstanceHandle,
1199 IN ACCESS_MASK DesiredAccess)
1200 {
1201 NTSTATUS Status;
1202 HANDLE KeyHandle;
1203 PDEVICE_NODE DeviceNode;
1204 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
1205 PAGED_CODE();
1206
1207 /* Open the enum key */
1208 Status = IopOpenRegistryKeyEx(&KeyHandle,
1209 NULL,
1210 &KeyName,
1211 KEY_READ);
1212 if (!NT_SUCCESS(Status)) return Status;
1213
1214 /* Make sure we have an instance path */
1215 DeviceNode = IopGetDeviceNode(DeviceObject);
1216 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
1217 {
1218 /* Get the instance key */
1219 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
1220 KeyHandle,
1221 &DeviceNode->InstancePath,
1222 DesiredAccess);
1223 }
1224 else
1225 {
1226 /* Fail */
1227 Status = STATUS_INVALID_DEVICE_REQUEST;
1228 }
1229
1230 /* Close the handle and return status */
1231 ZwClose(KeyHandle);
1232 return Status;
1233 }
1234
1235 ULONG
1236 NTAPI
PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)1237 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
1238 {
1239 ULONG FinalSize, PartialSize, EntrySize, i, j;
1240 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
1241 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
1242
1243 /* If we don't have one, that's easy */
1244 if (!ResourceList) return 0;
1245
1246 /* Start with the minimum size possible */
1247 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1248
1249 /* Loop each full descriptor */
1250 FullDescriptor = ResourceList->List;
1251 for (i = 0; i < ResourceList->Count; i++)
1252 {
1253 /* Start with the minimum size possible */
1254 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
1255 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
1256
1257 /* Loop each partial descriptor */
1258 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
1259 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
1260 {
1261 /* Start with the minimum size possible */
1262 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1263
1264 /* Check if there is extra data */
1265 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
1266 {
1267 /* Add that data */
1268 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
1269 }
1270
1271 /* The size of partial descriptors is bigger */
1272 PartialSize += EntrySize;
1273
1274 /* Go to the next partial descriptor */
1275 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
1276 }
1277
1278 /* The size of full descriptors is bigger */
1279 FinalSize += PartialSize;
1280
1281 /* Go to the next full descriptor */
1282 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
1283 }
1284
1285 /* Return the final size */
1286 return FinalSize;
1287 }
1288
1289 NTSTATUS
1290 NTAPI
PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,IN ULONG ValueType,IN PWSTR ValueName,IN PWSTR KeyName,OUT PVOID Buffer,IN PULONG BufferLength)1291 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
1292 IN ULONG ValueType,
1293 IN PWSTR ValueName,
1294 IN PWSTR KeyName,
1295 OUT PVOID Buffer,
1296 IN PULONG BufferLength)
1297 {
1298 NTSTATUS Status;
1299 HANDLE KeyHandle, SubHandle;
1300 UNICODE_STRING KeyString;
1301 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
1302 ULONG Length;
1303 PAGED_CODE();
1304
1305 /* Find the instance key */
1306 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
1307 if (NT_SUCCESS(Status))
1308 {
1309 /* Check for name given by caller */
1310 if (KeyName)
1311 {
1312 /* Open this key */
1313 RtlInitUnicodeString(&KeyString, KeyName);
1314 Status = IopOpenRegistryKeyEx(&SubHandle,
1315 KeyHandle,
1316 &KeyString,
1317 KEY_READ);
1318 if (NT_SUCCESS(Status))
1319 {
1320 /* And use this handle instead */
1321 ZwClose(KeyHandle);
1322 KeyHandle = SubHandle;
1323 }
1324 }
1325
1326 /* Check if sub-key handle succeeded (or no-op if no key name given) */
1327 if (NT_SUCCESS(Status))
1328 {
1329 /* Now get the size of the property */
1330 Status = IopGetRegistryValue(KeyHandle,
1331 ValueName,
1332 &KeyValueInfo);
1333 }
1334
1335 /* Close the key */
1336 ZwClose(KeyHandle);
1337 }
1338
1339 /* Fail if any of the registry operations failed */
1340 if (!NT_SUCCESS(Status)) return Status;
1341
1342 /* Check how much data we have to copy */
1343 Length = KeyValueInfo->DataLength;
1344 if (*BufferLength >= Length)
1345 {
1346 /* Check for a match in the value type */
1347 if (KeyValueInfo->Type == ValueType)
1348 {
1349 /* Copy the data */
1350 RtlCopyMemory(Buffer,
1351 (PVOID)((ULONG_PTR)KeyValueInfo +
1352 KeyValueInfo->DataOffset),
1353 Length);
1354 }
1355 else
1356 {
1357 /* Invalid registry property type, fail */
1358 Status = STATUS_INVALID_PARAMETER_2;
1359 }
1360 }
1361 else
1362 {
1363 /* Buffer is too small to hold data */
1364 Status = STATUS_BUFFER_TOO_SMALL;
1365 }
1366
1367 /* Return the required buffer length, free the buffer, and return status */
1368 *BufferLength = Length;
1369 ExFreePool(KeyValueInfo);
1370 return Status;
1371 }
1372
1373 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
1374 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
1375 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
1376
1377 /*
1378 * @implemented
1379 */
1380 NTSTATUS
1381 NTAPI
IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,IN DEVICE_REGISTRY_PROPERTY DeviceProperty,IN ULONG BufferLength,OUT PVOID PropertyBuffer,OUT PULONG ResultLength)1382 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
1383 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
1384 IN ULONG BufferLength,
1385 OUT PVOID PropertyBuffer,
1386 OUT PULONG ResultLength)
1387 {
1388 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1389 DEVICE_CAPABILITIES DeviceCaps;
1390 ULONG ReturnLength = 0, Length = 0, ValueType;
1391 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
1392 PVOID Data = NULL;
1393 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
1394 GUID BusTypeGuid;
1395 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
1396 BOOLEAN NullTerminate = FALSE;
1397 DEVICE_REMOVAL_POLICY Policy;
1398
1399 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
1400
1401 /* Assume failure */
1402 *ResultLength = 0;
1403
1404 /* Only PDOs can call this */
1405 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
1406
1407 /* Handle all properties */
1408 switch (DeviceProperty)
1409 {
1410 case DevicePropertyBusTypeGuid:
1411
1412 /* Get the GUID from the internal cache */
1413 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
1414 if (!NT_SUCCESS(Status)) return Status;
1415
1416 /* This is the format of the returned data */
1417 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
1418
1419 case DevicePropertyLegacyBusType:
1420
1421 /* Validate correct interface type */
1422 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
1423 return STATUS_OBJECT_NAME_NOT_FOUND;
1424
1425 /* This is the format of the returned data */
1426 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
1427
1428 case DevicePropertyBusNumber:
1429
1430 /* Validate correct bus number */
1431 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
1432 return STATUS_OBJECT_NAME_NOT_FOUND;
1433
1434 /* This is the format of the returned data */
1435 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
1436
1437 case DevicePropertyEnumeratorName:
1438
1439 /* Get the instance path */
1440 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
1441
1442 /* Sanity checks */
1443 ASSERT((BufferLength & 1) == 0);
1444 ASSERT(DeviceInstanceName != NULL);
1445
1446 /* Get the name from the path */
1447 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
1448 ASSERT(EnumeratorNameEnd);
1449
1450 /* This string needs to be NULL-terminated */
1451 NullTerminate = TRUE;
1452
1453 /* This is the format of the returned data */
1454 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
1455 DeviceInstanceName);
1456
1457 case DevicePropertyAddress:
1458
1459 /* Query the device caps */
1460 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
1461 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
1462 return STATUS_OBJECT_NAME_NOT_FOUND;
1463
1464 /* This is the format of the returned data */
1465 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
1466
1467 case DevicePropertyBootConfigurationTranslated:
1468
1469 /* Validate we have resources */
1470 if (!DeviceNode->BootResources)
1471 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
1472 {
1473 /* No resources will still fake success, but with 0 bytes */
1474 *ResultLength = 0;
1475 return STATUS_SUCCESS;
1476 }
1477
1478 /* This is the format of the returned data */
1479 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
1480 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
1481
1482 case DevicePropertyPhysicalDeviceObjectName:
1483
1484 /* Sanity check for Unicode-sized string */
1485 ASSERT((BufferLength & 1) == 0);
1486
1487 /* Allocate name buffer */
1488 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
1489 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
1490 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
1491
1492 /* Query the PDO name */
1493 Status = ObQueryNameString(DeviceObject,
1494 ObjectNameInfo,
1495 Length,
1496 ResultLength);
1497 if (Status == STATUS_INFO_LENGTH_MISMATCH)
1498 {
1499 /* It's up to the caller to try again */
1500 Status = STATUS_BUFFER_TOO_SMALL;
1501 }
1502
1503 /* This string needs to be NULL-terminated */
1504 NullTerminate = TRUE;
1505
1506 /* Return if successful */
1507 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
1508 ObjectNameInfo->Name.Buffer);
1509
1510 /* Let the caller know how big the name is */
1511 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
1512 break;
1513
1514 case DevicePropertyRemovalPolicy:
1515
1516 Policy = DeviceNode->RemovalPolicy;
1517 PIP_RETURN_DATA(sizeof(Policy), &Policy);
1518
1519 /* Handle the registry-based properties */
1520 case DevicePropertyUINumber:
1521 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
1522 case DevicePropertyLocationInformation:
1523 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
1524 case DevicePropertyDeviceDescription:
1525 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
1526 case DevicePropertyHardwareID:
1527 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
1528 case DevicePropertyCompatibleIDs:
1529 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
1530 case DevicePropertyBootConfiguration:
1531 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
1532 case DevicePropertyClassName:
1533 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
1534 case DevicePropertyClassGuid:
1535 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
1536 case DevicePropertyDriverKeyName:
1537 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
1538 case DevicePropertyManufacturer:
1539 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
1540 case DevicePropertyFriendlyName:
1541 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
1542 case DevicePropertyContainerID:
1543 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
1544 PIP_UNIMPLEMENTED();
1545 break;
1546 case DevicePropertyInstallState:
1547 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD);
1548 break;
1549 case DevicePropertyResourceRequirements:
1550 PIP_UNIMPLEMENTED();
1551 case DevicePropertyAllocatedResources:
1552 PIP_UNIMPLEMENTED();
1553 default:
1554 return STATUS_INVALID_PARAMETER_2;
1555 }
1556
1557 /* Having a registry value name implies registry data */
1558 if (ValueName)
1559 {
1560 /* We know up-front how much data to expect */
1561 *ResultLength = BufferLength;
1562
1563 /* Go get the data, use the LogConf subkey if necessary */
1564 Status = PiGetDeviceRegistryProperty(DeviceObject,
1565 ValueType,
1566 ValueName,
1567 (DeviceProperty ==
1568 DevicePropertyBootConfiguration) ?
1569 L"LogConf": NULL,
1570 PropertyBuffer,
1571 ResultLength);
1572 }
1573 else if (NT_SUCCESS(Status))
1574 {
1575 /* We know up-front how much data to expect, check the caller's buffer */
1576 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
1577 if (*ResultLength <= BufferLength)
1578 {
1579 /* Buffer is all good, copy the data */
1580 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
1581
1582 /* Check if we need to NULL-terminate the string */
1583 if (NullTerminate)
1584 {
1585 /* Terminate the string */
1586 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
1587 }
1588
1589 /* This is the success path */
1590 Status = STATUS_SUCCESS;
1591 }
1592 else
1593 {
1594 /* Failure path */
1595 Status = STATUS_BUFFER_TOO_SMALL;
1596 }
1597 }
1598
1599 /* Free any allocation we may have made, and return the status code */
1600 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
1601 return Status;
1602 }
1603
1604 /**
1605 * @name IoOpenDeviceRegistryKey
1606 *
1607 * Open a registry key unique for a specified driver or device instance.
1608 *
1609 * @param DeviceObject Device to get the registry key for.
1610 * @param DevInstKeyType Type of the key to return.
1611 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
1612 * @param DevInstRegKey Handle to the opened registry key on
1613 * successful return.
1614 *
1615 * @return Status.
1616 *
1617 * @implemented
1618 */
1619 NTSTATUS
1620 NTAPI
IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,IN ULONG DevInstKeyType,IN ACCESS_MASK DesiredAccess,OUT PHANDLE DevInstRegKey)1621 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
1622 IN ULONG DevInstKeyType,
1623 IN ACCESS_MASK DesiredAccess,
1624 OUT PHANDLE DevInstRegKey)
1625 {
1626 static WCHAR RootKeyName[] =
1627 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
1628 static WCHAR ProfileKeyName[] =
1629 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
1630 static WCHAR ClassKeyName[] = L"Control\\Class\\";
1631 static WCHAR EnumKeyName[] = L"Enum\\";
1632 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
1633 ULONG KeyNameLength;
1634 PWSTR KeyNameBuffer;
1635 UNICODE_STRING KeyName;
1636 ULONG DriverKeyLength;
1637 OBJECT_ATTRIBUTES ObjectAttributes;
1638 PDEVICE_NODE DeviceNode = NULL;
1639 NTSTATUS Status;
1640
1641 DPRINT("IoOpenDeviceRegistryKey() called\n");
1642
1643 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
1644 {
1645 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting...\n");
1646 return STATUS_INVALID_PARAMETER;
1647 }
1648
1649 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
1650 return STATUS_INVALID_DEVICE_REQUEST;
1651 DeviceNode = IopGetDeviceNode(DeviceObject);
1652
1653 /*
1654 * Calculate the length of the base key name. This is the full
1655 * name for driver key or the name excluding "Device Parameters"
1656 * subkey for device key.
1657 */
1658
1659 KeyNameLength = sizeof(RootKeyName);
1660 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
1661 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
1662 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
1663 {
1664 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
1665 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
1666 0, NULL, &DriverKeyLength);
1667 if (Status != STATUS_BUFFER_TOO_SMALL)
1668 return Status;
1669 KeyNameLength += DriverKeyLength;
1670 }
1671 else
1672 {
1673 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
1674 DeviceNode->InstancePath.Length;
1675 }
1676
1677 /*
1678 * Now allocate the buffer for the key name...
1679 */
1680
1681 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
1682 if (KeyNameBuffer == NULL)
1683 return STATUS_INSUFFICIENT_RESOURCES;
1684
1685 KeyName.Length = 0;
1686 KeyName.MaximumLength = (USHORT)KeyNameLength;
1687 KeyName.Buffer = KeyNameBuffer;
1688
1689 /*
1690 * ...and build the key name.
1691 */
1692
1693 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
1694 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
1695
1696 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
1697 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
1698
1699 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
1700 {
1701 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
1702 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
1703 DriverKeyLength, KeyNameBuffer +
1704 (KeyName.Length / sizeof(WCHAR)),
1705 &DriverKeyLength);
1706 if (!NT_SUCCESS(Status))
1707 {
1708 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
1709 ExFreePool(KeyNameBuffer);
1710 return Status;
1711 }
1712 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
1713 }
1714 else
1715 {
1716 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
1717 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
1718 if (DeviceNode->InstancePath.Length == 0)
1719 {
1720 ExFreePool(KeyNameBuffer);
1721 return Status;
1722 }
1723 }
1724
1725 /*
1726 * Open the base key.
1727 */
1728 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
1729 if (!NT_SUCCESS(Status))
1730 {
1731 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
1732 ExFreePool(KeyNameBuffer);
1733 return Status;
1734 }
1735 ExFreePool(KeyNameBuffer);
1736
1737 /*
1738 * For driver key we're done now.
1739 */
1740
1741 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
1742 return Status;
1743
1744 /*
1745 * Let's go further. For device key we must open "Device Parameters"
1746 * subkey and create it if it doesn't exist yet.
1747 */
1748
1749 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
1750 InitializeObjectAttributes(&ObjectAttributes,
1751 &KeyName,
1752 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1753 *DevInstRegKey,
1754 NULL);
1755 Status = ZwCreateKey(DevInstRegKey,
1756 DesiredAccess,
1757 &ObjectAttributes,
1758 0,
1759 NULL,
1760 REG_OPTION_NON_VOLATILE,
1761 NULL);
1762 ZwClose(ObjectAttributes.RootDirectory);
1763
1764 return Status;
1765 }
1766
1767 /*
1768 * @implemented
1769 */
1770 VOID
1771 NTAPI
IoInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject,IN DEVICE_RELATION_TYPE Type)1772 IoInvalidateDeviceRelations(
1773 IN PDEVICE_OBJECT DeviceObject,
1774 IN DEVICE_RELATION_TYPE Type)
1775 {
1776 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
1777 {
1778 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
1779 }
1780
1781 switch (Type)
1782 {
1783 case BusRelations:
1784 /* Enumerate the device */
1785 PiQueueDeviceAction(DeviceObject, PiActionEnumDeviceTree, NULL, NULL);
1786 break;
1787 default:
1788 /* Everything else is not implemented */
1789 break;
1790 }
1791 }
1792
1793 /*
1794 * @implemented
1795 */
1796 NTSTATUS
1797 NTAPI
IoSynchronousInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject,IN DEVICE_RELATION_TYPE Type)1798 IoSynchronousInvalidateDeviceRelations(
1799 IN PDEVICE_OBJECT DeviceObject,
1800 IN DEVICE_RELATION_TYPE Type)
1801 {
1802 PAGED_CODE();
1803
1804 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
1805 {
1806 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
1807 }
1808
1809 switch (Type)
1810 {
1811 case BusRelations:
1812 /* Enumerate the device */
1813 return PiPerformSyncDeviceAction(DeviceObject, PiActionEnumDeviceTree);
1814 case PowerRelations:
1815 /* Not handled yet */
1816 return STATUS_NOT_IMPLEMENTED;
1817 case TargetDeviceRelation:
1818 /* Nothing to do */
1819 return STATUS_SUCCESS;
1820 default:
1821 /* Ejection relations are not supported */
1822 return STATUS_NOT_SUPPORTED;
1823 }
1824 }
1825
1826 /*
1827 * @implemented
1828 */
1829 BOOLEAN
1830 NTAPI
IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,IN ULONG BusNumber,IN PHYSICAL_ADDRESS BusAddress,IN OUT PULONG AddressSpace,OUT PPHYSICAL_ADDRESS TranslatedAddress)1831 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
1832 IN ULONG BusNumber,
1833 IN PHYSICAL_ADDRESS BusAddress,
1834 IN OUT PULONG AddressSpace,
1835 OUT PPHYSICAL_ADDRESS TranslatedAddress)
1836 {
1837 /* FIXME: Notify the resource arbiter */
1838
1839 return HalTranslateBusAddress(InterfaceType,
1840 BusNumber,
1841 BusAddress,
1842 AddressSpace,
1843 TranslatedAddress);
1844 }
1845
1846 VOID
1847 NTAPI
IoInvalidateDeviceState(IN PDEVICE_OBJECT DeviceObject)1848 IoInvalidateDeviceState(
1849 IN PDEVICE_OBJECT DeviceObject)
1850 {
1851 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
1852 {
1853 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)DeviceObject, 0, 0);
1854 }
1855
1856 PiQueueDeviceAction(DeviceObject, PiActionQueryState, NULL, NULL);
1857 }
1858