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 ******************************************************************/
21 CmpFindControlSet(IN PHHIVE SystemHive
,
22 IN HCELL_INDEX RootCell
,
23 IN PUNICODE_STRING SelectKeyName
,
24 OUT PBOOLEAN AutoSelect
)
26 UNICODE_STRING KeyName
;
28 HCELL_INDEX SelectCell
, AutoSelectCell
, SelectValueCell
, ControlSetCell
;
29 HCELL_INDEX CurrentValueCell
;
30 PCM_KEY_VALUE KeyValue
;
33 ANSI_STRING ControlSetAnsiName
;
35 WCHAR WideBuffer
[128];
40 ASSERT(SystemHive
->ReleaseCellRoutine
== NULL
);
42 /* Get the Select subkey */
43 RtlInitUnicodeString(&KeyName
, L
"select");
44 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, RootCell
);
45 if (!Node
) return HCELL_NIL
;
46 SelectCell
= CmpFindSubKeyByName(SystemHive
, Node
, &KeyName
);
47 if (SelectCell
== HCELL_NIL
) return SelectCell
;
49 /* Get AutoSelect value */
50 RtlInitUnicodeString(&KeyName
, L
"AutoSelect");
51 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, SelectCell
);
52 if (!Node
) return HCELL_NIL
;
53 AutoSelectCell
= CmpFindValueByName(SystemHive
, Node
, &KeyName
);
54 if (AutoSelectCell
== HCELL_NIL
)
56 /* Assume TRUE if the value is missing. */
62 KeyValue
= (PCM_KEY_VALUE
)HvGetCell(SystemHive
, AutoSelectCell
);
63 if (KeyValue
== NULL
) return HCELL_NIL
;
65 /* Convert it to a boolean */
66 *AutoSelect
= *(PBOOLEAN
)CmpValueToData(SystemHive
, KeyValue
, &Length
);
69 /* Now find the control set being looked up */
70 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, SelectCell
);
71 if (!Node
) return HCELL_NIL
;
72 SelectValueCell
= CmpFindValueByName(SystemHive
, Node
, SelectKeyName
);
73 if (SelectValueCell
== HCELL_NIL
) return SelectValueCell
;
75 /* Read the value (corresponding to the CCS ID) */
76 KeyValue
= (PCM_KEY_VALUE
)HvGetCell(SystemHive
, SelectValueCell
);
77 if (!KeyValue
) return HCELL_NIL
;
78 if (KeyValue
->Type
!= REG_DWORD
) return HCELL_NIL
;
79 ControlSetId
= (PULONG
)CmpValueToData(SystemHive
, KeyValue
, &Length
);
81 /* Now build an Ansi String for the CCS's Name */
82 sprintf(Buffer
, "ControlSet%03lu", *ControlSetId
);
83 ControlSetAnsiName
.Length
= (USHORT
)strlen(Buffer
);
84 ControlSetAnsiName
.MaximumLength
= (USHORT
)strlen(Buffer
);
85 ControlSetAnsiName
.Buffer
= Buffer
;
87 /* And convert it to Unicode... */
88 KeyName
.MaximumLength
= 256;
89 KeyName
.Buffer
= WideBuffer
;
90 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
93 if (!NT_SUCCESS(Status
)) return HCELL_NIL
;
96 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, RootCell
);
97 if (!Node
) return HCELL_NIL
;
98 ControlSetCell
= CmpFindSubKeyByName(SystemHive
, Node
, &KeyName
);
99 if (ControlSetCell
== HCELL_NIL
) return ControlSetCell
;
101 /* Get the value of the "Current" CCS */
102 RtlInitUnicodeString(&KeyName
, L
"Current");
103 Node
= (PCM_KEY_NODE
)HvGetCell(SystemHive
, SelectCell
);
104 if (!Node
) return HCELL_NIL
;
105 CurrentValueCell
= CmpFindValueByName(SystemHive
, Node
, &KeyName
);
107 /* Make sure it exists */
108 if (CurrentValueCell
!= HCELL_NIL
)
110 /* Get the current value and make sure its a ULONG */
111 KeyValue
= (PCM_KEY_VALUE
)HvGetCell(SystemHive
, CurrentValueCell
);
112 if (!KeyValue
) return HCELL_NIL
;
113 if (KeyValue
->Type
== REG_DWORD
)
115 /* Get the data and update it */
116 CurrentData
= (PULONG
)CmpValueToData(SystemHive
,
119 if (!CurrentData
) return HCELL_NIL
;
120 *CurrentData
= *ControlSetId
;
124 /* Return the CCS Cell */
125 return ControlSetCell
;
131 CmpFindTagIndex(IN PHHIVE Hive
,
132 IN HCELL_INDEX TagCell
,
133 IN HCELL_INDEX GroupOrderCell
,
134 IN PUNICODE_STRING GroupName
)
136 PCM_KEY_VALUE TagValue
, Value
;
137 HCELL_INDEX OrderCell
;
138 PULONG TagOrder
, DriverTag
;
139 ULONG CurrentTag
, Length
;
141 BOOLEAN BufferAllocated
;
142 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
145 Value
= HvGetCell(Hive
, TagCell
);
147 DriverTag
= (PULONG
)CmpValueToData(Hive
, Value
, &Length
);
150 /* Get the order array */
151 Node
= HvGetCell(Hive
, GroupOrderCell
);
153 OrderCell
= CmpFindValueByName(Hive
, Node
, GroupName
);
154 if (OrderCell
== HCELL_NIL
) return -2;
157 TagValue
= HvGetCell(Hive
, OrderCell
);
158 CmpGetValueData(Hive
, TagValue
, &Length
, (PVOID
*)&TagOrder
, &BufferAllocated
, &OrderCell
);
162 for (CurrentTag
= 1; CurrentTag
<= TagOrder
[0]; CurrentTag
++)
165 if (TagOrder
[CurrentTag
] == *DriverTag
)
167 /* Found it -- return the tag */
168 if (BufferAllocated
) ExFreePool(TagOrder
);
173 /* No matches, so assume next to last ordering */
174 if (BufferAllocated
) ExFreePool(TagOrder
);
181 CmpAddDriverToList(IN PHHIVE Hive
,
182 IN HCELL_INDEX DriverCell
,
183 IN HCELL_INDEX GroupOrderCell
,
184 IN PUNICODE_STRING RegistryPath
,
185 IN PLIST_ENTRY BootDriverListHead
)
187 PBOOT_DRIVER_NODE DriverNode
;
188 PBOOT_DRIVER_LIST_ENTRY DriverEntry
;
190 ULONG NameLength
, Length
;
191 HCELL_INDEX ValueCell
, TagCell
;
193 PUNICODE_STRING FileName
, RegistryString
;
194 UNICODE_STRING UnicodeString
;
197 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
199 /* Allocate a driver node and initialize it */
200 DriverNode
= CmpAllocate(sizeof(BOOT_DRIVER_NODE
), FALSE
, TAG_CM
);
201 if (!DriverNode
) return FALSE
;
202 DriverEntry
= &DriverNode
->ListEntry
;
203 DriverEntry
->RegistryPath
.Buffer
= NULL
;
204 DriverEntry
->FilePath
.Buffer
= NULL
;
206 /* Get the driver cell */
207 Node
= HvGetCell(Hive
, DriverCell
);
210 /* Get the name from the cell */
211 DriverNode
->Name
.Length
= Node
->Flags
& KEY_COMP_NAME
?
212 CmpCompressedNameSize(Node
->Name
, Node
->NameLength
) :
214 DriverNode
->Name
.MaximumLength
= DriverNode
->Name
.Length
;
215 NameLength
= DriverNode
->Name
.Length
;
217 /* Now allocate the buffer for it and copy the name */
218 DriverNode
->Name
.Buffer
= CmpAllocate(NameLength
, FALSE
, TAG_CM
);
219 if (!DriverNode
->Name
.Buffer
) return FALSE
;
220 if (Node
->Flags
& KEY_COMP_NAME
)
222 /* Compressed name */
223 CmpCopyCompressedName(DriverNode
->Name
.Buffer
,
224 DriverNode
->Name
.Length
,
231 RtlCopyMemory(DriverNode
->Name
.Buffer
, Node
->Name
, Node
->NameLength
);
234 /* Now find the image path */
235 RtlInitUnicodeString(&UnicodeString
, L
"ImagePath");
236 ValueCell
= CmpFindValueByName(Hive
, Node
, &UnicodeString
);
237 if (ValueCell
== HCELL_NIL
)
239 /* Couldn't find it, so assume the drivers path */
240 Length
= sizeof(L
"System32\\Drivers\\") + NameLength
+ sizeof(L
".sys");
242 /* Allocate the path name */
243 FileName
= &DriverEntry
->FilePath
;
244 FileName
->Length
= 0;
245 FileName
->MaximumLength
= Length
;
246 FileName
->Buffer
= CmpAllocate(Length
, FALSE
,TAG_CM
);
247 if (!FileName
->Buffer
) return FALSE
;
249 /* Write the path name */
250 RtlAppendUnicodeToString(FileName
, L
"System32\\Drivers\\");
251 RtlAppendUnicodeStringToString(FileName
, &DriverNode
->Name
);
252 RtlAppendUnicodeToString(FileName
, L
".sys");
256 /* Path name exists, so grab it */
257 Value
= HvGetCell(Hive
, ValueCell
);
260 /* Allocate and setup the path name */
261 FileName
= &DriverEntry
->FilePath
;
262 Buffer
= (PWCHAR
)CmpValueToData(Hive
, Value
, &Length
);
263 FileName
->MaximumLength
= FileName
->Length
= Length
;
264 FileName
->Buffer
= CmpAllocate(Length
, FALSE
, TAG_CM
);
266 /* Transfer the data */
267 if (!(FileName
->Buffer
) || !(Buffer
)) return FALSE
;
268 RtlCopyMemory(FileName
->Buffer
, Buffer
, Length
);
271 /* Now build the registry path */
272 RegistryString
= &DriverEntry
->RegistryPath
;
273 RegistryString
->Length
= 0;
274 RegistryString
->MaximumLength
= RegistryPath
->Length
+ NameLength
;
275 RegistryString
->Buffer
= CmpAllocate(RegistryString
->MaximumLength
, FALSE
, TAG_CM
);
276 if (!RegistryString
->Buffer
) return FALSE
;
278 /* Add the driver name to it */
279 RtlAppendUnicodeStringToString(RegistryString
, RegistryPath
);
280 RtlAppendUnicodeStringToString(RegistryString
, &DriverNode
->Name
);
282 /* The entry is done, add it */
283 InsertHeadList(BootDriverListHead
, &DriverEntry
->Link
);
285 /* Now find error control settings */
286 RtlInitUnicodeString(&UnicodeString
, L
"ErrorControl");
287 ValueCell
= CmpFindValueByName(Hive
, Node
, &UnicodeString
);
288 if (ValueCell
== HCELL_NIL
)
290 /* Couldn't find it, so assume default */
291 DriverNode
->ErrorControl
= NormalError
;
295 /* Otherwise, read whatever the data says */
296 Value
= HvGetCell(Hive
, ValueCell
);
298 ErrorControl
= (PULONG
)CmpValueToData(Hive
, Value
, &Length
);
299 ASSERT(ErrorControl
);
300 DriverNode
->ErrorControl
= *ErrorControl
;
303 /* Next, get the group cell */
304 RtlInitUnicodeString(&UnicodeString
, L
"group");
305 ValueCell
= CmpFindValueByName(Hive
, Node
, &UnicodeString
);
306 if (ValueCell
== HCELL_NIL
)
308 /* Couldn't find, so set an empty string */
309 RtlInitEmptyUnicodeString(&DriverNode
->Group
, NULL
, 0);
313 /* Found it, read the group value */
314 Value
= HvGetCell(Hive
, ValueCell
);
317 /* Copy it into the node */
318 DriverNode
->Group
.Buffer
= (PWCHAR
)CmpValueToData(Hive
, Value
, &Length
);
319 if (!DriverNode
->Group
.Buffer
) return FALSE
;
320 DriverNode
->Group
.Length
= Length
- sizeof(UNICODE_NULL
);
321 DriverNode
->Group
.MaximumLength
= DriverNode
->Group
.Length
;
324 /* Finally, find the tag */
325 RtlInitUnicodeString(&UnicodeString
, L
"Tag");
326 TagCell
= CmpFindValueByName(Hive
, Node
, &UnicodeString
);
327 if (TagCell
== HCELL_NIL
)
329 /* No tag, so load last */
330 DriverNode
->Tag
= -1;
334 /* Otherwise, decode it based on tag order */
335 DriverNode
->Tag
= CmpFindTagIndex(Hive
,
348 CmpIsLoadType(IN PHHIVE Hive
,
350 IN SERVICE_LOAD_TYPE LoadType
)
353 HCELL_INDEX ValueCell
;
354 UNICODE_STRING ValueString
= RTL_CONSTANT_STRING(L
"Start");
358 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
360 /* Open the start cell */
361 Node
= HvGetCell(Hive
, Cell
);
363 ValueCell
= CmpFindValueByName(Hive
, Node
, &ValueString
);
364 if (ValueCell
== HCELL_NIL
) return FALSE
;
366 /* Read the start value */
367 Value
= HvGetCell(Hive
, ValueCell
);
369 Data
= (PLONG
)CmpValueToData(Hive
, Value
, &Length
);
372 /* Return if the type matches */
373 return (*Data
== LoadType
);
379 CmpFindDrivers(IN PHHIVE Hive
,
380 IN HCELL_INDEX ControlSet
,
381 IN SERVICE_LOAD_TYPE LoadType
,
382 IN PWCHAR BootFileSystem OPTIONAL
,
383 IN PLIST_ENTRY DriverListHead
)
385 HCELL_INDEX ServicesCell
, ControlCell
, GroupOrderCell
, DriverCell
;
389 UNICODE_STRING UnicodeString
, KeyPath
;
390 PBOOT_DRIVER_NODE FsNode
;
391 PCM_KEY_NODE ControlNode
, ServicesNode
, Node
;
392 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
394 /* Open the control set key */
395 ControlNode
= HvGetCell(Hive
, ControlSet
);
398 /* Get services cell */
399 RtlInitUnicodeString(&Name
, L
"Services");
400 ServicesCell
= CmpFindSubKeyByName(Hive
, ControlNode
, &Name
);
401 if (ServicesCell
== HCELL_NIL
) return FALSE
;
403 /* Open services key */
404 ServicesNode
= HvGetCell(Hive
, ServicesCell
);
405 ASSERT(ServicesNode
);
407 /* Get control cell */
408 RtlInitUnicodeString(&Name
, L
"Control");
409 ControlCell
= CmpFindSubKeyByName(Hive
, ControlNode
, &Name
);
410 if (ControlCell
== HCELL_NIL
) return FALSE
;
412 /* Get the group order cell and read it */
413 RtlInitUnicodeString(&Name
, L
"GroupOrderList");
414 Node
= HvGetCell(Hive
, ControlCell
);
416 GroupOrderCell
= CmpFindSubKeyByName(Hive
, Node
, &Name
);
417 if (GroupOrderCell
== HCELL_NIL
) return FALSE
;
419 /* Build the root registry path */
420 RtlInitEmptyUnicodeString(&KeyPath
, Buffer
, sizeof(Buffer
));
421 RtlAppendUnicodeToString(&KeyPath
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
423 /* Find the first subkey (ie: the first driver or service) */
425 DriverCell
= CmpFindSubKeyByNumber(Hive
, ServicesNode
, i
);
426 while (DriverCell
!= HCELL_NIL
)
428 /* Make sure it's a driver of this start type */
429 if (CmpIsLoadType(Hive
, DriverCell
, LoadType
))
431 /* Add it to the list */
432 CmpAddDriverToList(Hive
,
440 /* Try the next subkey */
441 DriverCell
= CmpFindSubKeyByNumber(Hive
, ServicesNode
, ++i
);
444 /* Check if we have a boot file system */
448 RtlInitUnicodeString(&UnicodeString
, BootFileSystem
);
449 DriverCell
= CmpFindSubKeyByName(Hive
, ServicesNode
, &UnicodeString
);
450 if (DriverCell
!= HCELL_NIL
)
452 /* Always add it to the list */
453 CmpAddDriverToList(Hive
,
459 /* Mark it as critical so it always loads */
460 FsNode
= CONTAINING_RECORD(DriverListHead
->Flink
,
463 FsNode
->ErrorControl
= SERVICE_ERROR_CRITICAL
;
474 CmpDoSort(IN PLIST_ENTRY DriverListHead
,
475 IN PUNICODE_STRING OrderList
)
477 PWCHAR Current
, End
= NULL
;
478 PLIST_ENTRY NextEntry
;
479 UNICODE_STRING GroupName
;
480 PBOOT_DRIVER_NODE CurrentNode
;
482 /* We're going from end to start, so get to the last group and keep going */
483 Current
= &OrderList
->Buffer
[OrderList
->Length
/ sizeof(WCHAR
)];
484 while (Current
> OrderList
->Buffer
)
486 /* Scan the current string */
489 if (*Current
== UNICODE_NULL
) End
= Current
;
490 } while ((*(--Current
- 1) != UNICODE_NULL
) && (Current
!= OrderList
->Buffer
));
492 /* This is our cleaned up string for this specific group */
494 GroupName
.Length
= (End
- Current
) * sizeof(WCHAR
);
495 GroupName
.MaximumLength
= GroupName
.Length
;
496 GroupName
.Buffer
= Current
;
498 /* Now loop the driver list */
499 NextEntry
= DriverListHead
->Flink
;
500 while (NextEntry
!= DriverListHead
)
503 CurrentNode
= CONTAINING_RECORD(NextEntry
,
507 /* Get the next entry now since we'll do a relink */
508 NextEntry
= CurrentNode
->ListEntry
.Link
.Flink
;
510 /* Is there a group name and does it match the current group? */
511 if ((CurrentNode
->Group
.Buffer
) &&
512 (RtlEqualUnicodeString(&GroupName
, &CurrentNode
->Group
, TRUE
)))
514 /* Remove from this location and re-link in the new one */
515 RemoveEntryList(&CurrentNode
->ListEntry
.Link
);
516 InsertHeadList(DriverListHead
, &CurrentNode
->ListEntry
.Link
);
531 CmpSortDriverList(IN PHHIVE Hive
,
532 IN HCELL_INDEX ControlSet
,
533 IN PLIST_ENTRY DriverListHead
)
535 HCELL_INDEX Controls
, GroupOrder
, ListCell
;
536 UNICODE_STRING Name
, DependList
;
537 PCM_KEY_VALUE ListNode
;
540 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
542 /* Open the control key */
543 Node
= HvGetCell(Hive
, ControlSet
);
545 RtlInitUnicodeString(&Name
, L
"Control");
546 Controls
= CmpFindSubKeyByName(Hive
, Node
, &Name
);
547 if (Controls
== HCELL_NIL
) return FALSE
;
549 /* Open the service group order */
550 Node
= HvGetCell(Hive
, Controls
);
552 RtlInitUnicodeString(&Name
, L
"ServiceGroupOrder");
553 GroupOrder
= CmpFindSubKeyByName(Hive
, Node
, &Name
);
554 if (GroupOrder
== HCELL_NIL
) return FALSE
;
556 /* Open the list key */
557 Node
= HvGetCell(Hive
, GroupOrder
);
559 RtlInitUnicodeString(&Name
, L
"list");
560 ListCell
= CmpFindValueByName(Hive
, Node
, &Name
);
561 if (ListCell
== HCELL_NIL
) return FALSE
;
563 /* Now read the actual list */
564 ListNode
= HvGetCell(Hive
, ListCell
);
566 if (ListNode
->Type
!= REG_MULTI_SZ
) return FALSE
;
568 /* Copy it into a buffer */
569 DependList
.Buffer
= (PWCHAR
)CmpValueToData(Hive
, ListNode
, &Length
);
570 if (!DependList
.Buffer
) return FALSE
;
571 DependList
.Length
= DependList
.MaximumLength
= Length
- sizeof(UNICODE_NULL
);
573 /* And start the recurive sort algorithm */
574 return CmpDoSort(DriverListHead
, &DependList
);
580 CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode
,
581 IN PBOOT_DRIVER_NODE EndNode
)
583 PBOOT_DRIVER_NODE CurrentNode
, PreviousNode
;
584 PLIST_ENTRY ListEntry
;
586 /* Base case, nothing to do */
587 if (StartNode
== EndNode
) return TRUE
;
590 CurrentNode
= StartNode
;
593 /* Save this as the previous node */
594 PreviousNode
= CurrentNode
;
596 /* And move to the next one */
597 ListEntry
= CurrentNode
->ListEntry
.Link
.Flink
;
598 CurrentNode
= CONTAINING_RECORD(ListEntry
,
602 /* Check if the previous driver had a bigger tag */
603 if (PreviousNode
->Tag
> CurrentNode
->Tag
)
605 /* Check if we need to update the tail */
606 if (CurrentNode
== EndNode
)
608 /* Update the tail */
609 ListEntry
= CurrentNode
->ListEntry
.Link
.Blink
;
610 EndNode
= CONTAINING_RECORD(ListEntry
,
615 /* Remove this driver since we need to move it */
616 RemoveEntryList(&CurrentNode
->ListEntry
.Link
);
618 /* Keep looping until we find a driver with a lower tag than ours */
619 while ((PreviousNode
->Tag
> CurrentNode
->Tag
) && (PreviousNode
!= StartNode
))
621 /* We'll be re-inserted at this spot */
622 ListEntry
= PreviousNode
->ListEntry
.Link
.Blink
;
623 PreviousNode
= CONTAINING_RECORD(ListEntry
,
628 /* Do the insert in the new location */
629 InsertTailList(&PreviousNode
->ListEntry
.Link
, &CurrentNode
->ListEntry
.Link
);
631 /* Update the head, if needed */
632 if (PreviousNode
== StartNode
) StartNode
= CurrentNode
;
634 } while (CurrentNode
!= EndNode
);
643 CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead
)
645 PLIST_ENTRY NextEntry
;
646 PBOOT_DRIVER_NODE StartNode
, EndNode
, CurrentNode
;
649 NextEntry
= DriverListHead
->Flink
;
650 while (NextEntry
!= DriverListHead
)
652 /* Find the first entry */
653 StartNode
= CONTAINING_RECORD(NextEntry
,
658 /* Find the last entry */
659 EndNode
= CONTAINING_RECORD(NextEntry
,
663 /* Get the next entry */
664 NextEntry
= NextEntry
->Flink
;
665 CurrentNode
= CONTAINING_RECORD(NextEntry
,
669 /* If the next entry is back to the top, break out */
670 if (NextEntry
== DriverListHead
) break;
672 /* Otherwise, check if this entry is equal */
673 if (!RtlEqualUnicodeString(&StartNode
->Group
,
677 /* It is, so we've detected a cycle, break out */
680 } while (NextEntry
!= DriverListHead
);
682 /* Now we have the correct start and end pointers, so do the sort */
683 CmpOrderGroup(StartNode
, EndNode
);