2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/config/cmboot.c
5 * PURPOSE: Configuration Manager - Boot Initialization
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES *******************************************************************/
16 /* FUNCTIONS ******************************************************************/
20 CmpFindControlSet(IN PHHIVE SystemHive
,
21 IN HCELL_INDEX RootCell
,
22 IN PUNICODE_STRING SelectKeyName
,
23 OUT PBOOLEAN AutoSelect
)
25 UNICODE_STRING KeyName
;
27 HCELL_INDEX SelectCell
, AutoSelectCell
, SelectValueCell
, ControlSetCell
;
28 HCELL_INDEX CurrentValueCell
;
29 PCM_KEY_VALUE KeyValue
;
32 ANSI_STRING ControlSetAnsiName
;
34 WCHAR WideBuffer
[128];
39 ASSERT(SystemHive
->ReleaseCellRoutine
== NULL
);
41 /* Get the Select subkey */
42 RtlInitUnicodeString(&KeyName
, L
"select");
43 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, RootCell
);
44 if (!Node
) return HCELL_NIL
;
45 SelectCell
= CmpFindSubKeyByName(SystemHive
, Node
, &KeyName
);
46 if (SelectCell
== HCELL_NIL
) return SelectCell
;
48 /* Get AutoSelect value */
49 RtlInitUnicodeString(&KeyName
, L
"AutoSelect");
50 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, SelectCell
);
51 if (!Node
) return HCELL_NIL
;
52 AutoSelectCell
= CmpFindValueByName(SystemHive
, Node
, &KeyName
);
53 if (AutoSelectCell
== HCELL_NIL
)
55 /* Assume TRUE if the value is missing. */
61 KeyValue
= (PCM_KEY_VALUE
)HvGetCell(SystemHive
, AutoSelectCell
);
62 if (KeyValue
== NULL
) return HCELL_NIL
;
64 /* Convert it to a boolean */
65 *AutoSelect
= *(PBOOLEAN
)CmpValueToData(SystemHive
, KeyValue
, &Length
);
68 /* Now find the control set being looked up */
69 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, SelectCell
);
70 if (!Node
) return HCELL_NIL
;
71 SelectValueCell
= CmpFindValueByName(SystemHive
, Node
, SelectKeyName
);
72 if (SelectValueCell
== HCELL_NIL
) return SelectValueCell
;
74 /* Read the value (corresponding to the CCS ID) */
75 KeyValue
= (PCM_KEY_VALUE
)HvGetCell(SystemHive
, SelectValueCell
);
76 if (!KeyValue
) return HCELL_NIL
;
77 if (KeyValue
->Type
!= REG_DWORD
) return HCELL_NIL
;
78 ControlSetId
= (PULONG
)CmpValueToData(SystemHive
, KeyValue
, &Length
);
80 /* Now build an Ansi String for the CCS's Name */
81 sprintf(Buffer
, "ControlSet%03lu", *ControlSetId
);
82 ControlSetAnsiName
.Length
= (USHORT
)strlen(Buffer
);
83 ControlSetAnsiName
.MaximumLength
= (USHORT
)strlen(Buffer
);
84 ControlSetAnsiName
.Buffer
= Buffer
;
86 /* And convert it to Unicode... */
87 KeyName
.MaximumLength
= 256;
88 KeyName
.Buffer
= WideBuffer
;
89 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
92 if (!NT_SUCCESS(Status
)) return HCELL_NIL
;
95 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, RootCell
);
96 if (!Node
) return HCELL_NIL
;
97 ControlSetCell
= CmpFindSubKeyByName(SystemHive
, Node
, &KeyName
);
98 if (ControlSetCell
== HCELL_NIL
) return ControlSetCell
;
100 /* Get the value of the "Current" CCS */
101 RtlInitUnicodeString(&KeyName
, L
"Current");
102 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, SelectCell
);
103 if (!Node
) return HCELL_NIL
;
104 CurrentValueCell
= CmpFindValueByName(SystemHive
, Node
, &KeyName
);
106 /* Make sure it exists */
107 if (CurrentValueCell
!= HCELL_NIL
)
109 /* Get the current value and make sure its a ULONG */
110 KeyValue
= (PCM_KEY_VALUE
)HvGetCell(SystemHive
, CurrentValueCell
);
111 if (!KeyValue
) return HCELL_NIL
;
112 if (KeyValue
->Type
== REG_DWORD
)
114 /* Get the data and update it */
115 CurrentData
= (PULONG
)CmpValueToData(SystemHive
,
118 if (!CurrentData
) return HCELL_NIL
;
119 *CurrentData
= *ControlSetId
;
123 /* Return the CCS Cell */
124 return ControlSetCell
;
129 CmpFindTagIndex(IN PHHIVE Hive
,
130 IN HCELL_INDEX TagCell
,
131 IN HCELL_INDEX GroupOrderCell
,
132 IN PUNICODE_STRING GroupName
)
134 PCM_KEY_VALUE TagValue
, Value
;
135 HCELL_INDEX OrderCell
;
136 PULONG TagOrder
, DriverTag
;
137 ULONG CurrentTag
, Length
;
139 BOOLEAN BufferAllocated
;
140 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
143 Value
= HvGetCell(Hive
, TagCell
);
145 DriverTag
= (PULONG
)CmpValueToData(Hive
, Value
, &Length
);
148 /* Get the order array */
149 Node
= HvGetCell(Hive
, GroupOrderCell
);
151 OrderCell
= CmpFindValueByName(Hive
, Node
, GroupName
);
152 if (OrderCell
== HCELL_NIL
) return -2;
155 TagValue
= HvGetCell(Hive
, OrderCell
);
156 CmpGetValueData(Hive
, TagValue
, &Length
, (PVOID
*)&TagOrder
, &BufferAllocated
, &OrderCell
);
160 for (CurrentTag
= 1; CurrentTag
<= TagOrder
[0]; CurrentTag
++)
163 if (TagOrder
[CurrentTag
] == *DriverTag
)
165 /* Found it -- return the tag */
166 if (BufferAllocated
) ExFreePool(TagOrder
);
171 /* No matches, so assume next to last ordering */
172 if (BufferAllocated
) ExFreePool(TagOrder
);
178 CmpAddDriverToList(IN PHHIVE Hive
,
179 IN HCELL_INDEX DriverCell
,
180 IN HCELL_INDEX GroupOrderCell
,
181 IN PUNICODE_STRING RegistryPath
,
182 IN PLIST_ENTRY BootDriverListHead
)
184 PBOOT_DRIVER_NODE DriverNode
;
185 PBOOT_DRIVER_LIST_ENTRY DriverEntry
;
187 ULONG NameLength
, Length
;
188 HCELL_INDEX ValueCell
, TagCell
;
190 PUNICODE_STRING FileName
, RegistryString
;
191 UNICODE_STRING UnicodeString
;
194 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
196 /* Allocate a driver node and initialize it */
197 DriverNode
= CmpAllocate(sizeof(BOOT_DRIVER_NODE
), FALSE
, TAG_CM
);
198 if (!DriverNode
) return FALSE
;
199 DriverEntry
= &DriverNode
->ListEntry
;
200 DriverEntry
->RegistryPath
.Buffer
= NULL
;
201 DriverEntry
->FilePath
.Buffer
= NULL
;
203 /* Get the driver cell */
204 Node
= HvGetCell(Hive
, DriverCell
);
207 /* Get the name from the cell */
208 DriverNode
->Name
.Length
= Node
->Flags
& KEY_COMP_NAME
?
209 CmpCompressedNameSize(Node
->Name
, Node
->NameLength
) :
211 DriverNode
->Name
.MaximumLength
= DriverNode
->Name
.Length
;
212 NameLength
= DriverNode
->Name
.Length
;
214 /* Now allocate the buffer for it and copy the name */
215 DriverNode
->Name
.Buffer
= CmpAllocate(NameLength
, FALSE
, TAG_CM
);
216 if (!DriverNode
->Name
.Buffer
) return FALSE
;
217 if (Node
->Flags
& KEY_COMP_NAME
)
219 /* Compressed name */
220 CmpCopyCompressedName(DriverNode
->Name
.Buffer
,
221 DriverNode
->Name
.Length
,
228 RtlCopyMemory(DriverNode
->Name
.Buffer
, Node
->Name
, Node
->NameLength
);
231 /* Now find the image path */
232 RtlInitUnicodeString(&UnicodeString
, L
"ImagePath");
233 ValueCell
= CmpFindValueByName(Hive
, Node
, &UnicodeString
);
234 if (ValueCell
== HCELL_NIL
)
236 /* Couldn't find it, so assume the drivers path */
237 Length
= sizeof(L
"System32\\Drivers\\") + NameLength
+ sizeof(L
".sys");
239 /* Allocate the path name */
240 FileName
= &DriverEntry
->FilePath
;
241 FileName
->Length
= 0;
242 FileName
->MaximumLength
= Length
;
243 FileName
->Buffer
= CmpAllocate(Length
, FALSE
,TAG_CM
);
244 if (!FileName
->Buffer
) return FALSE
;
246 /* Write the path name */
247 RtlAppendUnicodeToString(FileName
, L
"System32\\Drivers\\");
248 RtlAppendUnicodeStringToString(FileName
, &DriverNode
->Name
);
249 RtlAppendUnicodeToString(FileName
, L
".sys");
253 /* Path name exists, so grab it */
254 Value
= HvGetCell(Hive
, ValueCell
);
257 /* Allocate and setup the path name */
258 FileName
= &DriverEntry
->FilePath
;
259 Buffer
= (PWCHAR
)CmpValueToData(Hive
, Value
, &Length
);
260 FileName
->MaximumLength
= FileName
->Length
= Length
;
261 FileName
->Buffer
= CmpAllocate(Length
, FALSE
, TAG_CM
);
263 /* Transfer the data */
264 if (!(FileName
->Buffer
) || !(Buffer
)) return FALSE
;
265 RtlCopyMemory(FileName
->Buffer
, Buffer
, Length
);
268 /* Now build the registry path */
269 RegistryString
= &DriverEntry
->RegistryPath
;
270 RegistryString
->Length
= 0;
271 RegistryString
->MaximumLength
= RegistryPath
->Length
+ NameLength
;
272 RegistryString
->Buffer
= CmpAllocate(RegistryString
->MaximumLength
, FALSE
, TAG_CM
);
273 if (!RegistryString
->Buffer
) return FALSE
;
275 /* Add the driver name to it */
276 RtlAppendUnicodeStringToString(RegistryString
, RegistryPath
);
277 RtlAppendUnicodeStringToString(RegistryString
, &DriverNode
->Name
);
279 /* The entry is done, add it */
280 InsertHeadList(BootDriverListHead
, &DriverEntry
->Link
);
282 /* Now find error control settings */
283 RtlInitUnicodeString(&UnicodeString
, L
"ErrorControl");
284 ValueCell
= CmpFindValueByName(Hive
, Node
, &UnicodeString
);
285 if (ValueCell
== HCELL_NIL
)
287 /* Couldn't find it, so assume default */
288 DriverNode
->ErrorControl
= NormalError
;
292 /* Otherwise, read whatever the data says */
293 Value
= HvGetCell(Hive
, ValueCell
);
295 ErrorControl
= (PULONG
)CmpValueToData(Hive
, Value
, &Length
);
296 ASSERT(ErrorControl
);
297 DriverNode
->ErrorControl
= *ErrorControl
;
300 /* Next, get the group cell */
301 RtlInitUnicodeString(&UnicodeString
, L
"group");
302 ValueCell
= CmpFindValueByName(Hive
, Node
, &UnicodeString
);
303 if (ValueCell
== HCELL_NIL
)
305 /* Couldn't find, so set an empty string */
306 RtlInitEmptyUnicodeString(&DriverNode
->Group
, NULL
, 0);
310 /* Found it, read the group value */
311 Value
= HvGetCell(Hive
, ValueCell
);
314 /* Copy it into the node */
315 DriverNode
->Group
.Buffer
= (PWCHAR
)CmpValueToData(Hive
, Value
, &Length
);
316 if (!DriverNode
->Group
.Buffer
) return FALSE
;
317 DriverNode
->Group
.Length
= Length
- sizeof(UNICODE_NULL
);
318 DriverNode
->Group
.MaximumLength
= DriverNode
->Group
.Length
;
321 /* Finally, find the tag */
322 RtlInitUnicodeString(&UnicodeString
, L
"Tag");
323 TagCell
= CmpFindValueByName(Hive
, Node
, &UnicodeString
);
324 if (TagCell
== HCELL_NIL
)
326 /* No tag, so load last */
327 DriverNode
->Tag
= -1;
331 /* Otherwise, decode it based on tag order */
332 DriverNode
->Tag
= CmpFindTagIndex(Hive
,
344 CmpIsLoadType(IN PHHIVE Hive
,
346 IN SERVICE_LOAD_TYPE LoadType
)
349 HCELL_INDEX ValueCell
;
350 UNICODE_STRING ValueString
= RTL_CONSTANT_STRING(L
"Start");
354 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
356 /* Open the start cell */
357 Node
= HvGetCell(Hive
, Cell
);
359 ValueCell
= CmpFindValueByName(Hive
, Node
, &ValueString
);
360 if (ValueCell
== HCELL_NIL
) return FALSE
;
362 /* Read the start value */
363 Value
= HvGetCell(Hive
, ValueCell
);
365 Data
= (PLONG
)CmpValueToData(Hive
, Value
, &Length
);
368 /* Return if the type matches */
369 return (*Data
== LoadType
);
374 CmpFindDrivers(IN PHHIVE Hive
,
375 IN HCELL_INDEX ControlSet
,
376 IN SERVICE_LOAD_TYPE LoadType
,
377 IN PWCHAR BootFileSystem OPTIONAL
,
378 IN PLIST_ENTRY DriverListHead
)
380 HCELL_INDEX ServicesCell
, ControlCell
, GroupOrderCell
, DriverCell
;
384 UNICODE_STRING UnicodeString
, KeyPath
;
385 PBOOT_DRIVER_NODE FsNode
;
386 PCM_KEY_NODE ControlNode
, ServicesNode
, Node
;
387 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
389 /* Open the control set key */
390 ControlNode
= HvGetCell(Hive
, ControlSet
);
393 /* Get services cell */
394 RtlInitUnicodeString(&Name
, L
"Services");
395 ServicesCell
= CmpFindSubKeyByName(Hive
, ControlNode
, &Name
);
396 if (ServicesCell
== HCELL_NIL
) return FALSE
;
398 /* Open services key */
399 ServicesNode
= HvGetCell(Hive
, ServicesCell
);
400 ASSERT(ServicesNode
);
402 /* Get control cell */
403 RtlInitUnicodeString(&Name
, L
"Control");
404 ControlCell
= CmpFindSubKeyByName(Hive
, ControlNode
, &Name
);
405 if (ControlCell
== HCELL_NIL
) return FALSE
;
407 /* Get the group order cell and read it */
408 RtlInitUnicodeString(&Name
, L
"GroupOrderList");
409 Node
= HvGetCell(Hive
, ControlCell
);
411 GroupOrderCell
= CmpFindSubKeyByName(Hive
, Node
, &Name
);
412 if (GroupOrderCell
== HCELL_NIL
) return FALSE
;
414 /* Build the root registry path */
415 RtlInitEmptyUnicodeString(&KeyPath
, Buffer
, sizeof(Buffer
));
416 RtlAppendUnicodeToString(&KeyPath
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
418 /* Find the first subkey (ie: the first driver or service) */
420 DriverCell
= CmpFindSubKeyByNumber(Hive
, ServicesNode
, i
);
421 while (DriverCell
!= HCELL_NIL
)
423 /* Make sure it's a driver of this start type */
424 if (CmpIsLoadType(Hive
, DriverCell
, LoadType
))
426 /* Add it to the list */
427 CmpAddDriverToList(Hive
,
435 /* Try the next subkey */
436 DriverCell
= CmpFindSubKeyByNumber(Hive
, ServicesNode
, ++i
);
439 /* Check if we have a boot file system */
443 RtlInitUnicodeString(&UnicodeString
, BootFileSystem
);
444 DriverCell
= CmpFindSubKeyByName(Hive
, ServicesNode
, &UnicodeString
);
445 if (DriverCell
!= HCELL_NIL
)
447 /* Always add it to the list */
448 CmpAddDriverToList(Hive
,
454 /* Mark it as critical so it always loads */
455 FsNode
= CONTAINING_RECORD(DriverListHead
->Flink
,
458 FsNode
->ErrorControl
= SERVICE_ERROR_CRITICAL
;
468 CmpDoSort(IN PLIST_ENTRY DriverListHead
,
469 IN PUNICODE_STRING OrderList
)
471 PWCHAR Current
, End
= NULL
;
472 PLIST_ENTRY NextEntry
;
473 UNICODE_STRING GroupName
;
474 PBOOT_DRIVER_NODE CurrentNode
;
476 /* We're going from end to start, so get to the last group and keep going */
477 Current
= &OrderList
->Buffer
[OrderList
->Length
/ sizeof(WCHAR
)];
478 while (Current
> OrderList
->Buffer
)
480 /* Scan the current string */
483 if (*Current
== UNICODE_NULL
) End
= Current
;
484 } while ((*(--Current
- 1) != UNICODE_NULL
) && (Current
!= OrderList
->Buffer
));
486 /* This is our cleaned up string for this specific group */
488 GroupName
.Length
= (End
- Current
) * sizeof(WCHAR
);
489 GroupName
.MaximumLength
= GroupName
.Length
;
490 GroupName
.Buffer
= Current
;
492 /* Now loop the driver list */
493 NextEntry
= DriverListHead
->Flink
;
494 while (NextEntry
!= DriverListHead
)
497 CurrentNode
= CONTAINING_RECORD(NextEntry
,
501 /* Get the next entry now since we'll do a relink */
502 NextEntry
= CurrentNode
->ListEntry
.Link
.Flink
;
504 /* Is there a group name and does it match the current group? */
505 if ((CurrentNode
->Group
.Buffer
) &&
506 (RtlEqualUnicodeString(&GroupName
, &CurrentNode
->Group
, TRUE
)))
508 /* Remove from this location and re-link in the new one */
509 RemoveEntryList(&CurrentNode
->ListEntry
.Link
);
510 InsertHeadList(DriverListHead
, &CurrentNode
->ListEntry
.Link
);
524 CmpSortDriverList(IN PHHIVE Hive
,
525 IN HCELL_INDEX ControlSet
,
526 IN PLIST_ENTRY DriverListHead
)
528 HCELL_INDEX Controls
, GroupOrder
, ListCell
;
529 UNICODE_STRING Name
, DependList
;
530 PCM_KEY_VALUE ListNode
;
533 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
535 /* Open the control key */
536 Node
= HvGetCell(Hive
, ControlSet
);
538 RtlInitUnicodeString(&Name
, L
"Control");
539 Controls
= CmpFindSubKeyByName(Hive
, Node
, &Name
);
540 if (Controls
== HCELL_NIL
) return FALSE
;
542 /* Open the service group order */
543 Node
= HvGetCell(Hive
, Controls
);
545 RtlInitUnicodeString(&Name
, L
"ServiceGroupOrder");
546 GroupOrder
= CmpFindSubKeyByName(Hive
, Node
, &Name
);
547 if (GroupOrder
== HCELL_NIL
) return FALSE
;
549 /* Open the list key */
550 Node
= HvGetCell(Hive
, GroupOrder
);
552 RtlInitUnicodeString(&Name
, L
"list");
553 ListCell
= CmpFindValueByName(Hive
, Node
, &Name
);
554 if (ListCell
== HCELL_NIL
) return FALSE
;
556 /* Now read the actual list */
557 ListNode
= HvGetCell(Hive
, ListCell
);
559 if (ListNode
->Type
!= REG_MULTI_SZ
) return FALSE
;
561 /* Copy it into a buffer */
562 DependList
.Buffer
= (PWCHAR
)CmpValueToData(Hive
, ListNode
, &Length
);
563 if (!DependList
.Buffer
) return FALSE
;
564 DependList
.Length
= DependList
.MaximumLength
= Length
- sizeof(UNICODE_NULL
);
566 /* And start the recurive sort algorithm */
567 return CmpDoSort(DriverListHead
, &DependList
);
572 CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode
,
573 IN PBOOT_DRIVER_NODE EndNode
)
575 PBOOT_DRIVER_NODE CurrentNode
, PreviousNode
;
576 PLIST_ENTRY ListEntry
;
578 /* Base case, nothing to do */
579 if (StartNode
== EndNode
) return TRUE
;
582 CurrentNode
= StartNode
;
585 /* Save this as the previous node */
586 PreviousNode
= CurrentNode
;
588 /* And move to the next one */
589 ListEntry
= CurrentNode
->ListEntry
.Link
.Flink
;
590 CurrentNode
= CONTAINING_RECORD(ListEntry
,
594 /* Check if the previous driver had a bigger tag */
595 if (PreviousNode
->Tag
> CurrentNode
->Tag
)
597 /* Check if we need to update the tail */
598 if (CurrentNode
== EndNode
)
600 /* Update the tail */
601 ListEntry
= CurrentNode
->ListEntry
.Link
.Blink
;
602 EndNode
= CONTAINING_RECORD(ListEntry
,
607 /* Remove this driver since we need to move it */
608 RemoveEntryList(&CurrentNode
->ListEntry
.Link
);
610 /* Keep looping until we find a driver with a lower tag than ours */
611 while ((PreviousNode
->Tag
> CurrentNode
->Tag
) && (PreviousNode
!= StartNode
))
613 /* We'll be re-inserted at this spot */
614 ListEntry
= PreviousNode
->ListEntry
.Link
.Blink
;
615 PreviousNode
= CONTAINING_RECORD(ListEntry
,
620 /* Do the insert in the new location */
621 InsertTailList(&PreviousNode
->ListEntry
.Link
, &CurrentNode
->ListEntry
.Link
);
623 /* Update the head, if needed */
624 if (PreviousNode
== StartNode
) StartNode
= CurrentNode
;
626 } while (CurrentNode
!= EndNode
);
634 CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead
)
636 PLIST_ENTRY NextEntry
;
637 PBOOT_DRIVER_NODE StartNode
, EndNode
, CurrentNode
;
640 NextEntry
= DriverListHead
->Flink
;
641 while (NextEntry
!= DriverListHead
)
643 /* Find the first entry */
644 StartNode
= CONTAINING_RECORD(NextEntry
,
649 /* Find the last entry */
650 EndNode
= CONTAINING_RECORD(NextEntry
,
654 /* Get the next entry */
655 NextEntry
= NextEntry
->Flink
;
656 CurrentNode
= CONTAINING_RECORD(NextEntry
,
660 /* If the next entry is back to the top, break out */
661 if (NextEntry
== DriverListHead
) break;
663 /* Otherwise, check if this entry is equal */
664 if (!RtlEqualUnicodeString(&StartNode
->Group
,
668 /* It is, so we've detected a cycle, break out */
671 } while (NextEntry
!= DriverListHead
);
673 /* Now we have the correct start and end pointers, so do the sort */
674 CmpOrderGroup(StartNode
, EndNode
);