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 device manipulation functions
5 * COPYRIGHT: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * 2007 Hervé Poussineau (hpoussin@reactos.org)
7 * 2014-2017 Thomas Faber (thomas.faber@reactos.org)
8 * 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
9 */
10
11 /* Device tree is a resource shared among all system services: hal, kernel, drivers etc.
12 * Thus all code which interacts with the tree needs to be synchronized.
13 * Here it's done via a list of DEVICE_ACTION_REQUEST structures, which represents
14 * the device action queue. It is being processed exclusively by the PipDeviceActionWorker.
15 *
16 * Operation queuing can be done with the PiQueueDeviceAction function or with
17 * the PiPerfomSyncDeviceAction for synchronous operations.
18 * All device manipulation like starting, removing, enumeration (see DEVICE_ACTION enum)
19 * have to be done with the PiQueueDeviceAction in order to avoid race conditions.
20 *
21 * Note: there is one special operation here - PiActionEnumRootDevices. It is meant to be done
22 * during initialization process (and be the first device tree operation executed) and
23 * is always executed synchronously.
24 */
25
26 /* INCLUDES ******************************************************************/
27
28 #include <ntoskrnl.h>
29 #define NDEBUG
30 #include <debug.h>
31
32 /* GLOBALS *******************************************************************/
33
34 extern ERESOURCE IopDriverLoadResource;
35 extern BOOLEAN PnpSystemInit;
36 extern PDEVICE_NODE IopRootDeviceNode;
37 extern BOOLEAN PnPBootDriversLoaded;
38 extern BOOLEAN PnPBootDriversInitialized;
39
40 #define MAX_DEVICE_ID_LEN 200
41 #define MAX_SEPARATORS_INSTANCEID 0
42 #define MAX_SEPARATORS_DEVICEID 1
43
44 /* DATA **********************************************************************/
45
46 LIST_ENTRY IopDeviceActionRequestList;
47 WORK_QUEUE_ITEM IopDeviceActionWorkItem;
48 BOOLEAN IopDeviceActionInProgress;
49 KSPIN_LOCK IopDeviceActionLock;
50 KEVENT PiEnumerationFinished;
51 static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
52
53 /* TYPES *********************************************************************/
54
55 typedef struct _DEVICE_ACTION_REQUEST
56 {
57 LIST_ENTRY RequestListEntry;
58 PDEVICE_OBJECT DeviceObject;
59 PKEVENT CompletionEvent;
60 NTSTATUS *CompletionStatus;
61 DEVICE_ACTION Action;
62 } DEVICE_ACTION_REQUEST, *PDEVICE_ACTION_REQUEST;
63
64 typedef enum _ADD_DEV_DRIVER_TYPE
65 {
66 LowerFilter,
67 LowerClassFilter,
68 DeviceDriver,
69 UpperFilter,
70 UpperClassFilter
71 } ADD_DEV_DRIVER_TYPE;
72
73 typedef struct _ADD_DEV_DRIVERS_LIST
74 {
75 LIST_ENTRY ListEntry;
76 PDRIVER_OBJECT DriverObject;
77 ADD_DEV_DRIVER_TYPE DriverType;
78 } ADD_DEV_DRIVERS_LIST, *PADD_DEV_DRIVERS_LIST;
79
80 typedef struct _ATTACH_FILTER_DRIVERS_CONTEXT
81 {
82 ADD_DEV_DRIVER_TYPE DriverType;
83 PDEVICE_NODE DeviceNode;
84 PLIST_ENTRY DriversListHead;
85 } ATTACH_FILTER_DRIVERS_CONTEXT, *PATTACH_FILTER_DRIVERS_CONTEXT;
86
87 /* FUNCTIONS *****************************************************************/
88
89 PDEVICE_OBJECT
90 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance);
91
92 NTSTATUS
93 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode, PUNICODE_STRING ParentIdPrefix);
94
95 USHORT
96 NTAPI
97 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid);
98
99 NTSTATUS
100 IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode);
101
102 VOID
103 NTAPI
104 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode);
105
106 static
107 VOID
108 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject);
109
110 static
111 NTSTATUS
112 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force);
113
114 static
115 NTSTATUS
116 IopSetServiceEnumData(
117 _In_ PDEVICE_NODE DeviceNode,
118 _In_ HANDLE InstanceHandle);
119
120 static
121 BOOLEAN
IopValidateID(_In_ PWCHAR Id,_In_ BUS_QUERY_ID_TYPE QueryType)122 IopValidateID(
123 _In_ PWCHAR Id,
124 _In_ BUS_QUERY_ID_TYPE QueryType)
125 {
126 PWCHAR PtrChar;
127 PWCHAR StringEnd;
128 WCHAR Char;
129 ULONG SeparatorsCount = 0;
130 PWCHAR PtrPrevChar = NULL;
131 ULONG MaxSeparators;
132 BOOLEAN IsMultiSz;
133
134 PAGED_CODE();
135
136 switch (QueryType)
137 {
138 case BusQueryDeviceID:
139 MaxSeparators = MAX_SEPARATORS_DEVICEID;
140 IsMultiSz = FALSE;
141 break;
142 case BusQueryInstanceID:
143 MaxSeparators = MAX_SEPARATORS_INSTANCEID;
144 IsMultiSz = FALSE;
145 break;
146
147 case BusQueryHardwareIDs:
148 case BusQueryCompatibleIDs:
149 MaxSeparators = MAX_SEPARATORS_DEVICEID;
150 IsMultiSz = TRUE;
151 break;
152
153 default:
154 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
155 return FALSE;
156 }
157
158 StringEnd = Id + MAX_DEVICE_ID_LEN;
159
160 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
161 {
162 Char = *PtrChar;
163
164 if (Char == UNICODE_NULL)
165 {
166 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
167 {
168 if (MaxSeparators == SeparatorsCount || IsMultiSz)
169 {
170 return TRUE;
171 }
172
173 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
174 SeparatorsCount, MaxSeparators);
175 goto ErrorExit;
176 }
177
178 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
179 PtrPrevChar = PtrChar;
180 SeparatorsCount = 0;
181 }
182 else if (Char < ' ' || Char > 0x7F || Char == ',')
183 {
184 DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
185 goto ErrorExit;
186 }
187 else if (Char == ' ')
188 {
189 *PtrChar = '_';
190 }
191 else if (Char == '\\')
192 {
193 SeparatorsCount++;
194
195 if (SeparatorsCount > MaxSeparators)
196 {
197 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
198 SeparatorsCount, MaxSeparators);
199 goto ErrorExit;
200 }
201 }
202 }
203
204 DPRINT1("IopValidateID: Not terminated ID\n");
205
206 ErrorExit:
207 // FIXME logging
208 return FALSE;
209 }
210
211 static
212 NTSTATUS
IopCreateDeviceInstancePath(_In_ PDEVICE_NODE DeviceNode,_Out_ PUNICODE_STRING InstancePath)213 IopCreateDeviceInstancePath(
214 _In_ PDEVICE_NODE DeviceNode,
215 _Out_ PUNICODE_STRING InstancePath)
216 {
217 IO_STATUS_BLOCK IoStatusBlock;
218 UNICODE_STRING DeviceId;
219 UNICODE_STRING InstanceId;
220 IO_STACK_LOCATION Stack;
221 NTSTATUS Status;
222 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
223 DEVICE_CAPABILITIES DeviceCapabilities;
224 BOOLEAN IsValidID;
225
226 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
227
228 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
229 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
230 &IoStatusBlock,
231 IRP_MN_QUERY_ID,
232 &Stack);
233 if (!NT_SUCCESS(Status))
234 {
235 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
236 return Status;
237 }
238
239 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID);
240
241 if (!IsValidID)
242 {
243 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
244 }
245
246 /* Save the device id string */
247 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information);
248
249 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
250
251 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
252 if (!NT_SUCCESS(Status))
253 {
254 if (Status != STATUS_NOT_SUPPORTED)
255 {
256 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
257 }
258 RtlFreeUnicodeString(&DeviceId);
259 return Status;
260 }
261
262 /* This bit is only check after enumeration */
263 if (DeviceCapabilities.HardwareDisabled)
264 {
265 /* FIXME: Cleanup device */
266 RtlFreeUnicodeString(&DeviceId);
267 return STATUS_PLUGPLAY_NO_DEVICE;
268 }
269
270 if (!DeviceCapabilities.UniqueID)
271 {
272 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
273 DPRINT("Instance ID is not unique\n");
274 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
275 if (!NT_SUCCESS(Status))
276 {
277 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
278 RtlFreeUnicodeString(&DeviceId);
279 return Status;
280 }
281 }
282
283 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
284
285 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
286 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
287 &IoStatusBlock,
288 IRP_MN_QUERY_ID,
289 &Stack);
290 if (!NT_SUCCESS(Status))
291 {
292 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
293 ASSERT(IoStatusBlock.Information == 0);
294 }
295
296 if (IoStatusBlock.Information)
297 {
298 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID);
299
300 if (!IsValidID)
301 {
302 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
303 }
304 }
305
306 RtlInitUnicodeString(&InstanceId,
307 (PWSTR)IoStatusBlock.Information);
308
309 InstancePath->Length = 0;
310 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
311 ParentIdPrefix.Length +
312 InstanceId.Length +
313 sizeof(UNICODE_NULL);
314 if (ParentIdPrefix.Length && InstanceId.Length)
315 {
316 InstancePath->MaximumLength += sizeof(WCHAR);
317 }
318
319 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
320 InstancePath->MaximumLength,
321 TAG_IO);
322 if (!InstancePath->Buffer)
323 {
324 RtlFreeUnicodeString(&InstanceId);
325 RtlFreeUnicodeString(&ParentIdPrefix);
326 RtlFreeUnicodeString(&DeviceId);
327 return STATUS_INSUFFICIENT_RESOURCES;
328 }
329
330 /* Start with the device id */
331 RtlCopyUnicodeString(InstancePath, &DeviceId);
332 RtlAppendUnicodeToString(InstancePath, L"\\");
333
334 /* Add information from parent bus device to InstancePath */
335 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
336 if (ParentIdPrefix.Length && InstanceId.Length)
337 {
338 RtlAppendUnicodeToString(InstancePath, L"&");
339 }
340
341 /* Finally, add the id returned by the driver stack */
342 RtlAppendUnicodeStringToString(InstancePath, &InstanceId);
343
344 /*
345 * FIXME: Check for valid characters, if there is invalid characters
346 * then bugcheck
347 */
348
349 RtlFreeUnicodeString(&InstanceId);
350 RtlFreeUnicodeString(&DeviceId);
351 RtlFreeUnicodeString(&ParentIdPrefix);
352
353 return STATUS_SUCCESS;
354 }
355
356 /**
357 * @brief Loads and/or returns the driver associated with the registry entry if the driver
358 * is enabled. In case of an error, sets up a corresponding Problem to the DeviceNode
359 */
360 static
361 NTSTATUS
362 NTAPI
PiAttachFilterDriversCallback(PWSTR ValueName,ULONG ValueType,PVOID ValueData,ULONG ValueLength,PVOID Ctx,PVOID EntryContext)363 PiAttachFilterDriversCallback(
364 PWSTR ValueName,
365 ULONG ValueType,
366 PVOID ValueData,
367 ULONG ValueLength,
368 PVOID Ctx,
369 PVOID EntryContext)
370 {
371 PATTACH_FILTER_DRIVERS_CONTEXT context = Ctx;
372 PDRIVER_OBJECT DriverObject;
373 NTSTATUS Status;
374 BOOLEAN loadDrivers = (BOOLEAN)(ULONG_PTR)EntryContext;
375
376 PAGED_CODE();
377
378 // No filter value present
379 if (ValueType != REG_SZ)
380 return STATUS_SUCCESS;
381
382 if (ValueLength <= sizeof(WCHAR))
383 return STATUS_OBJECT_NAME_NOT_FOUND;
384
385 // open the service registry key
386 UNICODE_STRING serviceName = { .Length = 0 }, servicesKeyName;
387 RtlInitUnicodeString(&serviceName, ValueData);
388 RtlInitUnicodeString(&servicesKeyName, ServicesKeyName);
389
390 HANDLE ccsServicesHandle, serviceHandle = NULL;
391
392 Status = IopOpenRegistryKeyEx(&ccsServicesHandle, NULL, &servicesKeyName, KEY_READ);
393 if (!NT_SUCCESS(Status))
394 {
395 DPRINT1("Failed to open a registry key for \"%wZ\" (status %x)\n", &serviceName, Status);
396 return Status;
397 }
398
399 Status = IopOpenRegistryKeyEx(&serviceHandle, ccsServicesHandle, &serviceName, KEY_READ);
400 ZwClose(ccsServicesHandle);
401 if (!NT_SUCCESS(Status))
402 {
403 DPRINT1("Failed to open a registry key for \"%wZ\" (status %x)\n", &serviceName, Status);
404 return Status;
405 }
406
407 PADD_DEV_DRIVERS_LIST driverEntry = ExAllocatePoolWithTag(PagedPool,
408 sizeof(*driverEntry),
409 TAG_PNP_DEVACTION);
410
411 if (!driverEntry)
412 {
413 DPRINT1("Failed to allocate driverEntry for \"%wZ\"\n", &serviceName);
414 ZwClose(serviceHandle);
415 return STATUS_INSUFFICIENT_RESOURCES;
416 }
417
418 // check if the driver is disabled
419 PKEY_VALUE_FULL_INFORMATION kvInfo;
420 SERVICE_LOAD_TYPE startType = DisableLoad;
421
422 Status = IopGetRegistryValue(serviceHandle, L"Start", &kvInfo);
423 if (NT_SUCCESS(Status))
424 {
425 if (kvInfo->Type == REG_DWORD)
426 {
427 RtlMoveMemory(&startType,
428 (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
429 sizeof(startType));
430 }
431
432 ExFreePool(kvInfo);
433 }
434
435 // TODO: take into account other start types (like SERVICE_DEMAND_START)
436 if (startType >= DisableLoad)
437 {
438 if (!(context->DeviceNode->Flags & DNF_HAS_PROBLEM))
439 {
440 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_DISABLED_SERVICE);
441 }
442
443 DPRINT("Service \"%wZ\" is disabled (start type %u)\n", &serviceName, startType);
444 Status = STATUS_UNSUCCESSFUL;
445 goto Cleanup;
446 }
447
448 // check if the driver is already loaded
449 UNICODE_STRING driverName;
450 Status = IopGetDriverNames(serviceHandle, &driverName, NULL);
451 if (!NT_SUCCESS(Status))
452 {
453 DPRINT1("Unable to obtain the driver name for \"%wZ\"\n", &serviceName);
454 goto Cleanup;
455 }
456
457 // try to open it
458 Status = ObReferenceObjectByName(&driverName,
459 OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
460 NULL, /* PassedAccessState */
461 0, /* DesiredAccess */
462 IoDriverObjectType,
463 KernelMode,
464 NULL, /* ParseContext */
465 (PVOID*)&DriverObject);
466 RtlFreeUnicodeString(&driverName);
467
468 // the driver was not probably loaded, try to load
469 if (!NT_SUCCESS(Status))
470 {
471 if (loadDrivers)
472 {
473 Status = IopLoadDriver(serviceHandle, &DriverObject);
474 }
475 else
476 {
477 DPRINT("Service \"%wZ\" will not be loaded now\n", &serviceName);
478 // return failure, the driver will be loaded later (in a subsequent call)
479 Status = STATUS_UNSUCCESSFUL;
480 goto Cleanup;
481 }
482 }
483
484 if (NT_SUCCESS(Status))
485 {
486 driverEntry->DriverObject = DriverObject;
487 driverEntry->DriverType = context->DriverType;
488 InsertTailList(context->DriversListHead, &driverEntry->ListEntry);
489 ZwClose(serviceHandle);
490 return STATUS_SUCCESS;
491 }
492 else
493 {
494 if (!(context->DeviceNode->Flags & DNF_HAS_PROBLEM))
495 {
496 switch (Status)
497 {
498 case STATUS_INSUFFICIENT_RESOURCES:
499 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_OUT_OF_MEMORY);
500 break;
501 case STATUS_FAILED_DRIVER_ENTRY:
502 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_FAILED_DRIVER_ENTRY);
503 break;
504 case STATUS_ILL_FORMED_SERVICE_ENTRY:
505 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_DRIVER_SERVICE_KEY_INVALID);
506 break;
507 default:
508 PiSetDevNodeProblem(context->DeviceNode, CM_PROB_DRIVER_FAILED_LOAD);
509 break;
510 }
511 }
512
513 DPRINT1("Failed to load driver \"%wZ\" for %wZ (status %x)\n",
514 &serviceName, &context->DeviceNode->InstancePath, Status);
515 }
516
517 Cleanup:
518 ExFreePoolWithTag(driverEntry, TAG_PNP_DEVACTION);
519 if (serviceHandle)
520 {
521 ZwClose(serviceHandle);
522 }
523 return Status;
524 }
525
526
527 /**
528 * @brief Calls PiAttachFilterDriversCallback for filter drivers (if any)
529 */
530 static
531 NTSTATUS
PiAttachFilterDrivers(PLIST_ENTRY DriversListHead,PDEVICE_NODE DeviceNode,HANDLE EnumSubKey,HANDLE ClassKey,BOOLEAN Lower,BOOLEAN LoadDrivers)532 PiAttachFilterDrivers(
533 PLIST_ENTRY DriversListHead,
534 PDEVICE_NODE DeviceNode,
535 HANDLE EnumSubKey,
536 HANDLE ClassKey,
537 BOOLEAN Lower,
538 BOOLEAN LoadDrivers)
539 {
540 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
541 ATTACH_FILTER_DRIVERS_CONTEXT routineContext;
542 NTSTATUS Status;
543
544 PAGED_CODE();
545
546 routineContext.DriversListHead = DriversListHead;
547 routineContext.DeviceNode = DeviceNode;
548
549 // First add device filters
550 routineContext.DriverType = Lower ? LowerFilter : UpperFilter;
551 QueryTable[0] = (RTL_QUERY_REGISTRY_TABLE){
552 .QueryRoutine = PiAttachFilterDriversCallback,
553 .Name = Lower ? L"LowerFilters" : L"UpperFilters",
554 .DefaultType = REG_NONE,
555 .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
556 };
557
558 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
559 (PWSTR)EnumSubKey,
560 QueryTable,
561 &routineContext,
562 NULL);
563 if (ClassKey == NULL)
564 {
565 return Status;
566 }
567
568 // Then add device class filters
569 routineContext.DriverType = Lower ? LowerClassFilter : UpperClassFilter;
570 QueryTable[0] = (RTL_QUERY_REGISTRY_TABLE){
571 .QueryRoutine = PiAttachFilterDriversCallback,
572 .Name = Lower ? L"LowerFilters" : L"UpperFilters",
573 .DefaultType = REG_NONE,
574 .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
575 };
576
577 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
578 (PWSTR)ClassKey,
579 QueryTable,
580 &routineContext,
581 NULL);
582 return Status;
583 }
584
585 /**
586 * @brief Loads all drivers for a device node (actual service and filters)
587 * and calls their AddDevice routine
588 *
589 * @param[in] DeviceNode The device node
590 * @param[in] LoadDrivers Whether to load drivers if they are not loaded yet
591 * (used when storage subsystem is not yet initialized)
592 */
593 static
594 NTSTATUS
PiCallDriverAddDevice(_In_ PDEVICE_NODE DeviceNode,_In_ BOOLEAN LoadDrivers)595 PiCallDriverAddDevice(
596 _In_ PDEVICE_NODE DeviceNode,
597 _In_ BOOLEAN LoadDrivers)
598 {
599 NTSTATUS Status;
600 HANDLE EnumRootKey, SubKey;
601 HANDLE ClassKey = NULL;
602 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
603 static UNICODE_STRING ccsControlClass =
604 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
605 PKEY_VALUE_FULL_INFORMATION kvInfo = NULL;
606
607 PAGED_CODE();
608
609 // open the enumeration root key
610 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL, &EnumRoot, KEY_READ);
611 if (!NT_SUCCESS(Status))
612 {
613 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &EnumRoot, Status);
614 return Status;
615 }
616
617 // open an instance subkey
618 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey, &DeviceNode->InstancePath, KEY_READ);
619 ZwClose(EnumRootKey);
620 if (!NT_SUCCESS(Status))
621 {
622 DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n",
623 &DeviceNode->InstancePath, Status);
624 return Status;
625 }
626
627 // try to get the class GUID of an instance and its registry key
628 Status = IopGetRegistryValue(SubKey, REGSTR_VAL_CLASSGUID, &kvInfo);
629 if (NT_SUCCESS(Status))
630 {
631 if (kvInfo->Type == REG_SZ && kvInfo->DataLength > sizeof(WCHAR))
632 {
633 UNICODE_STRING classGUID = {
634 .MaximumLength = kvInfo->DataLength,
635 .Length = kvInfo->DataLength - sizeof(UNICODE_NULL),
636 .Buffer = (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset)
637 };
638 HANDLE ccsControlHandle;
639
640 Status = IopOpenRegistryKeyEx(&ccsControlHandle, NULL, &ccsControlClass, KEY_READ);
641 if (!NT_SUCCESS(Status))
642 {
643 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n",
644 &ccsControlClass, Status);
645 }
646 else
647 {
648 // open the CCS\Control\Class\<ClassGUID> key
649 Status = IopOpenRegistryKeyEx(&ClassKey, ccsControlHandle, &classGUID, KEY_READ);
650 ZwClose(ccsControlHandle);
651 if (!NT_SUCCESS(Status))
652 {
653 DPRINT1("Failed to open class key \"%wZ\" (status %x)\n", &classGUID, Status);
654 }
655 }
656
657 if (ClassKey)
658 {
659 // Check the Properties key of a class too
660 // Windows fills some device properties from this key (which is protected)
661 // TODO: add the device properties from this key
662
663 UNICODE_STRING properties = RTL_CONSTANT_STRING(REGSTR_KEY_DEVICE_PROPERTIES);
664 HANDLE propertiesHandle;
665
666 Status = IopOpenRegistryKeyEx(&propertiesHandle, ClassKey, &properties, KEY_READ);
667 if (!NT_SUCCESS(Status))
668 {
669 DPRINT("Properties key failed to open for \"%wZ\" (status %x)\n",
670 &classGUID, Status);
671 }
672 else
673 {
674 ZwClose(propertiesHandle);
675 }
676 }
677 }
678
679 ExFreePool(kvInfo);
680 }
681
682 // the driver loading order:
683 // 1. LowerFilters
684 // 2. LowerClassFilters
685 // 3. Device driver (only one service!)
686 // 4. UpperFilters
687 // 5. UpperClassFilters
688
689 LIST_ENTRY drvListHead;
690 InitializeListHead(&drvListHead);
691
692 // lower (class) filters
693 Status = PiAttachFilterDrivers(&drvListHead, DeviceNode, SubKey, ClassKey, TRUE, LoadDrivers);
694 if (!NT_SUCCESS(Status))
695 {
696 goto Cleanup;
697 }
698
699 ATTACH_FILTER_DRIVERS_CONTEXT routineContext = {
700 .DriversListHead = &drvListHead,
701 .DriverType = DeviceDriver,
702 .DeviceNode = DeviceNode
703 };
704
705 RTL_QUERY_REGISTRY_TABLE queryTable[2] = {{
706 .QueryRoutine = PiAttachFilterDriversCallback,
707 .Name = L"Service",
708 .Flags = RTL_QUERY_REGISTRY_REQUIRED,
709 .DefaultType = REG_SZ, // REG_MULTI_SZ is not allowed here
710 .DefaultData = L"",
711 .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
712 },};
713
714 // device driver
715 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
716 (PWSTR)SubKey,
717 queryTable,
718 &routineContext,
719 NULL);
720 if (NT_SUCCESS(Status))
721 {
722 // do nothing
723 }
724 // if a driver is not found, but a device allows raw access -> proceed
725 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND &&
726 (DeviceNode->CapabilityFlags & 0x00000040)) // CM_DEVCAP_RAWDEVICEOK
727 {
728 // add a dummy entry to the drivers list (need for later processing)
729 PADD_DEV_DRIVERS_LIST driverEntry = ExAllocatePoolZero(PagedPool,
730 sizeof(*driverEntry),
731 TAG_PNP_DEVACTION);
732 driverEntry->DriverType = DeviceDriver;
733 InsertTailList(&drvListHead, &driverEntry->ListEntry);
734 DPRINT("No service for \"%wZ\" (RawDeviceOK)\n", &DeviceNode->InstancePath);
735 }
736 else
737 {
738 if (Status == STATUS_OBJECT_TYPE_MISMATCH && !(DeviceNode->Flags & DNF_HAS_PROBLEM))
739 {
740 PiSetDevNodeProblem(DeviceNode, CM_PROB_REGISTRY);
741 }
742 DPRINT("No service for \"%wZ\" (loadDrv: %u)\n", &DeviceNode->InstancePath, LoadDrivers);
743 goto Cleanup;
744 }
745
746 // upper (class) filters
747 Status = PiAttachFilterDrivers(&drvListHead, DeviceNode, SubKey, ClassKey, FALSE, LoadDrivers);
748 if (!NT_SUCCESS(Status))
749 {
750 goto Cleanup;
751 }
752
753 // finally loop through the stack and call AddDevice for every driver
754 for (PLIST_ENTRY listEntry = drvListHead.Flink;
755 listEntry != &drvListHead;
756 listEntry = listEntry->Flink)
757 {
758 PADD_DEV_DRIVERS_LIST driverEntry;
759 driverEntry = CONTAINING_RECORD(listEntry, ADD_DEV_DRIVERS_LIST, ListEntry);
760 PDRIVER_OBJECT driverObject = driverEntry->DriverObject;
761
762 // FIXME: ReactOS is not quite ready for this assert
763 // (legacy drivers should not have AddDevice routine)
764 // ASSERT(!(DriverObject->Flags & DRVO_LEGACY_DRIVER));
765
766 if (driverObject && driverObject->DriverExtension->AddDevice)
767 {
768 Status = driverObject->DriverExtension->AddDevice(driverEntry->DriverObject,
769 DeviceNode->PhysicalDeviceObject);
770 }
771 else if (driverObject == NULL)
772 {
773 // valid only for DeviceDriver
774 ASSERT(driverEntry->DriverType == DeviceDriver);
775 ASSERT(DeviceNode->CapabilityFlags & 0x00000040); // CM_DEVCAP_RAWDEVICEOK
776 Status = STATUS_SUCCESS;
777 }
778 else
779 {
780 // HACK: the driver doesn't have a AddDevice routine. We shouldn't be here,
781 // but ReactOS' PnP stack is not that correct yet
782 DeviceNode->Flags |= DNF_LEGACY_DRIVER;
783 Status = STATUS_UNSUCCESSFUL;
784 }
785
786 // for filter drivers we don't care about the AddDevice result
787 if (driverEntry->DriverType == DeviceDriver)
788 {
789 if (NT_SUCCESS(Status))
790 {
791 PDEVICE_OBJECT fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
792
793 // HACK: Check if we have a ACPI device (needed for power management)
794 if (fdo->DeviceType == FILE_DEVICE_ACPI)
795 {
796 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
797
798 // There can be only one system power device
799 if (!SystemPowerDeviceNodeCreated)
800 {
801 PopSystemPowerDeviceNode = DeviceNode;
802 ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject);
803 SystemPowerDeviceNodeCreated = TRUE;
804 }
805 }
806
807 ObDereferenceObject(fdo);
808 PiSetDevNodeState(DeviceNode, DeviceNodeDriversAdded);
809 }
810 else
811 {
812 // lower filters (if already started) will be removed upon this request
813 PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_ADD);
814 PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
815 break;
816 }
817 }
818
819 #if DBG
820 PDEVICE_OBJECT attachedDO = IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject);
821 if (attachedDO->Flags & DO_DEVICE_INITIALIZING)
822 {
823 DPRINT1("DO_DEVICE_INITIALIZING is not cleared on a device 0x%p!\n", attachedDO);
824 }
825 #endif
826 }
827
828 Cleanup:
829 while (!IsListEmpty(&drvListHead))
830 {
831 PLIST_ENTRY listEntry = RemoveHeadList(&drvListHead);
832 PADD_DEV_DRIVERS_LIST driverEntry;
833 driverEntry = CONTAINING_RECORD(listEntry, ADD_DEV_DRIVERS_LIST, ListEntry);
834
835 // drivers which don't have any devices (in case of failure) will be cleaned up
836 if (driverEntry->DriverObject)
837 {
838 ObDereferenceObject(driverEntry->DriverObject);
839 }
840 ExFreePoolWithTag(driverEntry, TAG_PNP_DEVACTION);
841 }
842
843 ZwClose(SubKey);
844 if (ClassKey != NULL)
845 {
846 ZwClose(ClassKey);
847 }
848
849 return Status;
850 }
851
852 NTSTATUS
853 NTAPI
IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,PDEVICE_CAPABILITIES DeviceCaps)854 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
855 PDEVICE_CAPABILITIES DeviceCaps)
856 {
857 IO_STATUS_BLOCK StatusBlock;
858 IO_STACK_LOCATION Stack;
859 NTSTATUS Status;
860 HANDLE InstanceKey;
861 UNICODE_STRING ValueName;
862
863 /* Set up the Header */
864 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
865 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
866 DeviceCaps->Version = 1;
867 DeviceCaps->Address = -1;
868 DeviceCaps->UINumber = -1;
869
870 /* Set up the Stack */
871 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
872 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
873
874 /* Send the IRP */
875 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
876 &StatusBlock,
877 IRP_MN_QUERY_CAPABILITIES,
878 &Stack);
879 if (!NT_SUCCESS(Status))
880 {
881 if (Status != STATUS_NOT_SUPPORTED)
882 {
883 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status);
884 }
885 return Status;
886 }
887
888 /* Map device capabilities to capability flags */
889 DeviceNode->CapabilityFlags = 0;
890 if (DeviceCaps->LockSupported)
891 DeviceNode->CapabilityFlags |= 0x00000001; // CM_DEVCAP_LOCKSUPPORTED
892
893 if (DeviceCaps->EjectSupported)
894 DeviceNode->CapabilityFlags |= 0x00000002; // CM_DEVCAP_EJECTSUPPORTED
895
896 if (DeviceCaps->Removable)
897 DeviceNode->CapabilityFlags |= 0x00000004; // CM_DEVCAP_REMOVABLE
898
899 if (DeviceCaps->DockDevice)
900 DeviceNode->CapabilityFlags |= 0x00000008; // CM_DEVCAP_DOCKDEVICE
901
902 if (DeviceCaps->UniqueID)
903 DeviceNode->CapabilityFlags |= 0x00000010; // CM_DEVCAP_UNIQUEID
904
905 if (DeviceCaps->SilentInstall)
906 DeviceNode->CapabilityFlags |= 0x00000020; // CM_DEVCAP_SILENTINSTALL
907
908 if (DeviceCaps->RawDeviceOK)
909 DeviceNode->CapabilityFlags |= 0x00000040; // CM_DEVCAP_RAWDEVICEOK
910
911 if (DeviceCaps->SurpriseRemovalOK)
912 DeviceNode->CapabilityFlags |= 0x00000080; // CM_DEVCAP_SURPRISEREMOVALOK
913
914 if (DeviceCaps->HardwareDisabled)
915 DeviceNode->CapabilityFlags |= 0x00000100; // CM_DEVCAP_HARDWAREDISABLED
916
917 if (DeviceCaps->NonDynamic)
918 DeviceNode->CapabilityFlags |= 0x00000200; // CM_DEVCAP_NONDYNAMIC
919
920 if (DeviceCaps->NoDisplayInUI)
921 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
922 else
923 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
924
925 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
926 if (NT_SUCCESS(Status))
927 {
928 /* Set 'Capabilities' value */
929 RtlInitUnicodeString(&ValueName, L"Capabilities");
930 Status = ZwSetValueKey(InstanceKey,
931 &ValueName,
932 0,
933 REG_DWORD,
934 &DeviceNode->CapabilityFlags,
935 sizeof(ULONG));
936
937 /* Set 'UINumber' value */
938 if (DeviceCaps->UINumber != MAXULONG)
939 {
940 RtlInitUnicodeString(&ValueName, L"UINumber");
941 Status = ZwSetValueKey(InstanceKey,
942 &ValueName,
943 0,
944 REG_DWORD,
945 &DeviceCaps->UINumber,
946 sizeof(ULONG));
947 }
948
949 ZwClose(InstanceKey);
950 }
951
952 return Status;
953 }
954
955 static
956 NTSTATUS
IopQueryHardwareIds(PDEVICE_NODE DeviceNode,HANDLE InstanceKey)957 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
958 HANDLE InstanceKey)
959 {
960 IO_STACK_LOCATION Stack;
961 IO_STATUS_BLOCK IoStatusBlock;
962 PWSTR Ptr;
963 UNICODE_STRING ValueName;
964 NTSTATUS Status;
965 ULONG Length, TotalLength;
966 BOOLEAN IsValidID;
967
968 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
969
970 RtlZeroMemory(&Stack, sizeof(Stack));
971 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
972 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
973 &IoStatusBlock,
974 IRP_MN_QUERY_ID,
975 &Stack);
976 if (NT_SUCCESS(Status))
977 {
978 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs);
979
980 if (!IsValidID)
981 {
982 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
983 }
984
985 TotalLength = 0;
986
987 Ptr = (PWSTR)IoStatusBlock.Information;
988 DPRINT("Hardware IDs:\n");
989 while (*Ptr)
990 {
991 DPRINT(" %S\n", Ptr);
992 Length = (ULONG)wcslen(Ptr) + 1;
993
994 Ptr += Length;
995 TotalLength += Length;
996 }
997 DPRINT("TotalLength: %hu\n", TotalLength);
998 DPRINT("\n");
999
1000 RtlInitUnicodeString(&ValueName, L"HardwareID");
1001 Status = ZwSetValueKey(InstanceKey,
1002 &ValueName,
1003 0,
1004 REG_MULTI_SZ,
1005 (PVOID)IoStatusBlock.Information,
1006 (TotalLength + 1) * sizeof(WCHAR));
1007 if (!NT_SUCCESS(Status))
1008 {
1009 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1010 }
1011 }
1012 else
1013 {
1014 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1015 }
1016
1017 return Status;
1018 }
1019
1020 static
1021 NTSTATUS
IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,HANDLE InstanceKey)1022 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
1023 HANDLE InstanceKey)
1024 {
1025 IO_STACK_LOCATION Stack;
1026 IO_STATUS_BLOCK IoStatusBlock;
1027 PWSTR Ptr;
1028 UNICODE_STRING ValueName;
1029 NTSTATUS Status;
1030 ULONG Length, TotalLength;
1031 BOOLEAN IsValidID;
1032
1033 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1034
1035 RtlZeroMemory(&Stack, sizeof(Stack));
1036 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1037 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1038 &IoStatusBlock,
1039 IRP_MN_QUERY_ID,
1040 &Stack);
1041 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1042 {
1043 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs);
1044
1045 if (!IsValidID)
1046 {
1047 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
1048 }
1049
1050 TotalLength = 0;
1051
1052 Ptr = (PWSTR)IoStatusBlock.Information;
1053 DPRINT("Compatible IDs:\n");
1054 while (*Ptr)
1055 {
1056 DPRINT(" %S\n", Ptr);
1057 Length = (ULONG)wcslen(Ptr) + 1;
1058
1059 Ptr += Length;
1060 TotalLength += Length;
1061 }
1062 DPRINT("TotalLength: %hu\n", TotalLength);
1063 DPRINT("\n");
1064
1065 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1066 Status = ZwSetValueKey(InstanceKey,
1067 &ValueName,
1068 0,
1069 REG_MULTI_SZ,
1070 (PVOID)IoStatusBlock.Information,
1071 (TotalLength + 1) * sizeof(WCHAR));
1072 if (!NT_SUCCESS(Status))
1073 {
1074 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1075 }
1076 }
1077 else
1078 {
1079 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1080 }
1081
1082 return Status;
1083 }
1084
1085 /**
1086 * @brief Sets the DeviceNode's DeviceDesc and LocationInformation registry values
1087 */
1088 VOID
PiSetDevNodeText(_In_ PDEVICE_NODE DeviceNode,_In_ HANDLE InstanceKey)1089 PiSetDevNodeText(
1090 _In_ PDEVICE_NODE DeviceNode,
1091 _In_ HANDLE InstanceKey)
1092 {
1093 PAGED_CODE();
1094
1095 LCID localeId;
1096
1097 // Get the Locale ID
1098 NTSTATUS status = ZwQueryDefaultLocale(FALSE, &localeId);
1099 if (!NT_SUCCESS(status))
1100 {
1101 DPRINT1("ZwQueryDefaultLocale() failed with status %x\n", status);
1102 return;
1103 }
1104
1105 // Step 1: Write the DeviceDesc value if does not exist
1106
1107 UNICODE_STRING valDeviceDesc = RTL_CONSTANT_STRING(L"DeviceDesc");
1108 ULONG len;
1109
1110 status = ZwQueryValueKey(InstanceKey, &valDeviceDesc, KeyValueBasicInformation, NULL, 0, &len);
1111 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1112 {
1113 PWSTR deviceDesc = NULL;
1114 status = PiIrpQueryDeviceText(DeviceNode, localeId, DeviceTextDescription, &deviceDesc);
1115
1116 if (deviceDesc && deviceDesc[0] != UNICODE_NULL)
1117 {
1118 status = ZwSetValueKey(InstanceKey,
1119 &valDeviceDesc,
1120 0,
1121 REG_SZ,
1122 deviceDesc,
1123 ((ULONG)wcslen(deviceDesc) + 1) * sizeof(WCHAR));
1124
1125 if (!NT_SUCCESS(status))
1126 {
1127 DPRINT1("ZwSetValueKey() failed (Status %x)\n", status);
1128 }
1129 }
1130 else
1131 {
1132 // This key is mandatory, so even if the Irp fails, we still write it
1133 UNICODE_STRING unknownDeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
1134 DPRINT("Driver didn't return DeviceDesc (status %x)\n", status);
1135
1136 status = ZwSetValueKey(InstanceKey,
1137 &valDeviceDesc,
1138 0,
1139 REG_SZ,
1140 unknownDeviceDesc.Buffer,
1141 unknownDeviceDesc.MaximumLength);
1142 if (!NT_SUCCESS(status))
1143 {
1144 DPRINT1("ZwSetValueKey() failed (Status %x)\n", status);
1145 }
1146 }
1147
1148 if (deviceDesc)
1149 {
1150 ExFreePoolWithTag(deviceDesc, 0);
1151 }
1152 }
1153
1154 // Step 2: LocaltionInformation is overwritten unconditionally
1155
1156 PWSTR deviceLocationInfo = NULL;
1157 status = PiIrpQueryDeviceText(DeviceNode,
1158 localeId,
1159 DeviceTextLocationInformation,
1160 &deviceLocationInfo);
1161
1162 if (deviceLocationInfo && deviceLocationInfo[0] != UNICODE_NULL)
1163 {
1164 UNICODE_STRING valLocationInfo = RTL_CONSTANT_STRING(L"LocationInformation");
1165
1166 status = ZwSetValueKey(InstanceKey,
1167 &valLocationInfo,
1168 0,
1169 REG_SZ,
1170 deviceLocationInfo,
1171 ((ULONG)wcslen(deviceLocationInfo) + 1) * sizeof(WCHAR));
1172 if (!NT_SUCCESS(status))
1173 {
1174 DPRINT1("ZwSetValueKey() failed (Status %x)\n", status);
1175 }
1176 }
1177
1178 if (deviceLocationInfo)
1179 {
1180 ExFreePoolWithTag(deviceLocationInfo, 0);
1181 }
1182 else
1183 {
1184 DPRINT("Driver didn't return LocationInformation (status %x)\n", status);
1185 }
1186 }
1187
1188 static
1189 NTSTATUS
PiInitializeDevNode(_In_ PDEVICE_NODE DeviceNode)1190 PiInitializeDevNode(
1191 _In_ PDEVICE_NODE DeviceNode)
1192 {
1193 IO_STATUS_BLOCK IoStatusBlock;
1194 NTSTATUS Status;
1195 HANDLE InstanceKey = NULL;
1196 UNICODE_STRING InstancePathU;
1197 PDEVICE_OBJECT OldDeviceObject;
1198
1199 DPRINT("PiProcessNewDevNode(%p)\n", DeviceNode);
1200 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1201
1202 /*
1203 * FIXME: For critical errors, cleanup and disable device, but always
1204 * return STATUS_SUCCESS.
1205 */
1206
1207 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
1208 if (!NT_SUCCESS(Status))
1209 {
1210 if (Status != STATUS_PLUGPLAY_NO_DEVICE)
1211 {
1212 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
1213 }
1214 return Status;
1215 }
1216
1217 /* Verify that this is not a duplicate */
1218 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
1219 if (OldDeviceObject != NULL)
1220 {
1221 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
1222
1223 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
1224 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
1225 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
1226
1227 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
1228 0x01,
1229 (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
1230 (ULONG_PTR)OldDeviceObject,
1231 0);
1232 }
1233
1234 DeviceNode->InstancePath = InstancePathU;
1235
1236 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1237
1238 /*
1239 * Create registry key for the instance id, if it doesn't exist yet
1240 */
1241 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
1242 if (!NT_SUCCESS(Status))
1243 {
1244 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1245
1246 /* We have to return success otherwise we abort the traverse operation */
1247 return STATUS_SUCCESS;
1248 }
1249
1250 IopQueryHardwareIds(DeviceNode, InstanceKey);
1251
1252 IopQueryCompatibleIds(DeviceNode, InstanceKey);
1253
1254 DeviceNode->Flags |= DNF_IDS_QUERIED;
1255
1256 // Set the device's DeviceDesc and LocationInformation fields
1257 PiSetDevNodeText(DeviceNode, InstanceKey);
1258
1259 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1260
1261 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1262 &IoStatusBlock,
1263 IRP_MN_QUERY_BUS_INFORMATION,
1264 NULL);
1265 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1266 {
1267 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
1268
1269 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
1270 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
1271 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
1272 ExFreePoolWithTag(BusInformation, 0);
1273 }
1274 else
1275 {
1276 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1277
1278 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
1279 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
1280 DeviceNode->ChildBusTypeIndex = -1;
1281 }
1282
1283 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1284
1285 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1286 &IoStatusBlock,
1287 IRP_MN_QUERY_RESOURCES,
1288 NULL);
1289 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1290 {
1291 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information;
1292 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
1293 }
1294 else
1295 {
1296 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1297 DeviceNode->BootResources = NULL;
1298 }
1299
1300 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1301
1302 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1303 &IoStatusBlock,
1304 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
1305 NULL);
1306 if (NT_SUCCESS(Status))
1307 {
1308 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
1309 }
1310 else
1311 {
1312 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
1313 DeviceNode->ResourceRequirements = NULL;
1314 }
1315
1316 if (InstanceKey != NULL)
1317 {
1318 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
1319 }
1320
1321 // Try installing a critical device, so its Service key is populated
1322 // then call IopSetServiceEnumData to populate service's Enum key.
1323 // That allows us to start devices during an early boot
1324 IopInstallCriticalDevice(DeviceNode);
1325 IopSetServiceEnumData(DeviceNode, InstanceKey);
1326
1327 ZwClose(InstanceKey);
1328
1329 PiSetDevNodeState(DeviceNode, DeviceNodeInitialized);
1330
1331 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
1332 {
1333 /* Report the device to the user-mode pnp manager */
1334 IopQueueDeviceInstallEvent(&GUID_DEVICE_ENUMERATED,
1335 &DeviceNode->InstancePath);
1336 }
1337
1338 return STATUS_SUCCESS;
1339 }
1340
1341 static
1342 NTSTATUS
IopSetServiceEnumData(_In_ PDEVICE_NODE DeviceNode,_In_ HANDLE InstanceHandle)1343 IopSetServiceEnumData(
1344 _In_ PDEVICE_NODE DeviceNode,
1345 _In_ HANDLE InstanceHandle)
1346 {
1347 UNICODE_STRING ServicesKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1348 UNICODE_STRING ServiceKeyName;
1349 UNICODE_STRING EnumKeyName;
1350 UNICODE_STRING ValueName;
1351 UNICODE_STRING ServiceName;
1352 PKEY_VALUE_FULL_INFORMATION KeyValueInformation, kvInfo2;
1353 HANDLE ServiceKey = NULL, ServiceEnumKey = NULL;
1354 ULONG Disposition;
1355 ULONG Count = 0, NextInstance = 0;
1356 WCHAR ValueBuffer[6];
1357 NTSTATUS Status = STATUS_SUCCESS;
1358
1359 // obtain the device node's ServiceName
1360 Status = IopGetRegistryValue(InstanceHandle, L"Service", &kvInfo2);
1361 if (!NT_SUCCESS(Status))
1362 {
1363 return Status;
1364 }
1365
1366 if (kvInfo2->Type != REG_SZ || kvInfo2->DataLength <= sizeof(WCHAR))
1367 {
1368 ExFreePool(kvInfo2);
1369 return STATUS_UNSUCCESSFUL;
1370 }
1371
1372 ServiceName.MaximumLength = kvInfo2->DataLength;
1373 ServiceName.Length = kvInfo2->DataLength - sizeof(UNICODE_NULL);
1374 ServiceName.Buffer = (PVOID)((ULONG_PTR)kvInfo2 + kvInfo2->DataOffset);
1375
1376 DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode);
1377 DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath);
1378 DPRINT("Service: %wZ\n", &ServiceName);
1379
1380 ServiceKeyName.MaximumLength = ServicesKeyPath.Length + ServiceName.Length + sizeof(UNICODE_NULL);
1381 ServiceKeyName.Length = 0;
1382 ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength);
1383 if (ServiceKeyName.Buffer == NULL)
1384 {
1385 DPRINT1("No ServiceKeyName.Buffer!\n");
1386 return STATUS_INSUFFICIENT_RESOURCES;
1387 }
1388
1389 RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath);
1390 RtlAppendUnicodeStringToString(&ServiceKeyName, &ServiceName);
1391
1392 DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName);
1393
1394 Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY);
1395 if (!NT_SUCCESS(Status))
1396 {
1397 goto done;
1398 }
1399
1400 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING,
1401 &ServiceName,
1402 &DeviceNode->ServiceName);
1403 if (!NT_SUCCESS(Status))
1404 {
1405 goto done;
1406 }
1407
1408 RtlInitUnicodeString(&EnumKeyName, L"Enum");
1409 Status = IopCreateRegistryKeyEx(&ServiceEnumKey,
1410 ServiceKey,
1411 &EnumKeyName,
1412 KEY_SET_VALUE,
1413 REG_OPTION_VOLATILE,
1414 &Disposition);
1415 if (NT_SUCCESS(Status))
1416 {
1417 if (Disposition == REG_OPENED_EXISTING_KEY)
1418 {
1419 /* Read the NextInstance value */
1420 Status = IopGetRegistryValue(ServiceEnumKey,
1421 L"Count",
1422 &KeyValueInformation);
1423 if (!NT_SUCCESS(Status))
1424 goto done;
1425
1426 if ((KeyValueInformation->Type == REG_DWORD) &&
1427 (KeyValueInformation->DataLength))
1428 {
1429 /* Read it */
1430 Count = *(PULONG)((ULONG_PTR)KeyValueInformation +
1431 KeyValueInformation->DataOffset);
1432 }
1433
1434 ExFreePool(KeyValueInformation);
1435 KeyValueInformation = NULL;
1436
1437 /* Read the NextInstance value */
1438 Status = IopGetRegistryValue(ServiceEnumKey,
1439 L"NextInstance",
1440 &KeyValueInformation);
1441 if (!NT_SUCCESS(Status))
1442 goto done;
1443
1444 if ((KeyValueInformation->Type == REG_DWORD) &&
1445 (KeyValueInformation->DataLength))
1446 {
1447 NextInstance = *(PULONG)((ULONG_PTR)KeyValueInformation +
1448 KeyValueInformation->DataOffset);
1449 }
1450
1451 ExFreePool(KeyValueInformation);
1452 KeyValueInformation = NULL;
1453 }
1454
1455 /* Set the instance path */
1456 swprintf(ValueBuffer, L"%lu", NextInstance);
1457 RtlInitUnicodeString(&ValueName, ValueBuffer);
1458 Status = ZwSetValueKey(ServiceEnumKey,
1459 &ValueName,
1460 0,
1461 REG_SZ,
1462 DeviceNode->InstancePath.Buffer,
1463 DeviceNode->InstancePath.MaximumLength);
1464 if (!NT_SUCCESS(Status))
1465 goto done;
1466
1467 /* Increment Count and NextInstance */
1468 Count++;
1469 NextInstance++;
1470
1471 /* Set the new Count value */
1472 RtlInitUnicodeString(&ValueName, L"Count");
1473 Status = ZwSetValueKey(ServiceEnumKey,
1474 &ValueName,
1475 0,
1476 REG_DWORD,
1477 &Count,
1478 sizeof(Count));
1479 if (!NT_SUCCESS(Status))
1480 goto done;
1481
1482 /* Set the new NextInstance value */
1483 RtlInitUnicodeString(&ValueName, L"NextInstance");
1484 Status = ZwSetValueKey(ServiceEnumKey,
1485 &ValueName,
1486 0,
1487 REG_DWORD,
1488 &NextInstance,
1489 sizeof(NextInstance));
1490 }
1491
1492 done:
1493 if (ServiceEnumKey != NULL)
1494 ZwClose(ServiceEnumKey);
1495
1496 if (ServiceKey != NULL)
1497 ZwClose(ServiceKey);
1498
1499 ExFreePool(ServiceKeyName.Buffer);
1500 ExFreePool(kvInfo2);
1501
1502 return Status;
1503 }
1504
1505 /**
1506 * @brief Processes the IoInvalidateDeviceState request
1507 *
1508 * Sends IRP_MN_QUERY_PNP_DEVICE_STATE request and sets device node's flags
1509 * according to the result.
1510 * Tree reenumeration should be started upon a successful return of the function.
1511 *
1512 * @todo Do not return STATUS_SUCCESS if nothing is changed.
1513 */
1514 static
1515 NTSTATUS
PiUpdateDeviceState(_In_ PDEVICE_NODE DeviceNode)1516 PiUpdateDeviceState(
1517 _In_ PDEVICE_NODE DeviceNode)
1518 {
1519 PNP_DEVICE_STATE PnPFlags;
1520 NTSTATUS Status;
1521
1522 Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags);
1523 if (!NT_SUCCESS(Status))
1524 {
1525 return Status;
1526 }
1527
1528 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
1529 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
1530 else
1531 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
1532
1533 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
1534 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
1535 else
1536 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
1537
1538 if (PnPFlags & PNP_DEVICE_REMOVED || PnPFlags & PNP_DEVICE_DISABLED)
1539 {
1540 PiSetDevNodeProblem(DeviceNode,
1541 PnPFlags & PNP_DEVICE_DISABLED
1542 ? CM_PROB_HARDWARE_DISABLED
1543 : CM_PROB_DEVICE_NOT_THERE);
1544
1545 PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
1546 }
1547 else if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
1548 {
1549 // Query resource rebalance
1550
1551 if (PnPFlags & PNP_DEVICE_FAILED)
1552 DeviceNode->Flags &= DNF_NON_STOPPED_REBALANCE;
1553 else
1554 DeviceNode->Flags |= DNF_NON_STOPPED_REBALANCE;
1555
1556 // Clear DNF_NO_RESOURCE_REQUIRED just in case (will be set back if needed)
1557 DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
1558
1559 // This will be caught up later by enumeration
1560 DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED;
1561 }
1562 else if (PnPFlags & PNP_DEVICE_FAILED)
1563 {
1564 PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START);
1565 PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval);
1566 }
1567
1568 return STATUS_SUCCESS;
1569 }
1570
1571 static
1572 NTSTATUS
PiStartDeviceFinal(_In_ PDEVICE_NODE DeviceNode)1573 PiStartDeviceFinal(
1574 _In_ PDEVICE_NODE DeviceNode)
1575 {
1576 DEVICE_CAPABILITIES DeviceCapabilities;
1577 NTSTATUS Status;
1578
1579 if (!(DeviceNode->Flags & DNF_IDS_QUERIED))
1580 {
1581 // query ids (for reported devices)
1582 UNICODE_STRING enumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
1583 HANDLE enumRootHandle, instanceHandle;
1584
1585 // open the enumeration root key
1586 Status = IopOpenRegistryKeyEx(&enumRootHandle, NULL, &enumRoot, KEY_READ);
1587 if (!NT_SUCCESS(Status))
1588 {
1589 DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &enumRoot, Status);
1590 return Status;
1591 }
1592
1593 // open an instance subkey
1594 Status = IopOpenRegistryKeyEx(&instanceHandle, enumRootHandle, &DeviceNode->InstancePath, KEY_READ);
1595 ZwClose(enumRootHandle);
1596 if (!NT_SUCCESS(Status))
1597 {
1598 DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n",
1599 &DeviceNode->InstancePath, Status);
1600 return Status;
1601 }
1602
1603 IopQueryHardwareIds(DeviceNode, instanceHandle);
1604 IopQueryCompatibleIds(DeviceNode, instanceHandle);
1605
1606 DeviceNode->Flags |= DNF_IDS_QUERIED;
1607 ZwClose(instanceHandle);
1608 }
1609
1610 // we're about to start - needs enumeration
1611 DeviceNode->Flags |= DNF_REENUMERATE;
1612
1613 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
1614
1615 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1616 if (!NT_SUCCESS(Status))
1617 {
1618 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1619 }
1620
1621 // Query the device state (IRP_MN_QUERY_PNP_DEVICE_STATE)
1622 PiUpdateDeviceState(DeviceNode);
1623
1624 DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode->InstancePath);
1625 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath);
1626
1627 PiSetDevNodeState(DeviceNode, DeviceNodeStarted);
1628
1629 return STATUS_SUCCESS;
1630 }
1631
1632 /* PUBLIC FUNCTIONS **********************************************************/
1633
1634 /**
1635 * @brief Sends one of the remove IRPs to the device stack
1636 *
1637 * If there is a mounted VPB attached to a one of the stack devices, the IRP
1638 * should be send to a VPB's DeviceObject first (which belongs to a FS driver).
1639 * FS driver will then forward it down to the volume device.
1640 * While walking the device stack, the function sets (or unsets) VPB_REMOVE_PENDING flag
1641 * thus blocking all further mounts on a soon-to-be-removed devices
1642 */
1643 static
1644 NTSTATUS
PiIrpSendRemoveCheckVpb(_In_ PDEVICE_OBJECT DeviceObject,_In_ UCHAR MinorFunction)1645 PiIrpSendRemoveCheckVpb(
1646 _In_ PDEVICE_OBJECT DeviceObject,
1647 _In_ UCHAR MinorFunction)
1648 {
1649 KIRQL oldIrql;
1650
1651 ASSERT(MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE ||
1652 MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE ||
1653 MinorFunction == IRP_MN_SURPRISE_REMOVAL ||
1654 MinorFunction == IRP_MN_REMOVE_DEVICE);
1655
1656 PDEVICE_OBJECT vpbDevObj = DeviceObject, targetDevice = DeviceObject;
1657
1658 // walk the device stack down, stop on a first mounted device
1659 do
1660 {
1661 if (vpbDevObj->Vpb)
1662 {
1663 // two locks are needed here
1664 KeWaitForSingleObject(&vpbDevObj->DeviceLock, Executive, KernelMode, FALSE, NULL);
1665 IoAcquireVpbSpinLock(&oldIrql);
1666
1667 if (MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE)
1668 {
1669 vpbDevObj->Vpb->Flags &= ~VPB_REMOVE_PENDING;
1670 }
1671 else
1672 {
1673 vpbDevObj->Vpb->Flags |= VPB_REMOVE_PENDING;
1674 }
1675
1676 BOOLEAN isMounted = (_Bool)(vpbDevObj->Vpb->Flags & VPB_MOUNTED);
1677
1678 if (isMounted)
1679 {
1680 targetDevice = vpbDevObj->Vpb->DeviceObject;
1681 }
1682
1683 IoReleaseVpbSpinLock(oldIrql);
1684 KeSetEvent(&vpbDevObj->DeviceLock, IO_NO_INCREMENT, FALSE);
1685
1686 if (isMounted)
1687 {
1688 break;
1689 }
1690 }
1691
1692 oldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1693 vpbDevObj = vpbDevObj->AttachedDevice;
1694 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, oldIrql);
1695 } while (vpbDevObj);
1696
1697 ASSERT(targetDevice);
1698
1699 PVOID info;
1700 IO_STACK_LOCATION stack = {.MajorFunction = IRP_MJ_PNP, .MinorFunction = MinorFunction};
1701
1702 return IopSynchronousCall(targetDevice, &stack, &info);
1703 }
1704
1705 NTSTATUS
1706 IopUpdateResourceMapForPnPDevice(
1707 IN PDEVICE_NODE DeviceNode);
1708
1709 static
1710 VOID
1711 NTAPI
IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)1712 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
1713 {
1714 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1715
1716 ASSERT(DeviceNode->State == DeviceNodeAwaitingQueuedRemoval);
1717
1718 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
1719 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_REMOVE_DEVICE);
1720
1721 /* Start of HACK: update resources stored in registry, so IopDetectResourceConflict works */
1722 if (DeviceNode->ResourceList)
1723 {
1724 ASSERT(DeviceNode->ResourceListTranslated);
1725 DeviceNode->ResourceList->Count = 0;
1726 DeviceNode->ResourceListTranslated->Count = 0;
1727 IopUpdateResourceMapForPnPDevice(DeviceNode);
1728 }
1729 /* End of HACK */
1730
1731 PiSetDevNodeState(DeviceNode, DeviceNodeRemoved);
1732 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE, DeviceObject, NULL);
1733 LONG_PTR refCount = ObDereferenceObject(DeviceObject);
1734 if (refCount != 0)
1735 {
1736 DPRINT1("Leaking device %wZ, refCount = %d\n", &DeviceNode->InstancePath, (INT32)refCount);
1737 }
1738 }
1739
1740 static
1741 VOID
IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)1742 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
1743 {
1744 /* This function DOES dereference the device objects in all cases */
1745
1746 ULONG i;
1747
1748 for (i = 0; i < DeviceRelations->Count; i++)
1749 {
1750 IopSendRemoveDevice(DeviceRelations->Objects[i]);
1751 DeviceRelations->Objects[i] = NULL;
1752 }
1753
1754 ExFreePool(DeviceRelations);
1755 }
1756
1757 static
1758 VOID
IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)1759 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
1760 {
1761 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
1762 KIRQL OldIrql;
1763
1764 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1765 ChildDeviceNode = ParentDeviceNode->Child;
1766 while (ChildDeviceNode != NULL)
1767 {
1768 NextDeviceNode = ChildDeviceNode->Sibling;
1769 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1770
1771 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
1772
1773 ChildDeviceNode = NextDeviceNode;
1774
1775 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1776 }
1777 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1778 }
1779
1780 static
1781 VOID
1782 NTAPI
IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)1783 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
1784 {
1785 ASSERT(IopGetDeviceNode(DeviceObject)->State == DeviceNodeAwaitingQueuedRemoval);
1786 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
1787 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_SURPRISE_REMOVAL);
1788 }
1789
1790 static
1791 VOID
1792 NTAPI
IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)1793 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
1794 {
1795 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
1796 PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_CANCEL_REMOVE_DEVICE);
1797
1798 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_CANCELLED, DeviceObject, NULL);
1799 }
1800
1801 static
1802 VOID
IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)1803 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
1804 {
1805 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
1806 KIRQL OldIrql;
1807
1808 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1809 ChildDeviceNode = ParentDeviceNode->Child;
1810 while (ChildDeviceNode != NULL)
1811 {
1812 NextDeviceNode = ChildDeviceNode->Sibling;
1813 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1814
1815 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
1816
1817 ChildDeviceNode = NextDeviceNode;
1818
1819 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1820 }
1821 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1822 }
1823
1824 static
1825 VOID
IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)1826 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
1827 {
1828 /* This function DOES dereference the device objects in all cases */
1829
1830 ULONG i;
1831
1832 for (i = 0; i < DeviceRelations->Count; i++)
1833 {
1834 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
1835 ObDereferenceObject(DeviceRelations->Objects[i]);
1836 DeviceRelations->Objects[i] = NULL;
1837 }
1838
1839 ExFreePool(DeviceRelations);
1840 }
1841
1842 static
1843 VOID
IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)1844 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
1845 {
1846 IO_STACK_LOCATION Stack;
1847 IO_STATUS_BLOCK IoStatusBlock;
1848 PDEVICE_RELATIONS DeviceRelations;
1849 NTSTATUS Status;
1850
1851 IopCancelRemoveDevice(DeviceObject);
1852
1853 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
1854
1855 Status = IopInitiatePnpIrp(DeviceObject,
1856 &IoStatusBlock,
1857 IRP_MN_QUERY_DEVICE_RELATIONS,
1858 &Stack);
1859 if (!NT_SUCCESS(Status))
1860 {
1861 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
1862 DeviceRelations = NULL;
1863 }
1864 else
1865 {
1866 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1867 }
1868
1869 if (DeviceRelations)
1870 IopCancelRemoveDeviceRelations(DeviceRelations);
1871 }
1872
1873 static
1874 NTSTATUS
1875 NTAPI
IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)1876 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
1877 {
1878 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1879 NTSTATUS Status;
1880
1881 ASSERT(DeviceNode);
1882
1883 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
1884 &DeviceNode->InstancePath);
1885
1886 Status = PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_QUERY_REMOVE_DEVICE);
1887
1888 PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_QUERY_REMOVE, DeviceObject, NULL);
1889
1890 if (!NT_SUCCESS(Status))
1891 {
1892 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath);
1893 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
1894 &DeviceNode->InstancePath);
1895 }
1896
1897 return Status;
1898 }
1899
1900 static
1901 NTSTATUS
IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode,BOOLEAN Force)1902 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force)
1903 {
1904 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
1905 NTSTATUS Status;
1906 KIRQL OldIrql;
1907
1908 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1909 ChildDeviceNode = ParentDeviceNode->Child;
1910 while (ChildDeviceNode != NULL)
1911 {
1912 NextDeviceNode = ChildDeviceNode->Sibling;
1913 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1914 PiSetDevNodeState(ChildDeviceNode, DeviceNodeAwaitingQueuedRemoval);
1915
1916 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force);
1917 if (!NT_SUCCESS(Status))
1918 {
1919 FailedRemoveDevice = ChildDeviceNode;
1920 goto cleanup;
1921 }
1922
1923 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1924 ChildDeviceNode = NextDeviceNode;
1925 }
1926 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1927
1928 return STATUS_SUCCESS;
1929
1930 cleanup:
1931 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1932 ChildDeviceNode = ParentDeviceNode->Child;
1933 while (ChildDeviceNode != NULL)
1934 {
1935 NextDeviceNode = ChildDeviceNode->Sibling;
1936 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1937
1938 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
1939
1940 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
1941 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
1942 if (ChildDeviceNode == FailedRemoveDevice)
1943 return Status;
1944
1945 ChildDeviceNode = NextDeviceNode;
1946
1947 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1948 }
1949 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1950
1951 return Status;
1952 }
1953
1954 static
1955 NTSTATUS
IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations,BOOLEAN Force)1956 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force)
1957 {
1958 /* This function DOES NOT dereference the device objects on SUCCESS
1959 * but it DOES dereference device objects on FAILURE */
1960
1961 ULONG i, j;
1962 NTSTATUS Status;
1963
1964 for (i = 0; i < DeviceRelations->Count; i++)
1965 {
1966 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force);
1967 if (!NT_SUCCESS(Status))
1968 {
1969 j = i;
1970 goto cleanup;
1971 }
1972 }
1973
1974 return STATUS_SUCCESS;
1975
1976 cleanup:
1977 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
1978 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
1979 for (i = 0; i <= j; i++)
1980 {
1981 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
1982 ObDereferenceObject(DeviceRelations->Objects[i]);
1983 DeviceRelations->Objects[i] = NULL;
1984 }
1985 for (; i < DeviceRelations->Count; i++)
1986 {
1987 ObDereferenceObject(DeviceRelations->Objects[i]);
1988 DeviceRelations->Objects[i] = NULL;
1989 }
1990 ExFreePool(DeviceRelations);
1991
1992 return Status;
1993 }
1994
1995 static
1996 NTSTATUS
IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject,BOOLEAN Force)1997 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force)
1998 {
1999 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2000 IO_STACK_LOCATION Stack;
2001 IO_STATUS_BLOCK IoStatusBlock;
2002 PDEVICE_RELATIONS DeviceRelations;
2003 NTSTATUS Status;
2004
2005 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force)
2006 {
2007 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
2008 return STATUS_UNSUCCESSFUL;
2009 }
2010
2011 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
2012 {
2013 DPRINT1("Removal vetoed by failing the query remove request\n");
2014
2015 IopCancelRemoveDevice(DeviceObject);
2016
2017 return STATUS_UNSUCCESSFUL;
2018 }
2019
2020 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
2021
2022 Status = IopInitiatePnpIrp(DeviceObject,
2023 &IoStatusBlock,
2024 IRP_MN_QUERY_DEVICE_RELATIONS,
2025 &Stack);
2026 if (!NT_SUCCESS(Status))
2027 {
2028 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2029 DeviceRelations = NULL;
2030 }
2031 else
2032 {
2033 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2034 }
2035
2036 if (DeviceRelations)
2037 {
2038 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force);
2039 if (!NT_SUCCESS(Status))
2040 return Status;
2041 }
2042
2043 Status = IopQueryRemoveChildDevices(DeviceNode, Force);
2044 if (!NT_SUCCESS(Status))
2045 {
2046 if (DeviceRelations)
2047 IopCancelRemoveDeviceRelations(DeviceRelations);
2048 return Status;
2049 }
2050
2051 if (DeviceRelations)
2052 IopSendRemoveDeviceRelations(DeviceRelations);
2053 IopSendRemoveChildDevices(DeviceNode);
2054
2055 return STATUS_SUCCESS;
2056 }
2057
2058 static
2059 NTSTATUS
IopRemoveDevice(PDEVICE_NODE DeviceNode)2060 IopRemoveDevice(PDEVICE_NODE DeviceNode)
2061 {
2062 NTSTATUS Status;
2063
2064 // This function removes the device subtree, with the root in DeviceNode
2065 // atm everyting is in fact done inside this function, which is completely wrong.
2066 // The right implementation should have a separate removal worker thread and
2067 // properly do device node state transitions
2068
2069 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
2070
2071 BOOLEAN surpriseRemoval = (_Bool)(DeviceNode->Flags & DNF_DEVICE_GONE);
2072
2073 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, surpriseRemoval);
2074
2075 if (surpriseRemoval)
2076 {
2077 IopSendSurpriseRemoval(DeviceNode->PhysicalDeviceObject);
2078 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, &DeviceNode->InstancePath);
2079 }
2080
2081 if (NT_SUCCESS(Status))
2082 {
2083 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
2084 if (surpriseRemoval)
2085 {
2086 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, &DeviceNode->InstancePath);
2087 }
2088 return STATUS_SUCCESS;
2089 }
2090
2091 return Status;
2092 }
2093
2094 static
2095 NTSTATUS
PiEnumerateDevice(_In_ PDEVICE_NODE DeviceNode)2096 PiEnumerateDevice(
2097 _In_ PDEVICE_NODE DeviceNode)
2098 {
2099 PDEVICE_OBJECT ChildDeviceObject;
2100 PDEVICE_NODE ChildDeviceNode;
2101 ULONG i;
2102
2103 // bus relations are already obtained for this device node
2104
2105 if (!NT_SUCCESS(DeviceNode->CompletionStatus))
2106 {
2107 DPRINT("QDR request failed for %wZ, status %x\n",
2108 &DeviceNode->InstancePath, DeviceNode->CompletionStatus);
2109 // treat as if there are no child objects
2110 }
2111
2112 PDEVICE_RELATIONS DeviceRelations = DeviceNode->OverUsed1.PendingDeviceRelations;
2113 DeviceNode->OverUsed1.PendingDeviceRelations = NULL;
2114
2115 // it's acceptable not to have PDOs
2116 if (!DeviceRelations)
2117 {
2118 PiSetDevNodeState(DeviceNode, DeviceNodeStarted);
2119 DPRINT("No PDOs\n");
2120 return STATUS_SUCCESS;
2121 }
2122
2123 // mark children nodes as non-present (those not returned in DR request will be removed)
2124 for (PDEVICE_NODE child = DeviceNode->Child; child != NULL; child = child->Sibling)
2125 {
2126 child->Flags &= ~DNF_ENUMERATED;
2127 }
2128
2129 DPRINT("PiEnumerateDevice: enumerating %u children\n", DeviceRelations->Count);
2130
2131 // create device nodes for all new children and set DNF_ENUMERATED back for old ones
2132 for (i = 0; i < DeviceRelations->Count; i++)
2133 {
2134 ChildDeviceObject = DeviceRelations->Objects[i];
2135 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2136
2137 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2138 if (!ChildDeviceNode)
2139 {
2140 /* One doesn't exist, create it */
2141 ChildDeviceNode = PipAllocateDeviceNode(ChildDeviceObject);
2142 if (ChildDeviceNode)
2143 {
2144 PiInsertDevNode(ChildDeviceNode, DeviceNode);
2145
2146 /* Mark the node as enumerated */
2147 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2148
2149 /* Mark the DO as bus enumerated */
2150 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2151 }
2152 else
2153 {
2154 /* Ignore this DO */
2155 DPRINT1("PipAllocateDeviceNode() failed. Skipping PDO %u\n", i);
2156 ObDereferenceObject(ChildDeviceObject);
2157 }
2158 }
2159 else
2160 {
2161 /* Mark it as enumerated */
2162 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2163 ObDereferenceObject(ChildDeviceObject);
2164 }
2165 }
2166 ExFreePool(DeviceRelations);
2167
2168 // time to remove non-reported devices
2169 for (PDEVICE_NODE child = DeviceNode->Child; child != NULL; child = child->Sibling)
2170 {
2171 if (!(child->Flags & (DNF_ENUMERATED|DNF_DEVICE_GONE)))
2172 {
2173 // this flag indicates that this is a surprise removal
2174 child->Flags |= DNF_DEVICE_GONE;
2175 PiSetDevNodeState(child, DeviceNodeAwaitingQueuedRemoval);
2176 }
2177 }
2178
2179 PiSetDevNodeState(DeviceNode, DeviceNodeStarted);
2180 return STATUS_SUCCESS;
2181 }
2182
2183 static
2184 NTSTATUS
2185 NTAPI
IopSendEject(IN PDEVICE_OBJECT DeviceObject)2186 IopSendEject(IN PDEVICE_OBJECT DeviceObject)
2187 {
2188 IO_STACK_LOCATION Stack;
2189 PVOID Dummy;
2190
2191 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
2192 Stack.MajorFunction = IRP_MJ_PNP;
2193 Stack.MinorFunction = IRP_MN_EJECT;
2194
2195 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
2196 }
2197
2198 /*
2199 * @implemented
2200 */
2201 VOID
2202 NTAPI
IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)2203 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
2204 {
2205 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
2206 PDEVICE_RELATIONS DeviceRelations;
2207 IO_STATUS_BLOCK IoStatusBlock;
2208 IO_STACK_LOCATION Stack;
2209 DEVICE_CAPABILITIES Capabilities;
2210 NTSTATUS Status;
2211
2212 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
2213 &DeviceNode->InstancePath);
2214
2215 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
2216 {
2217 goto cleanup;
2218 }
2219
2220 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
2221
2222 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
2223 &IoStatusBlock,
2224 IRP_MN_QUERY_DEVICE_RELATIONS,
2225 &Stack);
2226 if (!NT_SUCCESS(Status))
2227 {
2228 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2229 DeviceRelations = NULL;
2230 }
2231 else
2232 {
2233 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2234 }
2235
2236 if (DeviceRelations)
2237 {
2238 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE);
2239 if (!NT_SUCCESS(Status))
2240 goto cleanup;
2241 }
2242
2243 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE);
2244 if (!NT_SUCCESS(Status))
2245 {
2246 if (DeviceRelations)
2247 IopCancelRemoveDeviceRelations(DeviceRelations);
2248 goto cleanup;
2249 }
2250
2251 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS)
2252 {
2253 if (DeviceRelations)
2254 IopCancelRemoveDeviceRelations(DeviceRelations);
2255 IopCancelRemoveChildDevices(DeviceNode);
2256 goto cleanup;
2257 }
2258
2259 if (DeviceRelations)
2260 IopSendRemoveDeviceRelations(DeviceRelations);
2261 IopSendRemoveChildDevices(DeviceNode);
2262
2263 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT;
2264 if (Capabilities.EjectSupported)
2265 {
2266 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
2267 {
2268 goto cleanup;
2269 }
2270 }
2271 else
2272 {
2273 // DeviceNode->Flags |= DNF_DISABLED;
2274 }
2275
2276 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
2277 &DeviceNode->InstancePath);
2278
2279 return;
2280
2281 cleanup:
2282 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
2283 &DeviceNode->InstancePath);
2284 }
2285
2286 static
2287 VOID
PiFakeResourceRebalance(_In_ PDEVICE_NODE DeviceNode)2288 PiFakeResourceRebalance(
2289 _In_ PDEVICE_NODE DeviceNode)
2290 {
2291 ASSERT(DeviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED);
2292
2293 PCM_RESOURCE_LIST bootConfig = NULL;
2294 PIO_RESOURCE_REQUIREMENTS_LIST resourceRequirements = NULL;
2295
2296 PiIrpQueryResources(DeviceNode, &bootConfig);
2297 PiIrpQueryResourceRequirements(DeviceNode, &resourceRequirements);
2298
2299 DeviceNode->BootResources = bootConfig;
2300 DeviceNode->ResourceRequirements = resourceRequirements;
2301
2302 if (bootConfig)
2303 {
2304 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
2305 }
2306
2307 DeviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_CHANGED;
2308 }
2309
2310 static
2311 VOID
PiDevNodeStateMachine(_In_ PDEVICE_NODE RootNode)2312 PiDevNodeStateMachine(
2313 _In_ PDEVICE_NODE RootNode)
2314 {
2315 NTSTATUS status;
2316 BOOLEAN doProcessAgain;
2317 PDEVICE_NODE currentNode = RootNode;
2318 PDEVICE_OBJECT referencedObject;
2319
2320 do
2321 {
2322 doProcessAgain = FALSE;
2323
2324 // The device can be removed during processing, but we still need its Parent and Sibling
2325 // links to continue the tree traversal. So keep the link till the and of a cycle
2326 referencedObject = currentNode->PhysicalDeviceObject;
2327 ObReferenceObject(referencedObject);
2328
2329 // Devices with problems are skipped (unless they are not being removed)
2330 if (currentNode->Flags & DNF_HAS_PROBLEM &&
2331 currentNode->State != DeviceNodeAwaitingQueuedRemoval)
2332 {
2333 goto skipEnum;
2334 }
2335
2336 switch (currentNode->State)
2337 {
2338 case DeviceNodeUnspecified: // this state is not used
2339 break;
2340 case DeviceNodeUninitialized:
2341 DPRINT("DeviceNodeUninitialized %wZ\n", ¤tNode->InstancePath);
2342 status = PiInitializeDevNode(currentNode);
2343 doProcessAgain = NT_SUCCESS(status);
2344 break;
2345 case DeviceNodeInitialized:
2346 DPRINT("DeviceNodeInitialized %wZ\n", ¤tNode->InstancePath);
2347 status = PiCallDriverAddDevice(currentNode, PnPBootDriversInitialized);
2348 doProcessAgain = NT_SUCCESS(status);
2349 break;
2350 case DeviceNodeDriversAdded:
2351 DPRINT("DeviceNodeDriversAdded %wZ\n", ¤tNode->InstancePath);
2352 status = IopAssignDeviceResources(currentNode);
2353 doProcessAgain = NT_SUCCESS(status);
2354 break;
2355 case DeviceNodeResourcesAssigned:
2356 DPRINT("DeviceNodeResourcesAssigned %wZ\n", ¤tNode->InstancePath);
2357 // send IRP_MN_START_DEVICE
2358 PiIrpStartDevice(currentNode);
2359
2360 // skip DeviceNodeStartPending, it is probably used for an async IRP_MN_START_DEVICE
2361 PiSetDevNodeState(currentNode, DeviceNodeStartCompletion);
2362 doProcessAgain = TRUE;
2363 break;
2364 case DeviceNodeStartPending: // skipped on XP/2003
2365 break;
2366 case DeviceNodeStartCompletion:
2367 DPRINT("DeviceNodeStartCompletion %wZ\n", ¤tNode->InstancePath);
2368 status = currentNode->CompletionStatus;
2369 doProcessAgain = TRUE;
2370 if (!NT_SUCCESS(status))
2371 {
2372 UINT32 problem = (status == STATUS_PNP_REBOOT_REQUIRED)
2373 ? CM_PROB_NEED_RESTART
2374 : CM_PROB_FAILED_START;
2375
2376 PiSetDevNodeProblem(currentNode, problem);
2377 PiSetDevNodeState(currentNode, DeviceNodeAwaitingQueuedRemoval);
2378 }
2379 else
2380 {
2381 // TODO: IopDoDeferredSetInterfaceState and IopAllocateLegacyBootResources
2382 // are called here too
2383
2384 PiSetDevNodeState(currentNode, DeviceNodeStartPostWork);
2385 }
2386 break;
2387 case DeviceNodeStartPostWork:
2388 DPRINT("DeviceNodeStartPostWork %wZ\n", ¤tNode->InstancePath);
2389 // TODO: inspect the status
2390 status = PiStartDeviceFinal(currentNode);
2391 doProcessAgain = TRUE;
2392 break;
2393 case DeviceNodeStarted:
2394 if (currentNode->Flags & DNF_REENUMERATE)
2395 {
2396 DPRINT("DeviceNodeStarted REENUMERATE %wZ\n", ¤tNode->InstancePath);
2397 currentNode->Flags &= ~DNF_REENUMERATE;
2398 status = PiIrpQueryDeviceRelations(currentNode, BusRelations);
2399
2400 // again, skip DeviceNodeEnumeratePending as with the starting sequence
2401 PiSetDevNodeState(currentNode, DeviceNodeEnumerateCompletion);
2402 doProcessAgain = TRUE;
2403 }
2404 else if (currentNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED)
2405 {
2406 if (currentNode->Flags & DNF_NON_STOPPED_REBALANCE)
2407 {
2408 PiFakeResourceRebalance(currentNode);
2409 currentNode->Flags &= ~DNF_NON_STOPPED_REBALANCE;
2410 }
2411 else
2412 {
2413 PiIrpQueryStopDevice(currentNode);
2414 PiSetDevNodeState(currentNode, DeviceNodeQueryStopped);
2415 }
2416
2417 doProcessAgain = TRUE;
2418 }
2419 break;
2420 case DeviceNodeQueryStopped:
2421 // we're here after sending IRP_MN_QUERY_STOP_DEVICE
2422 status = currentNode->CompletionStatus;
2423 if (NT_SUCCESS(status))
2424 {
2425 PiIrpStopDevice(currentNode);
2426 PiSetDevNodeState(currentNode, DeviceNodeStopped);
2427 }
2428 else
2429 {
2430 PiIrpCancelStopDevice(currentNode);
2431 PiSetDevNodeState(currentNode, DeviceNodeStarted);
2432 }
2433 doProcessAgain = TRUE;
2434 break;
2435 case DeviceNodeStopped:
2436 // TODO: do resource rebalance (not implemented)
2437 PiFakeResourceRebalance(currentNode);
2438
2439 PiSetDevNodeState(currentNode, DeviceNodeDriversAdded);
2440 doProcessAgain = TRUE;
2441 break;
2442 case DeviceNodeRestartCompletion:
2443 break;
2444 case DeviceNodeEnumeratePending: // skipped on XP/2003
2445 break;
2446 case DeviceNodeEnumerateCompletion:
2447 DPRINT("DeviceNodeEnumerateCompletion %wZ\n", ¤tNode->InstancePath);
2448 status = PiEnumerateDevice(currentNode);
2449 doProcessAgain = TRUE;
2450 break;
2451 case DeviceNodeAwaitingQueuedDeletion:
2452 break;
2453 case DeviceNodeAwaitingQueuedRemoval:
2454 DPRINT("DeviceNodeAwaitingQueuedRemoval %wZ\n", ¤tNode->InstancePath);
2455 status = IopRemoveDevice(currentNode);
2456 break;
2457 case DeviceNodeQueryRemoved:
2458 break;
2459 case DeviceNodeRemovePendingCloses:
2460 break;
2461 case DeviceNodeRemoved:
2462 break;
2463 case DeviceNodeDeletePendingCloses:
2464 break;
2465 case DeviceNodeDeleted:
2466 break;
2467 default:
2468 break;
2469 }
2470
2471 skipEnum:
2472 if (!doProcessAgain)
2473 {
2474 KIRQL OldIrql;
2475 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
2476 /* If we have a child, simply go down the tree */
2477 if (currentNode->State != DeviceNodeRemoved && currentNode->Child != NULL)
2478 {
2479 ASSERT(currentNode->Child->Parent == currentNode);
2480 currentNode = currentNode->Child;
2481 }
2482 else
2483 {
2484 while (currentNode != RootNode)
2485 {
2486 /* All children processed -- go sideways */
2487 if (currentNode->Sibling != NULL)
2488 {
2489 ASSERT(currentNode->Sibling->Parent == currentNode->Parent);
2490 currentNode = currentNode->Sibling;
2491 break;
2492 }
2493 else
2494 {
2495 /* We're the last sibling -- go back up */
2496 ASSERT(currentNode->Parent->LastChild == currentNode);
2497 currentNode = currentNode->Parent;
2498 }
2499 /* We already visited the parent and all its children, so keep looking */
2500 }
2501 }
2502 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
2503 }
2504 ObDereferenceObject(referencedObject);
2505 } while (doProcessAgain || currentNode != RootNode);
2506 }
2507
2508 #ifdef DBG
2509 static
2510 PCSTR
ActionToStr(_In_ DEVICE_ACTION Action)2511 ActionToStr(
2512 _In_ DEVICE_ACTION Action)
2513 {
2514 switch (Action)
2515 {
2516 case PiActionEnumDeviceTree:
2517 return "PiActionEnumDeviceTree";
2518 case PiActionEnumRootDevices:
2519 return "PiActionEnumRootDevices";
2520 case PiActionResetDevice:
2521 return "PiActionResetDevice";
2522 case PiActionAddBootDevices:
2523 return "PiActionAddBootDevices";
2524 case PiActionStartDevice:
2525 return "PiActionStartDevice";
2526 case PiActionQueryState:
2527 return "PiActionQueryState";
2528 default:
2529 return "(request unknown)";
2530 }
2531 }
2532 #endif
2533
2534 static
2535 VOID
2536 NTAPI
PipDeviceActionWorker(_In_opt_ PVOID Context)2537 PipDeviceActionWorker(
2538 _In_opt_ PVOID Context)
2539 {
2540 PLIST_ENTRY ListEntry;
2541 PDEVICE_ACTION_REQUEST Request;
2542 KIRQL OldIrql;
2543 PDEVICE_NODE deviceNode;
2544 NTSTATUS status;
2545
2546 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
2547 while (!IsListEmpty(&IopDeviceActionRequestList))
2548 {
2549 ListEntry = RemoveHeadList(&IopDeviceActionRequestList);
2550 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2551 Request = CONTAINING_RECORD(ListEntry, DEVICE_ACTION_REQUEST, RequestListEntry);
2552
2553 ASSERT(Request->DeviceObject);
2554
2555 deviceNode = IopGetDeviceNode(Request->DeviceObject);
2556 ASSERT(deviceNode);
2557
2558 status = STATUS_SUCCESS;
2559
2560 DPRINT("Processing PnP request %p: DeviceObject - %p, Action - %s\n",
2561 Request, Request->DeviceObject, ActionToStr(Request->Action));
2562
2563 switch (Request->Action)
2564 {
2565 case PiActionAddBootDevices:
2566 {
2567 if (deviceNode->State == DeviceNodeInitialized &&
2568 !(deviceNode->Flags & DNF_HAS_PROBLEM))
2569 {
2570 status = PiCallDriverAddDevice(deviceNode, PnPBootDriversInitialized);
2571 }
2572 break;
2573 }
2574 case PiActionEnumRootDevices:
2575 case PiActionEnumDeviceTree:
2576 deviceNode->Flags |= DNF_REENUMERATE;
2577 PiDevNodeStateMachine(deviceNode);
2578 break;
2579
2580 case PiActionResetDevice:
2581 // TODO: the operation is a no-op for everything except removed nodes
2582 // for removed nodes, it returns them back to DeviceNodeUninitialized
2583 if (deviceNode->State == DeviceNodeRemoved)
2584 {
2585 deviceNode->State = DeviceNodeUninitialized;
2586 }
2587 status = STATUS_SUCCESS;
2588 break;
2589
2590 case PiActionStartDevice:
2591 // This action is triggered from usermode, when a driver is installed
2592 // for a non-critical PDO
2593 if (deviceNode->State == DeviceNodeInitialized &&
2594 !(deviceNode->Flags & DNF_HAS_PROBLEM))
2595 {
2596 PiDevNodeStateMachine(deviceNode);
2597 }
2598 else
2599 {
2600 DPRINT1("NOTE: attempt to start an already started/uninitialized device %wZ\n",
2601 &deviceNode->InstancePath);
2602 status = STATUS_UNSUCCESSFUL;
2603 }
2604 break;
2605
2606 case PiActionQueryState:
2607 // This action is only valid for started devices. If the device is not yet
2608 // started, the PnP manager issues IRP_MN_QUERY_PNP_DEVICE_STATE by itself.
2609 if (deviceNode->State == DeviceNodeStarted)
2610 {
2611 // Issue a IRP_MN_QUERY_PNP_DEVICE_STATE request: it will update node's flags
2612 // and then do enumeration if something has changed
2613 status = PiUpdateDeviceState(deviceNode);
2614 if (NT_SUCCESS(status))
2615 {
2616 PiDevNodeStateMachine(deviceNode);
2617 }
2618 }
2619 // TODO: Windows may return STATUS_DELETE_PENDING here
2620 status = STATUS_SUCCESS;
2621 break;
2622
2623 default:
2624 DPRINT1("Unimplemented device action %u\n", Request->Action);
2625 status = STATUS_NOT_IMPLEMENTED;
2626 break;
2627 }
2628
2629 if (Request->CompletionStatus)
2630 {
2631 *Request->CompletionStatus = status;
2632 }
2633
2634 if (Request->CompletionEvent)
2635 {
2636 KeSetEvent(Request->CompletionEvent, IO_NO_INCREMENT, FALSE);
2637 }
2638
2639 DPRINT("Finished processing PnP request %p\n", Request);
2640 ObDereferenceObject(Request->DeviceObject);
2641 ExFreePoolWithTag(Request, TAG_IO);
2642 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
2643 }
2644 IopDeviceActionInProgress = FALSE;
2645 KeSetEvent(&PiEnumerationFinished, IO_NO_INCREMENT, FALSE);
2646 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2647 }
2648
2649 /**
2650 * @brief Queue a device operation to a worker thread.
2651 *
2652 * @param[in] DeviceObject The device object
2653 * @param[in] Action The action
2654 * @param[in] CompletionEvent The completion event object (optional)
2655 * @param[out] CompletionStatus Status returned be the action will be written here
2656 */
2657
2658 VOID
PiQueueDeviceAction(_In_ PDEVICE_OBJECT DeviceObject,_In_ DEVICE_ACTION Action,_In_opt_ PKEVENT CompletionEvent,_Out_opt_ NTSTATUS * CompletionStatus)2659 PiQueueDeviceAction(
2660 _In_ PDEVICE_OBJECT DeviceObject,
2661 _In_ DEVICE_ACTION Action,
2662 _In_opt_ PKEVENT CompletionEvent,
2663 _Out_opt_ NTSTATUS *CompletionStatus)
2664 {
2665 PDEVICE_ACTION_REQUEST Request;
2666 KIRQL OldIrql;
2667
2668 Request = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, sizeof(*Request), TAG_IO);
2669
2670 DPRINT("PiQueueDeviceAction: DeviceObject - %p, Request - %p, Action - %s\n",
2671 DeviceObject, Request, ActionToStr(Action));
2672
2673 ObReferenceObject(DeviceObject);
2674
2675 Request->DeviceObject = DeviceObject;
2676 Request->Action = Action;
2677 Request->CompletionEvent = CompletionEvent;
2678 Request->CompletionStatus = CompletionStatus;
2679
2680 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
2681 InsertTailList(&IopDeviceActionRequestList, &Request->RequestListEntry);
2682
2683 if (Action == PiActionEnumRootDevices || Action == PiActionAddBootDevices)
2684 {
2685 ASSERT(!IopDeviceActionInProgress);
2686
2687 IopDeviceActionInProgress = TRUE;
2688 KeClearEvent(&PiEnumerationFinished);
2689 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2690
2691 PipDeviceActionWorker(NULL);
2692 return;
2693 }
2694
2695 if (IopDeviceActionInProgress || !PnPBootDriversLoaded)
2696 {
2697 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2698 return;
2699 }
2700 IopDeviceActionInProgress = TRUE;
2701 KeClearEvent(&PiEnumerationFinished);
2702 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
2703
2704 ExInitializeWorkItem(&IopDeviceActionWorkItem, PipDeviceActionWorker, NULL);
2705 ExQueueWorkItem(&IopDeviceActionWorkItem, DelayedWorkQueue);
2706 }
2707
2708 /**
2709 * @brief Perfom a device operation synchronously via PiQueueDeviceAction
2710 *
2711 * @param[in] DeviceObject The device object
2712 * @param[in] Action The action
2713 *
2714 * @return Status of the operation
2715 */
2716
2717 NTSTATUS
PiPerformSyncDeviceAction(_In_ PDEVICE_OBJECT DeviceObject,_In_ DEVICE_ACTION Action)2718 PiPerformSyncDeviceAction(
2719 _In_ PDEVICE_OBJECT DeviceObject,
2720 _In_ DEVICE_ACTION Action)
2721 {
2722 KEVENT opFinished;
2723 NTSTATUS status;
2724
2725 KeInitializeEvent(&opFinished, SynchronizationEvent, FALSE);
2726 PiQueueDeviceAction(DeviceObject, Action, &opFinished, &status);
2727 KeWaitForSingleObject(&opFinished, Executive, KernelMode, FALSE, NULL);
2728
2729 return status;
2730 }
2731