Sync with trunk r63935.
[reactos.git] / ntoskrnl / config / cmboot.c
1 /*
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)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "ntoskrnl.h"
13 #define NDEBUG
14 #include "debug.h"
15
16 /* GLOBALS ********************************************************************/
17
18 extern ULONG InitSafeBootMode;
19
20 /* FUNCTIONS ******************************************************************/
21
22 HCELL_INDEX
23 NTAPI
24 INIT_FUNCTION
25 CmpFindControlSet(IN PHHIVE SystemHive,
26 IN HCELL_INDEX RootCell,
27 IN PUNICODE_STRING SelectKeyName,
28 OUT PBOOLEAN AutoSelect)
29 {
30 UNICODE_STRING KeyName;
31 PCM_KEY_NODE Node;
32 HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell;
33 HCELL_INDEX CurrentValueCell;
34 PCM_KEY_VALUE KeyValue;
35 ULONG Length;
36 PULONG ControlSetId;
37 ANSI_STRING ControlSetAnsiName;
38 CHAR Buffer[128];
39 WCHAR WideBuffer[128];
40 NTSTATUS Status;
41 PULONG CurrentData;
42
43 /* Sanity check */
44 ASSERT(SystemHive->ReleaseCellRoutine == NULL);
45
46 /* Get the Select subkey */
47 RtlInitUnicodeString(&KeyName, L"select");
48 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell);
49 if (!Node) return HCELL_NIL;
50 SelectCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName);
51 if (SelectCell == HCELL_NIL) return SelectCell;
52
53 /* Get AutoSelect value */
54 RtlInitUnicodeString(&KeyName, L"AutoSelect");
55 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
56 if (!Node) return HCELL_NIL;
57 AutoSelectCell = CmpFindValueByName(SystemHive, Node, &KeyName);
58 if (AutoSelectCell == HCELL_NIL)
59 {
60 /* Assume TRUE if the value is missing. */
61 *AutoSelect = TRUE;
62 }
63 else
64 {
65 /* Read the value */
66 KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell);
67 if (KeyValue == NULL) return HCELL_NIL;
68
69 /* Convert it to a boolean */
70 *AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length);
71 }
72
73 /* Now find the control set being looked up */
74 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
75 if (!Node) return HCELL_NIL;
76 SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName);
77 if (SelectValueCell == HCELL_NIL) return SelectValueCell;
78
79 /* Read the value (corresponding to the CCS ID) */
80 KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell);
81 if (!KeyValue) return HCELL_NIL;
82 if (KeyValue->Type != REG_DWORD) return HCELL_NIL;
83 ControlSetId = (PULONG)CmpValueToData(SystemHive, KeyValue, &Length);
84
85 /* Now build an Ansi String for the CCS's Name */
86 sprintf(Buffer, "ControlSet%03lu", *ControlSetId);
87 ControlSetAnsiName.Length = (USHORT)strlen(Buffer);
88 ControlSetAnsiName.MaximumLength = (USHORT)strlen(Buffer);
89 ControlSetAnsiName.Buffer = Buffer;
90
91 /* And convert it to Unicode... */
92 KeyName.MaximumLength = 256;
93 KeyName.Buffer = WideBuffer;
94 Status = RtlAnsiStringToUnicodeString(&KeyName,
95 &ControlSetAnsiName,
96 FALSE);
97 if (!NT_SUCCESS(Status)) return HCELL_NIL;
98
99 /* Now open it */
100 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell);
101 if (!Node) return HCELL_NIL;
102 ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName);
103 if (ControlSetCell == HCELL_NIL) return ControlSetCell;
104
105 /* Get the value of the "Current" CCS */
106 RtlInitUnicodeString(&KeyName, L"Current");
107 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
108 if (!Node) return HCELL_NIL;
109 CurrentValueCell = CmpFindValueByName(SystemHive, Node, &KeyName);
110
111 /* Make sure it exists */
112 if (CurrentValueCell != HCELL_NIL)
113 {
114 /* Get the current value and make sure its a ULONG */
115 KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell);
116 if (!KeyValue) return HCELL_NIL;
117 if (KeyValue->Type == REG_DWORD)
118 {
119 /* Get the data and update it */
120 CurrentData = (PULONG)CmpValueToData(SystemHive,
121 KeyValue,
122 &Length);
123 if (!CurrentData) return HCELL_NIL;
124 *CurrentData = *ControlSetId;
125 }
126 }
127
128 /* Return the CCS Cell */
129 return ControlSetCell;
130 }
131
132 ULONG
133 NTAPI
134 INIT_FUNCTION
135 CmpFindTagIndex(IN PHHIVE Hive,
136 IN HCELL_INDEX TagCell,
137 IN HCELL_INDEX GroupOrderCell,
138 IN PUNICODE_STRING GroupName)
139 {
140 PCM_KEY_VALUE TagValue, Value;
141 HCELL_INDEX OrderCell;
142 PULONG TagOrder, DriverTag;
143 ULONG CurrentTag, Length;
144 PCM_KEY_NODE Node;
145 BOOLEAN BufferAllocated;
146 ASSERT(Hive->ReleaseCellRoutine == NULL);
147
148 /* Get the tag */
149 Value = HvGetCell(Hive, TagCell);
150 ASSERT(Value);
151 DriverTag = (PULONG)CmpValueToData(Hive, Value, &Length);
152 ASSERT(DriverTag);
153
154 /* Get the order array */
155 Node = HvGetCell(Hive, GroupOrderCell);
156 ASSERT(Node);
157 OrderCell = CmpFindValueByName(Hive, Node, GroupName);
158 if (OrderCell == HCELL_NIL) return -2;
159
160 /* And read it */
161 TagValue = HvGetCell(Hive, OrderCell);
162 CmpGetValueData(Hive, TagValue, &Length, (PVOID*)&TagOrder, &BufferAllocated, &OrderCell);
163 ASSERT(TagOrder);
164
165 /* Parse each tag */
166 for (CurrentTag = 1; CurrentTag <= TagOrder[0]; CurrentTag++)
167 {
168 /* Find a match */
169 if (TagOrder[CurrentTag] == *DriverTag)
170 {
171 /* Found it -- return the tag */
172 if (BufferAllocated) ExFreePool(TagOrder);
173 return CurrentTag;
174 }
175 }
176
177 /* No matches, so assume next to last ordering */
178 if (BufferAllocated) ExFreePool(TagOrder);
179 return -2;
180 }
181
182 BOOLEAN
183 NTAPI
184 INIT_FUNCTION
185 CmpAddDriverToList(IN PHHIVE Hive,
186 IN HCELL_INDEX DriverCell,
187 IN HCELL_INDEX GroupOrderCell,
188 IN PUNICODE_STRING RegistryPath,
189 IN PLIST_ENTRY BootDriverListHead)
190 {
191 PBOOT_DRIVER_NODE DriverNode;
192 PBOOT_DRIVER_LIST_ENTRY DriverEntry;
193 PCM_KEY_NODE Node;
194 ULONG Length;
195 USHORT NameLength;
196 HCELL_INDEX ValueCell, TagCell; PCM_KEY_VALUE Value;
197 PUNICODE_STRING FileName, RegistryString;
198 UNICODE_STRING UnicodeString;
199 PULONG ErrorControl;
200 PWCHAR Buffer;
201 ASSERT(Hive->ReleaseCellRoutine == NULL);
202
203 /* Allocate a driver node and initialize it */
204 DriverNode = CmpAllocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM);
205 if (!DriverNode) return FALSE;
206 DriverEntry = &DriverNode->ListEntry;
207 DriverEntry->RegistryPath.Buffer = NULL;
208 DriverEntry->FilePath.Buffer = NULL;
209
210 /* Get the driver cell */
211 Node = HvGetCell(Hive, DriverCell);
212 ASSERT(Node);
213
214 /* Get the name from the cell */
215 DriverNode->Name.Length = Node->Flags & KEY_COMP_NAME ?
216 CmpCompressedNameSize(Node->Name, Node->NameLength) :
217 Node->NameLength;
218 DriverNode->Name.MaximumLength = DriverNode->Name.Length;
219 NameLength = DriverNode->Name.Length;
220
221 /* Now allocate the buffer for it and copy the name */
222 DriverNode->Name.Buffer = CmpAllocate(NameLength, FALSE, TAG_CM);
223 if (!DriverNode->Name.Buffer) return FALSE;
224 if (Node->Flags & KEY_COMP_NAME)
225 {
226 /* Compressed name */
227 CmpCopyCompressedName(DriverNode->Name.Buffer,
228 DriverNode->Name.Length,
229 Node->Name,
230 Node->NameLength);
231 }
232 else
233 {
234 /* Normal name */
235 RtlCopyMemory(DriverNode->Name.Buffer, Node->Name, Node->NameLength);
236 }
237
238 /* Now find the image path */
239 RtlInitUnicodeString(&UnicodeString, L"ImagePath");
240 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
241 if (ValueCell == HCELL_NIL)
242 {
243 /* Couldn't find it, so assume the drivers path */
244 Length = sizeof(L"System32\\Drivers\\") + NameLength + sizeof(L".sys");
245
246 /* Allocate the path name */
247 FileName = &DriverEntry->FilePath;
248 FileName->Length = 0;
249 FileName->MaximumLength = (USHORT)Length;
250 FileName->Buffer = CmpAllocate(Length, FALSE,TAG_CM);
251 if (!FileName->Buffer) return FALSE;
252
253 /* Write the path name */
254 RtlAppendUnicodeToString(FileName, L"System32\\Drivers\\");
255 RtlAppendUnicodeStringToString(FileName, &DriverNode->Name);
256 RtlAppendUnicodeToString(FileName, L".sys");
257 }
258 else
259 {
260 /* Path name exists, so grab it */
261 Value = HvGetCell(Hive, ValueCell);
262 ASSERT(Value);
263
264 /* Allocate and setup the path name */
265 FileName = &DriverEntry->FilePath;
266 Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length);
267 FileName->MaximumLength = FileName->Length = (USHORT)Length;
268 FileName->Buffer = CmpAllocate(Length, FALSE, TAG_CM);
269
270 /* Transfer the data */
271 if (!(FileName->Buffer) || !(Buffer)) return FALSE;
272 RtlCopyMemory(FileName->Buffer, Buffer, Length);
273 }
274
275 /* Now build the registry path */
276 RegistryString = &DriverEntry->RegistryPath;
277 RegistryString->Length = 0;
278 RegistryString->MaximumLength = RegistryPath->Length + NameLength;
279 RegistryString->Buffer = CmpAllocate(RegistryString->MaximumLength, FALSE, TAG_CM);
280 if (!RegistryString->Buffer) return FALSE;
281
282 /* Add the driver name to it */
283 RtlAppendUnicodeStringToString(RegistryString, RegistryPath);
284 RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name);
285
286 /* The entry is done, add it */
287 InsertHeadList(BootDriverListHead, &DriverEntry->Link);
288
289 /* Now find error control settings */
290 RtlInitUnicodeString(&UnicodeString, L"ErrorControl");
291 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
292 if (ValueCell == HCELL_NIL)
293 {
294 /* Couldn't find it, so assume default */
295 DriverNode->ErrorControl = NormalError;
296 }
297 else
298 {
299 /* Otherwise, read whatever the data says */
300 Value = HvGetCell(Hive, ValueCell);
301 ASSERT(Value);
302 ErrorControl = (PULONG)CmpValueToData(Hive, Value, &Length);
303 ASSERT(ErrorControl);
304 DriverNode->ErrorControl = *ErrorControl;
305 }
306
307 /* Next, get the group cell */
308 RtlInitUnicodeString(&UnicodeString, L"group");
309 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
310 if (ValueCell == HCELL_NIL)
311 {
312 /* Couldn't find, so set an empty string */
313 RtlInitEmptyUnicodeString(&DriverNode->Group, NULL, 0);
314 }
315 else
316 {
317 /* Found it, read the group value */
318 Value = HvGetCell(Hive, ValueCell);
319 ASSERT(Value);
320
321 /* Copy it into the node */
322 DriverNode->Group.Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length);
323 if (!DriverNode->Group.Buffer) return FALSE;
324 DriverNode->Group.Length = (USHORT)Length - sizeof(UNICODE_NULL);
325 DriverNode->Group.MaximumLength = DriverNode->Group.Length;
326 }
327
328 /* Finally, find the tag */
329 RtlInitUnicodeString(&UnicodeString, L"Tag");
330 TagCell = CmpFindValueByName(Hive, Node, &UnicodeString);
331 if (TagCell == HCELL_NIL)
332 {
333 /* No tag, so load last */
334 DriverNode->Tag = -1;
335 }
336 else
337 {
338 /* Otherwise, decode it based on tag order */
339 DriverNode->Tag = CmpFindTagIndex(Hive,
340 TagCell,
341 GroupOrderCell,
342 &DriverNode->Group);
343 }
344
345 /* All done! */
346 return TRUE;
347 }
348
349 BOOLEAN
350 NTAPI
351 INIT_FUNCTION
352 CmpIsLoadType(IN PHHIVE Hive,
353 IN HCELL_INDEX Cell,
354 IN SERVICE_LOAD_TYPE LoadType)
355 {
356 PCM_KEY_NODE Node;
357 HCELL_INDEX ValueCell;
358 UNICODE_STRING ValueString = RTL_CONSTANT_STRING(L"Start");
359 PCM_KEY_VALUE Value;
360 ULONG Length;
361 PLONG Data;
362 ASSERT(Hive->ReleaseCellRoutine == NULL);
363
364 /* Open the start cell */
365 Node = HvGetCell(Hive, Cell);
366 ASSERT(Node);
367 ValueCell = CmpFindValueByName(Hive, Node, &ValueString);
368 if (ValueCell == HCELL_NIL) return FALSE;
369
370 /* Read the start value */
371 Value = HvGetCell(Hive, ValueCell);
372 ASSERT(Value);
373 Data = (PLONG)CmpValueToData(Hive, Value, &Length);
374 ASSERT(Data);
375
376 /* Return if the type matches */
377 return (*Data == LoadType);
378 }
379
380 BOOLEAN
381 NTAPI
382 INIT_FUNCTION
383 CmpFindDrivers(IN PHHIVE Hive,
384 IN HCELL_INDEX ControlSet,
385 IN SERVICE_LOAD_TYPE LoadType,
386 IN PWCHAR BootFileSystem OPTIONAL,
387 IN PLIST_ENTRY DriverListHead)
388 {
389 HCELL_INDEX ServicesCell, ControlCell, GroupOrderCell, DriverCell;
390 HCELL_INDEX SafeBootCell = HCELL_NIL;
391 UNICODE_STRING Name;
392 ULONG i;
393 WCHAR Buffer[128];
394 UNICODE_STRING UnicodeString, KeyPath;
395 PBOOT_DRIVER_NODE FsNode;
396 PCM_KEY_NODE ControlNode, ServicesNode, Node;
397 ASSERT(Hive->ReleaseCellRoutine == NULL);
398
399 /* Open the control set key */
400 ControlNode = HvGetCell(Hive, ControlSet);
401 ASSERT(ControlNode);
402
403 /* Get services cell */
404 RtlInitUnicodeString(&Name, L"Services");
405 ServicesCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
406 if (ServicesCell == HCELL_NIL) return FALSE;
407
408 /* Open services key */
409 ServicesNode = HvGetCell(Hive, ServicesCell);
410 ASSERT(ServicesNode);
411
412 /* Get control cell */
413 RtlInitUnicodeString(&Name, L"Control");
414 ControlCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
415 if (ControlCell == HCELL_NIL) return FALSE;
416
417 /* Get the group order cell and read it */
418 RtlInitUnicodeString(&Name, L"GroupOrderList");
419 Node = HvGetCell(Hive, ControlCell);
420 ASSERT(Node);
421 GroupOrderCell = CmpFindSubKeyByName(Hive, Node, &Name);
422 if (GroupOrderCell == HCELL_NIL) return FALSE;
423
424 /* Get Safe Boot cell */
425 if(InitSafeBootMode)
426 {
427 /* Open the Safe Boot key */
428 RtlInitUnicodeString(&Name, L"SafeBoot");
429 Node = HvGetCell(Hive, ControlCell);
430 ASSERT(Node);
431 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
432 if (SafeBootCell == HCELL_NIL) return FALSE;
433
434 /* Open the correct start key (depending on the mode) */
435 Node = HvGetCell(Hive, SafeBootCell);
436 ASSERT(Node);
437 switch(InitSafeBootMode)
438 {
439 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
440 case 1:
441 case 3: RtlInitUnicodeString(&Name, L"Minimal"); break;
442 case 2: RtlInitUnicodeString(&Name, L"Network"); break;
443 default: return FALSE;
444 }
445 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
446 if(SafeBootCell == HCELL_NIL) return FALSE;
447 }
448
449 /* Build the root registry path */
450 RtlInitEmptyUnicodeString(&KeyPath, Buffer, sizeof(Buffer));
451 RtlAppendUnicodeToString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
452
453 /* Find the first subkey (ie: the first driver or service) */
454 i = 0;
455 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, i);
456 while (DriverCell != HCELL_NIL)
457 {
458 /* Make sure it's a driver of this start type AND is "safe" to load */
459 if (CmpIsLoadType(Hive, DriverCell, LoadType) &&
460 CmpIsSafe(Hive, SafeBootCell, DriverCell))
461 {
462 /* Add it to the list */
463 CmpAddDriverToList(Hive,
464 DriverCell,
465 GroupOrderCell,
466 &KeyPath,
467 DriverListHead);
468
469 }
470
471 /* Try the next subkey */
472 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, ++i);
473 }
474
475 /* Check if we have a boot file system */
476 if (BootFileSystem)
477 {
478 /* Find it */
479 RtlInitUnicodeString(&UnicodeString, BootFileSystem);
480 DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &UnicodeString);
481 if (DriverCell != HCELL_NIL)
482 {
483 /* Always add it to the list */
484 CmpAddDriverToList(Hive,
485 DriverCell,
486 GroupOrderCell,
487 &KeyPath,
488 DriverListHead);
489
490 /* Mark it as critical so it always loads */
491 FsNode = CONTAINING_RECORD(DriverListHead->Flink,
492 BOOT_DRIVER_NODE,
493 ListEntry.Link);
494 FsNode->ErrorControl = SERVICE_ERROR_CRITICAL;
495 }
496 }
497
498 /* We're done! */
499 return TRUE;
500 }
501
502 BOOLEAN
503 NTAPI
504 INIT_FUNCTION
505 CmpDoSort(IN PLIST_ENTRY DriverListHead,
506 IN PUNICODE_STRING OrderList)
507 {
508 PWCHAR Current, End = NULL;
509 PLIST_ENTRY NextEntry;
510 UNICODE_STRING GroupName;
511 PBOOT_DRIVER_NODE CurrentNode;
512
513 /* We're going from end to start, so get to the last group and keep going */
514 Current = &OrderList->Buffer[OrderList->Length / sizeof(WCHAR)];
515 while (Current > OrderList->Buffer)
516 {
517 /* Scan the current string */
518 do
519 {
520 if (*Current == UNICODE_NULL) End = Current;
521 } while ((*(--Current - 1) != UNICODE_NULL) && (Current != OrderList->Buffer));
522
523 /* This is our cleaned up string for this specific group */
524 ASSERT(End != NULL);
525 GroupName.Length = (USHORT)(End - Current) * sizeof(WCHAR);
526 GroupName.MaximumLength = GroupName.Length;
527 GroupName.Buffer = Current;
528
529 /* Now loop the driver list */
530 NextEntry = DriverListHead->Flink;
531 while (NextEntry != DriverListHead)
532 {
533 /* Get this node */
534 CurrentNode = CONTAINING_RECORD(NextEntry,
535 BOOT_DRIVER_NODE,
536 ListEntry.Link);
537
538 /* Get the next entry now since we'll do a relink */
539 NextEntry = CurrentNode->ListEntry.Link.Flink;
540
541 /* Is there a group name and does it match the current group? */
542 if ((CurrentNode->Group.Buffer) &&
543 (RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE)))
544 {
545 /* Remove from this location and re-link in the new one */
546 RemoveEntryList(&CurrentNode->ListEntry.Link);
547 InsertHeadList(DriverListHead, &CurrentNode->ListEntry.Link);
548 }
549 }
550
551 /* Move on */
552 Current--;
553 }
554
555 /* All done */
556 return TRUE;
557 }
558
559 BOOLEAN
560 NTAPI
561 INIT_FUNCTION
562 CmpSortDriverList(IN PHHIVE Hive,
563 IN HCELL_INDEX ControlSet,
564 IN PLIST_ENTRY DriverListHead)
565 {
566 HCELL_INDEX Controls, GroupOrder, ListCell;
567 UNICODE_STRING Name, DependList;
568 PCM_KEY_VALUE ListNode;
569 ULONG Length;
570 PCM_KEY_NODE Node;
571 ASSERT(Hive->ReleaseCellRoutine == NULL);
572
573 /* Open the control key */
574 Node = HvGetCell(Hive, ControlSet);
575 ASSERT(Node);
576 RtlInitUnicodeString(&Name, L"Control");
577 Controls = CmpFindSubKeyByName(Hive, Node, &Name);
578 if (Controls == HCELL_NIL) return FALSE;
579
580 /* Open the service group order */
581 Node = HvGetCell(Hive, Controls);
582 ASSERT(Node);
583 RtlInitUnicodeString(&Name, L"ServiceGroupOrder");
584 GroupOrder = CmpFindSubKeyByName(Hive, Node, &Name);
585 if (GroupOrder == HCELL_NIL) return FALSE;
586
587 /* Open the list key */
588 Node = HvGetCell(Hive, GroupOrder);
589 ASSERT(Node);
590 RtlInitUnicodeString(&Name, L"list");
591 ListCell = CmpFindValueByName(Hive, Node, &Name);
592 if (ListCell == HCELL_NIL) return FALSE;
593
594 /* Now read the actual list */
595 ListNode = HvGetCell(Hive, ListCell);
596 ASSERT(ListNode);
597 if (ListNode->Type != REG_MULTI_SZ) return FALSE;
598
599 /* Copy it into a buffer */
600 DependList.Buffer = (PWCHAR)CmpValueToData(Hive, ListNode, &Length);
601 if (!DependList.Buffer) return FALSE;
602 DependList.Length = DependList.MaximumLength = (USHORT)Length - sizeof(UNICODE_NULL);
603
604 /* And start the recurive sort algorithm */
605 return CmpDoSort(DriverListHead, &DependList);
606 }
607
608 BOOLEAN
609 NTAPI
610 INIT_FUNCTION
611 CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode,
612 IN PBOOT_DRIVER_NODE EndNode)
613 {
614 PBOOT_DRIVER_NODE CurrentNode, PreviousNode;
615 PLIST_ENTRY ListEntry;
616
617 /* Base case, nothing to do */
618 if (StartNode == EndNode) return TRUE;
619
620 /* Loop the nodes */
621 CurrentNode = StartNode;
622 do
623 {
624 /* Save this as the previous node */
625 PreviousNode = CurrentNode;
626
627 /* And move to the next one */
628 ListEntry = CurrentNode->ListEntry.Link.Flink;
629 CurrentNode = CONTAINING_RECORD(ListEntry,
630 BOOT_DRIVER_NODE,
631 ListEntry.Link);
632
633 /* Check if the previous driver had a bigger tag */
634 if (PreviousNode->Tag > CurrentNode->Tag)
635 {
636 /* Check if we need to update the tail */
637 if (CurrentNode == EndNode)
638 {
639 /* Update the tail */
640 ListEntry = CurrentNode->ListEntry.Link.Blink;
641 EndNode = CONTAINING_RECORD(ListEntry,
642 BOOT_DRIVER_NODE,
643 ListEntry.Link);
644 }
645
646 /* Remove this driver since we need to move it */
647 RemoveEntryList(&CurrentNode->ListEntry.Link);
648
649 /* Keep looping until we find a driver with a lower tag than ours */
650 while ((PreviousNode->Tag > CurrentNode->Tag) && (PreviousNode != StartNode))
651 {
652 /* We'll be re-inserted at this spot */
653 ListEntry = PreviousNode->ListEntry.Link.Blink;
654 PreviousNode = CONTAINING_RECORD(ListEntry,
655 BOOT_DRIVER_NODE,
656 ListEntry.Link);
657 }
658
659 /* Do the insert in the new location */
660 InsertTailList(&PreviousNode->ListEntry.Link, &CurrentNode->ListEntry.Link);
661
662 /* Update the head, if needed */
663 if (PreviousNode == StartNode) StartNode = CurrentNode;
664 }
665 } while (CurrentNode != EndNode);
666
667 /* All done */
668 return TRUE;
669 }
670
671 BOOLEAN
672 NTAPI
673 INIT_FUNCTION
674 CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead)
675 {
676 PLIST_ENTRY NextEntry;
677 PBOOT_DRIVER_NODE StartNode, EndNode, CurrentNode;
678
679 /* Loop the list */
680 NextEntry = DriverListHead->Flink;
681 while (NextEntry != DriverListHead)
682 {
683 /* Find the first entry */
684 StartNode = CONTAINING_RECORD(NextEntry,
685 BOOT_DRIVER_NODE,
686 ListEntry.Link);
687 do
688 {
689 /* Find the last entry */
690 EndNode = CONTAINING_RECORD(NextEntry,
691 BOOT_DRIVER_NODE,
692 ListEntry.Link);
693
694 /* Get the next entry */
695 NextEntry = NextEntry->Flink;
696 CurrentNode = CONTAINING_RECORD(NextEntry,
697 BOOT_DRIVER_NODE,
698 ListEntry.Link);
699
700 /* If the next entry is back to the top, break out */
701 if (NextEntry == DriverListHead) break;
702
703 /* Otherwise, check if this entry is equal */
704 if (!RtlEqualUnicodeString(&StartNode->Group,
705 &CurrentNode->Group,
706 TRUE))
707 {
708 /* It is, so we've detected a cycle, break out */
709 break;
710 }
711 } while (NextEntry != DriverListHead);
712
713 /* Now we have the correct start and end pointers, so do the sort */
714 CmpOrderGroup(StartNode, EndNode);
715 }
716
717 /* We're done */
718 return TRUE;
719 }
720
721 BOOLEAN
722 NTAPI
723 INIT_FUNCTION
724 CmpIsSafe(IN PHHIVE Hive,
725 IN HCELL_INDEX SafeBootCell,
726 IN HCELL_INDEX DriverCell)
727 {
728 PCM_KEY_NODE SafeBootNode;
729 PCM_KEY_NODE DriverNode;
730 PCM_KEY_VALUE KeyValue;
731 HCELL_INDEX CellIndex;
732 ULONG Length = 0;
733 UNICODE_STRING Name;
734 PWCHAR OriginalName;
735 ASSERT(Hive->ReleaseCellRoutine == NULL);
736
737 /* Driver key node (mandatory) */
738 ASSERT(DriverCell != HCELL_NIL);
739 DriverNode = HvGetCell(Hive, DriverCell);
740 ASSERT(DriverNode);
741
742 /* Safe boot key node (optional but return TRUE if not present) */
743 if(SafeBootCell == HCELL_NIL) return TRUE;
744 SafeBootNode = HvGetCell(Hive, SafeBootCell);
745 if(!SafeBootNode) return FALSE;
746
747 /* Search by the name from the group */
748 RtlInitUnicodeString(&Name, L"Group");
749 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
750 if(CellIndex != HCELL_NIL)
751 {
752 KeyValue = HvGetCell(Hive, CellIndex);
753 ASSERT(KeyValue);
754 if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ)
755 {
756 /* Compose the search 'key' */
757 Name.Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
758 if (!Name.Buffer) return FALSE;
759 Name.Length = (USHORT)Length - sizeof(UNICODE_NULL);
760 Name.MaximumLength = Name.Length;
761 /* Search for corresponding key in the Safe Boot key */
762 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
763 if(CellIndex != HCELL_NIL) return TRUE;
764 }
765 }
766
767 /* Group has not been found - find driver name */
768 Name.Length = DriverNode->Flags & KEY_COMP_NAME ?
769 CmpCompressedNameSize(DriverNode->Name,
770 DriverNode->NameLength) :
771 DriverNode->NameLength;
772 Name.MaximumLength = Name.Length;
773 /* Now allocate the buffer for it and copy the name */
774 Name.Buffer = CmpAllocate(Name.Length, FALSE, TAG_CM);
775 if (!Name.Buffer) return FALSE;
776 if (DriverNode->Flags & KEY_COMP_NAME)
777 {
778 /* Compressed name */
779 CmpCopyCompressedName(Name.Buffer,
780 Name.Length,
781 DriverNode->Name,
782 DriverNode->NameLength);
783 }
784 else
785 {
786 /* Normal name */
787 RtlCopyMemory(Name.Buffer, DriverNode->Name, DriverNode->NameLength);
788 }
789 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
790 RtlFreeUnicodeString(&Name);
791 if(CellIndex != HCELL_NIL) return TRUE;
792
793 /* Not group or driver name - search by image name */
794 RtlInitUnicodeString(&Name, L"ImagePath");
795 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
796 if(CellIndex != HCELL_NIL)
797 {
798 KeyValue = HvGetCell(Hive, CellIndex);
799 ASSERT(KeyValue);
800 if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ)
801 {
802 /* Compose the search 'key' */
803 OriginalName = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
804 if (!OriginalName) return FALSE;
805 /* Get the base image file name */
806 Name.Buffer = wcsrchr(OriginalName, L'\\');
807 if (!Name.Buffer) return FALSE;
808 ++Name.Buffer;
809 /* Length of the base name must be >=1 */
810 Name.Length = (USHORT)Length - (USHORT)((PUCHAR)Name.Buffer - (PUCHAR)OriginalName)
811 - sizeof(UNICODE_NULL);
812 if(Name.Length < 1) return FALSE;
813 Name.MaximumLength = Name.Length;
814 /* Search for corresponding key in the Safe Boot key */
815 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
816 if(CellIndex != HCELL_NIL) return TRUE;
817 }
818 }
819 /* Nothing found - nothing else to search */
820 return FALSE;
821 }
822
823 /* EOF */