xref: /reactos/ntoskrnl/io/pnpmgr/pnpinit.c (revision 84344399)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/io/pnpmgr/pnpinit.c
5  * PURPOSE:         PnP Initialization Code
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS ********************************************************************/
16 
17 PUNICODE_STRING PiInitGroupOrderTable;
18 USHORT PiInitGroupOrderTableCount;
19 INTERFACE_TYPE PnpDefaultInterfaceType;
20 BOOLEAN PnPBootDriversLoaded = FALSE;
21 BOOLEAN PnPBootDriversInitialized = FALSE;
22 
23 ARBITER_INSTANCE IopRootBusNumberArbiter;
24 ARBITER_INSTANCE IopRootIrqArbiter;
25 ARBITER_INSTANCE IopRootDmaArbiter;
26 ARBITER_INSTANCE IopRootMemArbiter;
27 ARBITER_INSTANCE IopRootPortArbiter;
28 
29 extern KEVENT PiEnumerationFinished;
30 
31 NTSTATUS NTAPI IopPortInitialize(VOID);
32 NTSTATUS NTAPI IopMemInitialize(VOID);
33 NTSTATUS NTAPI IopDmaInitialize(VOID);
34 NTSTATUS NTAPI IopIrqInitialize(VOID);
35 NTSTATUS NTAPI IopBusNumberInitialize(VOID);
36 
37 /* FUNCTIONS ******************************************************************/
38 
39 INTERFACE_TYPE
40 NTAPI
41 IopDetermineDefaultInterfaceType(VOID)
42 {
43     /* FIXME: ReactOS doesn't support MicroChannel yet */
44     return Isa;
45 }
46 
47 NTSTATUS
48 NTAPI
49 IopInitializeArbiters(VOID)
50 {
51     NTSTATUS Status;
52 
53     Status = IopPortInitialize();
54     if (!NT_SUCCESS(Status))
55     {
56         DPRINT1("IopPortInitialize() return %X\n", Status);
57         return Status;
58     }
59 
60     Status = IopMemInitialize();
61     if (!NT_SUCCESS(Status))
62     {
63         DPRINT1("IopMemInitialize() return %X\n", Status);
64         return Status;
65     }
66 
67     Status = IopDmaInitialize();
68     if (!NT_SUCCESS(Status))
69     {
70         DPRINT1("IopDmaInitialize() return %X\n", Status);
71         return Status;
72     }
73 
74     Status = IopIrqInitialize();
75     if (!NT_SUCCESS(Status))
76     {
77         DPRINT1("IopIrqInitialize() return %X\n", Status);
78         return Status;
79     }
80 
81     Status = IopBusNumberInitialize();
82     if (!NT_SUCCESS(Status))
83     {
84         DPRINT1("IopBusNumberInitialize() return %X\n", Status);
85     }
86 
87     return Status;
88 }
89 
90 
91 CODE_SEG("INIT")
92 NTSTATUS
93 NTAPI
94 PiInitCacheGroupInformation(VOID)
95 {
96     HANDLE KeyHandle;
97     NTSTATUS Status;
98     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
99     PUNICODE_STRING GroupTable;
100     ULONG Count;
101     UNICODE_STRING GroupString =
102         RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
103                             L"\\Control\\ServiceGroupOrder");
104 
105     /* Open the registry key */
106     Status = IopOpenRegistryKeyEx(&KeyHandle,
107                                   NULL,
108                                   &GroupString,
109                                   KEY_READ);
110     if (NT_SUCCESS(Status))
111     {
112         /* Get the list */
113         Status = IopGetRegistryValue(KeyHandle, L"List", &KeyValueInformation);
114         ZwClose(KeyHandle);
115 
116         /* Make sure we got it */
117         if (NT_SUCCESS(Status))
118         {
119             /* Make sure it's valid */
120             if ((KeyValueInformation->Type == REG_MULTI_SZ) &&
121                 (KeyValueInformation->DataLength))
122             {
123                 /* Convert it to unicode strings */
124                 Status = PnpRegMultiSzToUnicodeStrings(KeyValueInformation,
125                                                        &GroupTable,
126                                                        &Count);
127 
128                 /* Cache it for later */
129                 PiInitGroupOrderTable = GroupTable;
130                 PiInitGroupOrderTableCount = (USHORT)Count;
131             }
132             else
133             {
134                 /* Fail */
135                 Status = STATUS_UNSUCCESSFUL;
136             }
137 
138             /* Free the information */
139             ExFreePool(KeyValueInformation);
140         }
141     }
142 
143     /* Return status */
144     return Status;
145 }
146 
147 USHORT
148 NTAPI
149 PpInitGetGroupOrderIndex(IN HANDLE ServiceHandle)
150 {
151     NTSTATUS Status;
152     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
153     USHORT i;
154     PVOID Buffer;
155     UNICODE_STRING Group;
156     PAGED_CODE();
157 
158     /* Make sure we have a cache */
159     if (!PiInitGroupOrderTable) return -1;
160 
161     /* If we don't have a handle, the rest is easy -- return the count */
162     if (!ServiceHandle) return PiInitGroupOrderTableCount + 1;
163 
164     /* Otherwise, get the group value */
165     Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
166     if (!NT_SUCCESS(Status)) return PiInitGroupOrderTableCount;
167 
168     /* Make sure we have a valid string */
169     ASSERT(KeyValueInformation->Type == REG_SZ);
170     ASSERT(KeyValueInformation->DataLength);
171 
172     /* Convert to unicode string */
173     Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
174     PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
175     Group.MaximumLength = (USHORT)KeyValueInformation->DataLength;
176     Group.Buffer = Buffer;
177 
178     /* Loop the groups */
179     for (i = 0; i < PiInitGroupOrderTableCount; i++)
180     {
181         /* Try to find a match */
182         if (RtlEqualUnicodeString(&Group, &PiInitGroupOrderTable[i], TRUE)) break;
183     }
184 
185     /* We're done */
186     ExFreePool(KeyValueInformation);
187     return i;
188 }
189 
190 USHORT
191 NTAPI
192 PipGetDriverTagPriority(IN HANDLE ServiceHandle)
193 {
194     NTSTATUS Status;
195     HANDLE KeyHandle = NULL;
196     PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
197     PKEY_VALUE_FULL_INFORMATION KeyValueInformationTag;
198     PKEY_VALUE_FULL_INFORMATION KeyValueInformationGroupOrderList;
199     PVOID Buffer;
200     UNICODE_STRING Group;
201     PULONG GroupOrder;
202     ULONG Count, Tag = 0;
203     USHORT i = -1;
204     UNICODE_STRING GroupString =
205     RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
206                         L"\\Control\\ServiceGroupOrder");
207 
208     /* Open the key */
209     Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &GroupString, KEY_READ);
210     if (!NT_SUCCESS(Status)) goto Quickie;
211 
212     /* Read the group */
213     Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
214     if (!NT_SUCCESS(Status)) goto Quickie;
215 
216     /* Make sure we have a group */
217     if ((KeyValueInformation->Type == REG_SZ) &&
218         (KeyValueInformation->DataLength))
219     {
220         /* Convert to unicode string */
221         Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
222         PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
223         Group.MaximumLength = (USHORT)KeyValueInformation->DataLength;
224         Group.Buffer = Buffer;
225     }
226 
227     /* Now read the tag */
228     Status = IopGetRegistryValue(ServiceHandle, L"Tag", &KeyValueInformationTag);
229     if (!NT_SUCCESS(Status)) goto Quickie;
230 
231     /* Make sure we have a tag */
232     if ((KeyValueInformationTag->Type == REG_DWORD) &&
233         (KeyValueInformationTag->DataLength))
234     {
235         /* Read it */
236         Tag = *(PULONG)((ULONG_PTR)KeyValueInformationTag +
237                         KeyValueInformationTag->DataOffset);
238     }
239 
240     /* We can get rid of this now */
241     ExFreePool(KeyValueInformationTag);
242 
243     /* Now let's read the group's tag order */
244     Status = IopGetRegistryValue(KeyHandle,
245                                  Group.Buffer,
246                                  &KeyValueInformationGroupOrderList);
247 
248     /* We can get rid of this now */
249 Quickie:
250     if (KeyValueInformation) ExFreePool(KeyValueInformation);
251     if (KeyHandle) NtClose(KeyHandle);
252     if (!NT_SUCCESS(Status)) return -1;
253 
254     /* We're on the success path -- validate the tag order*/
255     if ((KeyValueInformationGroupOrderList->Type == REG_BINARY) &&
256         (KeyValueInformationGroupOrderList->DataLength))
257     {
258         /* Get the order array */
259         GroupOrder = (PULONG)((ULONG_PTR)KeyValueInformationGroupOrderList +
260                               KeyValueInformationGroupOrderList->DataOffset);
261 
262         /* Get the count */
263         Count = *GroupOrder;
264         ASSERT(((Count + 1) * sizeof(ULONG)) <=
265                KeyValueInformationGroupOrderList->DataLength);
266 
267         /* Now loop each tag */
268         GroupOrder++;
269         for (i = 1; i <= Count; i++)
270         {
271             /* If we found it, we're out */
272             if (Tag == *GroupOrder) break;
273 
274             /* Try the next one */
275             GroupOrder++;
276         }
277     }
278 
279     /* Last buffer to free */
280     ExFreePool(KeyValueInformationGroupOrderList);
281     return i;
282 }
283 
284 CODE_SEG("INIT")
285 NTSTATUS
286 NTAPI
287 IopInitializePlugPlayServices(VOID)
288 {
289     NTSTATUS Status;
290     ULONG Disposition;
291     HANDLE KeyHandle, EnumHandle, ParentHandle, TreeHandle, ControlHandle;
292     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
293     UNICODE_STRING PnpManagerDriverName = RTL_CONSTANT_STRING(DRIVER_ROOT_NAME L"PnpManager");
294     PDEVICE_OBJECT Pdo;
295 
296     /* Initialize locks and such */
297     KeInitializeSpinLock(&IopDeviceTreeLock);
298     KeInitializeSpinLock(&IopDeviceActionLock);
299     InitializeListHead(&IopDeviceActionRequestList);
300     KeInitializeEvent(&PiEnumerationFinished, NotificationEvent, TRUE);
301 
302     /* Get the default interface */
303     PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType();
304 
305     /* Initialize arbiters */
306     Status = IopInitializeArbiters();
307     if (!NT_SUCCESS(Status)) return Status;
308 
309     /* Setup the group cache */
310     Status = PiInitCacheGroupInformation();
311     if (!NT_SUCCESS(Status)) return Status;
312 
313     /* Open the current control set */
314     Status = IopOpenRegistryKeyEx(&KeyHandle,
315                                   NULL,
316                                   &KeyName,
317                                   KEY_ALL_ACCESS);
318     if (!NT_SUCCESS(Status)) return Status;
319 
320     /* Create the control key */
321     RtlInitUnicodeString(&KeyName, L"Control");
322     Status = IopCreateRegistryKeyEx(&ControlHandle,
323                                     KeyHandle,
324                                     &KeyName,
325                                     KEY_ALL_ACCESS,
326                                     REG_OPTION_NON_VOLATILE,
327                                     &Disposition);
328     if (!NT_SUCCESS(Status)) return Status;
329 
330     /* Check if it's a new key */
331     if (Disposition == REG_CREATED_NEW_KEY)
332     {
333         HANDLE DeviceClassesHandle;
334 
335         /* Create the device classes key */
336         RtlInitUnicodeString(&KeyName, L"DeviceClasses");
337         Status = IopCreateRegistryKeyEx(&DeviceClassesHandle,
338                                         ControlHandle,
339                                         &KeyName,
340                                         KEY_ALL_ACCESS,
341                                         REG_OPTION_NON_VOLATILE,
342                                         &Disposition);
343         if (!NT_SUCCESS(Status)) return Status;
344 
345         ZwClose(DeviceClassesHandle);
346     }
347 
348     ZwClose(ControlHandle);
349 
350     /* Create the enum key */
351     RtlInitUnicodeString(&KeyName, REGSTR_KEY_ENUM);
352     Status = IopCreateRegistryKeyEx(&EnumHandle,
353                                     KeyHandle,
354                                     &KeyName,
355                                     KEY_ALL_ACCESS,
356                                     REG_OPTION_NON_VOLATILE,
357                                     &Disposition);
358     if (!NT_SUCCESS(Status)) return Status;
359 
360     /* Check if it's a new key */
361     if (Disposition == REG_CREATED_NEW_KEY)
362     {
363         /* FIXME: DACLs */
364     }
365 
366     /* Create the root key */
367     ParentHandle = EnumHandle;
368     RtlInitUnicodeString(&KeyName, REGSTR_KEY_ROOTENUM);
369     Status = IopCreateRegistryKeyEx(&EnumHandle,
370                                     ParentHandle,
371                                     &KeyName,
372                                     KEY_ALL_ACCESS,
373                                     REG_OPTION_NON_VOLATILE,
374                                     &Disposition);
375     NtClose(ParentHandle);
376     if (!NT_SUCCESS(Status)) return Status;
377     NtClose(EnumHandle);
378 
379     /* Open the root key now */
380     RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
381     Status = IopOpenRegistryKeyEx(&EnumHandle,
382                                   NULL,
383                                   &KeyName,
384                                   KEY_ALL_ACCESS);
385     if (NT_SUCCESS(Status))
386     {
387         /* Create the root dev node */
388         RtlInitUnicodeString(&KeyName, REGSTR_VAL_ROOT_DEVNODE);
389         Status = IopCreateRegistryKeyEx(&TreeHandle,
390                                         EnumHandle,
391                                         &KeyName,
392                                         KEY_ALL_ACCESS,
393                                         REG_OPTION_NON_VOLATILE,
394                                         NULL);
395         NtClose(EnumHandle);
396         if (NT_SUCCESS(Status)) NtClose(TreeHandle);
397     }
398 
399     /* Create the root driver */
400     Status = IoCreateDriver(&PnpManagerDriverName, PnpRootDriverEntry);
401     if (!NT_SUCCESS(Status))
402     {
403         DPRINT1("IoCreateDriverObject() failed\n");
404         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
405     }
406 
407     /* Create the root PDO */
408     Status = IoCreateDevice(IopRootDriverObject,
409                             0,
410                             NULL,
411                             FILE_DEVICE_CONTROLLER,
412                             0,
413                             FALSE,
414                             &Pdo);
415     if (!NT_SUCCESS(Status))
416     {
417         DPRINT1("IoCreateDevice() failed\n");
418         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
419     }
420 
421     /* This is a bus enumerated device */
422     Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
423 
424     /* Create the root device node */
425     IopRootDeviceNode = PipAllocateDeviceNode(Pdo);
426 
427     /* Set flags */
428     IopRootDeviceNode->Flags |= DNF_MADEUP | DNF_ENUMERATED |
429                                 DNF_IDS_QUERIED | DNF_NO_RESOURCE_REQUIRED;
430 
431     /* Create instance path */
432     if (!RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath, REGSTR_VAL_ROOT_DEVNODE))
433     {
434         DPRINT1("RtlCreateUnicodeString() failed\n");
435         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
436     }
437 
438     PnpRootInitializeDevExtension();
439 
440     PiSetDevNodeState(IopRootDeviceNode, DeviceNodeStarted);
441 
442     /* Initialize PnP-Event notification support */
443     Status = IopInitPlugPlayEvents();
444     if (!NT_SUCCESS(Status)) return Status;
445 
446     /* Initialize the Bus Type GUID List */
447     PnpBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
448     RtlZeroMemory(PnpBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
449     ExInitializeFastMutex(&PnpBusTypeGuidList->Lock);
450 
451     /* Initialize PnP root relations (this is a syncronous operation) */
452     PiQueueDeviceAction(Pdo, PiActionEnumRootDevices, NULL, NULL);
453 
454     /* Launch the firmware mapper */
455     Status = IopUpdateRootKey();
456     if (!NT_SUCCESS(Status)) return Status;
457 
458     /* Close the handle to the control set */
459     NtClose(KeyHandle);
460 
461     /* Initialize PnP root relations (this is a syncronous operation) */
462     PiQueueDeviceAction(Pdo, PiActionEnumRootDevices, NULL, NULL);
463 
464     /* We made it */
465     return STATUS_SUCCESS;
466 }
467 
468 /* EOF */
469