1416c4dfe010f0e4a100bda24b3fea08251c7543
[reactos.git] / reactos / 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 /* FUNCTIONS ******************************************************************/
17
18 HCELL_INDEX
19 NTAPI
20 INIT_FUNCTION
21 CmpFindControlSet(IN PHHIVE SystemHive,
22 IN HCELL_INDEX RootCell,
23 IN PUNICODE_STRING SelectKeyName,
24 OUT PBOOLEAN AutoSelect)
25 {
26 UNICODE_STRING KeyName;
27 PCM_KEY_NODE Node;
28 HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell;
29 HCELL_INDEX CurrentValueCell;
30 PCM_KEY_VALUE KeyValue;
31 ULONG Length;
32 PULONG ControlSetId;
33 ANSI_STRING ControlSetAnsiName;
34 CHAR Buffer[128];
35 WCHAR WideBuffer[128];
36 NTSTATUS Status;
37 PULONG CurrentData;
38
39 /* Sanity check */
40 ASSERT(SystemHive->ReleaseCellRoutine == NULL);
41
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;
48
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)
55 {
56 /* Assume TRUE if the value is missing. */
57 *AutoSelect = TRUE;
58 }
59 else
60 {
61 /* Read the value */
62 KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell);
63 if (KeyValue == NULL) return HCELL_NIL;
64
65 /* Convert it to a boolean */
66 *AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length);
67 }
68
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;
74
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);
80
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;
86
87 /* And convert it to Unicode... */
88 KeyName.MaximumLength = 256;
89 KeyName.Buffer = WideBuffer;
90 Status = RtlAnsiStringToUnicodeString(&KeyName,
91 &ControlSetAnsiName,
92 FALSE);
93 if (!NT_SUCCESS(Status)) return HCELL_NIL;
94
95 /* Now open it */
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;
100
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);
106
107 /* Make sure it exists */
108 if (CurrentValueCell != HCELL_NIL)
109 {
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)
114 {
115 /* Get the data and update it */
116 CurrentData = (PULONG)CmpValueToData(SystemHive,
117 KeyValue,
118 &Length);
119 if (!CurrentData) return HCELL_NIL;
120 *CurrentData = *ControlSetId;
121 }
122 }
123
124 /* Return the CCS Cell */
125 return ControlSetCell;
126 }
127
128 ULONG
129 NTAPI
130 INIT_FUNCTION
131 CmpFindTagIndex(IN PHHIVE Hive,
132 IN HCELL_INDEX TagCell,
133 IN HCELL_INDEX GroupOrderCell,
134 IN PUNICODE_STRING GroupName)
135 {
136 PCM_KEY_VALUE TagValue, Value;
137 HCELL_INDEX OrderCell;
138 PULONG TagOrder, DriverTag;
139 ULONG CurrentTag, Length;
140 PCM_KEY_NODE Node;
141 BOOLEAN BufferAllocated;
142 ASSERT(Hive->ReleaseCellRoutine == NULL);
143
144 /* Get the tag */
145 Value = HvGetCell(Hive, TagCell);
146 ASSERT(Value);
147 DriverTag = (PULONG)CmpValueToData(Hive, Value, &Length);
148 ASSERT(DriverTag);
149
150 /* Get the order array */
151 Node = HvGetCell(Hive, GroupOrderCell);
152 ASSERT(Node);
153 OrderCell = CmpFindValueByName(Hive, Node, GroupName);
154 if (OrderCell == HCELL_NIL) return -2;
155
156 /* And read it */
157 TagValue = HvGetCell(Hive, OrderCell);
158 CmpGetValueData(Hive, TagValue, &Length, (PVOID*)&TagOrder, &BufferAllocated, &OrderCell);
159 ASSERT(TagOrder);
160
161 /* Parse each tag */
162 for (CurrentTag = 1; CurrentTag <= TagOrder[0]; CurrentTag++)
163 {
164 /* Find a match */
165 if (TagOrder[CurrentTag] == *DriverTag)
166 {
167 /* Found it -- return the tag */
168 if (BufferAllocated) ExFreePool(TagOrder);
169 return CurrentTag;
170 }
171 }
172
173 /* No matches, so assume next to last ordering */
174 if (BufferAllocated) ExFreePool(TagOrder);
175 return -2;
176 }
177
178 BOOLEAN
179 NTAPI
180 INIT_FUNCTION
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)
186 {
187 PBOOT_DRIVER_NODE DriverNode;
188 PBOOT_DRIVER_LIST_ENTRY DriverEntry;
189 PCM_KEY_NODE Node;
190 ULONG NameLength, Length;
191 HCELL_INDEX ValueCell, TagCell;
192 PCM_KEY_VALUE Value;
193 PUNICODE_STRING FileName, RegistryString;
194 UNICODE_STRING UnicodeString;
195 PULONG ErrorControl;
196 PWCHAR Buffer;
197 ASSERT(Hive->ReleaseCellRoutine == NULL);
198
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;
205
206 /* Get the driver cell */
207 Node = HvGetCell(Hive, DriverCell);
208 ASSERT(Node);
209
210 /* Get the name from the cell */
211 DriverNode->Name.Length = Node->Flags & KEY_COMP_NAME ?
212 CmpCompressedNameSize(Node->Name, Node->NameLength) :
213 Node->NameLength;
214 DriverNode->Name.MaximumLength = DriverNode->Name.Length;
215 NameLength = DriverNode->Name.Length;
216
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)
221 {
222 /* Compressed name */
223 CmpCopyCompressedName(DriverNode->Name.Buffer,
224 DriverNode->Name.Length,
225 Node->Name,
226 Node->NameLength);
227 }
228 else
229 {
230 /* Normal name */
231 RtlCopyMemory(DriverNode->Name.Buffer, Node->Name, Node->NameLength);
232 }
233
234 /* Now find the image path */
235 RtlInitUnicodeString(&UnicodeString, L"ImagePath");
236 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
237 if (ValueCell == HCELL_NIL)
238 {
239 /* Couldn't find it, so assume the drivers path */
240 Length = sizeof(L"System32\\Drivers\\") + NameLength + sizeof(L".sys");
241
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;
248
249 /* Write the path name */
250 RtlAppendUnicodeToString(FileName, L"System32\\Drivers\\");
251 RtlAppendUnicodeStringToString(FileName, &DriverNode->Name);
252 RtlAppendUnicodeToString(FileName, L".sys");
253 }
254 else
255 {
256 /* Path name exists, so grab it */
257 Value = HvGetCell(Hive, ValueCell);
258 ASSERT(Value);
259
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);
265
266 /* Transfer the data */
267 if (!(FileName->Buffer) || !(Buffer)) return FALSE;
268 RtlCopyMemory(FileName->Buffer, Buffer, Length);
269 }
270
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;
277
278 /* Add the driver name to it */
279 RtlAppendUnicodeStringToString(RegistryString, RegistryPath);
280 RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name);
281
282 /* The entry is done, add it */
283 InsertHeadList(BootDriverListHead, &DriverEntry->Link);
284
285 /* Now find error control settings */
286 RtlInitUnicodeString(&UnicodeString, L"ErrorControl");
287 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
288 if (ValueCell == HCELL_NIL)
289 {
290 /* Couldn't find it, so assume default */
291 DriverNode->ErrorControl = NormalError;
292 }
293 else
294 {
295 /* Otherwise, read whatever the data says */
296 Value = HvGetCell(Hive, ValueCell);
297 ASSERT(Value);
298 ErrorControl = (PULONG)CmpValueToData(Hive, Value, &Length);
299 ASSERT(ErrorControl);
300 DriverNode->ErrorControl = *ErrorControl;
301 }
302
303 /* Next, get the group cell */
304 RtlInitUnicodeString(&UnicodeString, L"group");
305 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString);
306 if (ValueCell == HCELL_NIL)
307 {
308 /* Couldn't find, so set an empty string */
309 RtlInitEmptyUnicodeString(&DriverNode->Group, NULL, 0);
310 }
311 else
312 {
313 /* Found it, read the group value */
314 Value = HvGetCell(Hive, ValueCell);
315 ASSERT(Value);
316
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;
322 }
323
324 /* Finally, find the tag */
325 RtlInitUnicodeString(&UnicodeString, L"Tag");
326 TagCell = CmpFindValueByName(Hive, Node, &UnicodeString);
327 if (TagCell == HCELL_NIL)
328 {
329 /* No tag, so load last */
330 DriverNode->Tag = -1;
331 }
332 else
333 {
334 /* Otherwise, decode it based on tag order */
335 DriverNode->Tag = CmpFindTagIndex(Hive,
336 TagCell,
337 GroupOrderCell,
338 &DriverNode->Group);
339 }
340
341 /* All done! */
342 return TRUE;
343 }
344
345 BOOLEAN
346 NTAPI
347 INIT_FUNCTION
348 CmpIsLoadType(IN PHHIVE Hive,
349 IN HCELL_INDEX Cell,
350 IN SERVICE_LOAD_TYPE LoadType)
351 {
352 PCM_KEY_NODE Node;
353 HCELL_INDEX ValueCell;
354 UNICODE_STRING ValueString = RTL_CONSTANT_STRING(L"Start");
355 PCM_KEY_VALUE Value;
356 ULONG Length;
357 PLONG Data;
358 ASSERT(Hive->ReleaseCellRoutine == NULL);
359
360 /* Open the start cell */
361 Node = HvGetCell(Hive, Cell);
362 ASSERT(Node);
363 ValueCell = CmpFindValueByName(Hive, Node, &ValueString);
364 if (ValueCell == HCELL_NIL) return FALSE;
365
366 /* Read the start value */
367 Value = HvGetCell(Hive, ValueCell);
368 ASSERT(Value);
369 Data = (PLONG)CmpValueToData(Hive, Value, &Length);
370 ASSERT(Data);
371
372 /* Return if the type matches */
373 return (*Data == LoadType);
374 }
375
376 BOOLEAN
377 NTAPI
378 INIT_FUNCTION
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)
384 {
385 HCELL_INDEX ServicesCell, ControlCell, GroupOrderCell, DriverCell;
386 UNICODE_STRING Name;
387 ULONG i;
388 WCHAR Buffer[128];
389 UNICODE_STRING UnicodeString, KeyPath;
390 PBOOT_DRIVER_NODE FsNode;
391 PCM_KEY_NODE ControlNode, ServicesNode, Node;
392 ASSERT(Hive->ReleaseCellRoutine == NULL);
393
394 /* Open the control set key */
395 ControlNode = HvGetCell(Hive, ControlSet);
396 ASSERT(ControlNode);
397
398 /* Get services cell */
399 RtlInitUnicodeString(&Name, L"Services");
400 ServicesCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
401 if (ServicesCell == HCELL_NIL) return FALSE;
402
403 /* Open services key */
404 ServicesNode = HvGetCell(Hive, ServicesCell);
405 ASSERT(ServicesNode);
406
407 /* Get control cell */
408 RtlInitUnicodeString(&Name, L"Control");
409 ControlCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
410 if (ControlCell == HCELL_NIL) return FALSE;
411
412 /* Get the group order cell and read it */
413 RtlInitUnicodeString(&Name, L"GroupOrderList");
414 Node = HvGetCell(Hive, ControlCell);
415 ASSERT(Node);
416 GroupOrderCell = CmpFindSubKeyByName(Hive, Node, &Name);
417 if (GroupOrderCell == HCELL_NIL) return FALSE;
418
419 /* Build the root registry path */
420 RtlInitEmptyUnicodeString(&KeyPath, Buffer, sizeof(Buffer));
421 RtlAppendUnicodeToString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
422
423 /* Find the first subkey (ie: the first driver or service) */
424 i = 0;
425 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, i);
426 while (DriverCell != HCELL_NIL)
427 {
428 /* Make sure it's a driver of this start type */
429 if (CmpIsLoadType(Hive, DriverCell, LoadType))
430 {
431 /* Add it to the list */
432 CmpAddDriverToList(Hive,
433 DriverCell,
434 GroupOrderCell,
435 &KeyPath,
436 DriverListHead);
437
438 }
439
440 /* Try the next subkey */
441 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, ++i);
442 }
443
444 /* Check if we have a boot file system */
445 if (BootFileSystem)
446 {
447 /* Find it */
448 RtlInitUnicodeString(&UnicodeString, BootFileSystem);
449 DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &UnicodeString);
450 if (DriverCell != HCELL_NIL)
451 {
452 /* Always add it to the list */
453 CmpAddDriverToList(Hive,
454 DriverCell,
455 GroupOrderCell,
456 &KeyPath,
457 DriverListHead);
458
459 /* Mark it as critical so it always loads */
460 FsNode = CONTAINING_RECORD(DriverListHead->Flink,
461 BOOT_DRIVER_NODE,
462 ListEntry.Link);
463 FsNode->ErrorControl = SERVICE_ERROR_CRITICAL;
464 }
465 }
466
467 /* We're done! */
468 return TRUE;
469 }
470
471 BOOLEAN
472 NTAPI
473 INIT_FUNCTION
474 CmpDoSort(IN PLIST_ENTRY DriverListHead,
475 IN PUNICODE_STRING OrderList)
476 {
477 PWCHAR Current, End = NULL;
478 PLIST_ENTRY NextEntry;
479 UNICODE_STRING GroupName;
480 PBOOT_DRIVER_NODE CurrentNode;
481
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)
485 {
486 /* Scan the current string */
487 do
488 {
489 if (*Current == UNICODE_NULL) End = Current;
490 } while ((*(--Current - 1) != UNICODE_NULL) && (Current != OrderList->Buffer));
491
492 /* This is our cleaned up string for this specific group */
493 ASSERT(End != NULL);
494 GroupName.Length = (End - Current) * sizeof(WCHAR);
495 GroupName.MaximumLength = GroupName.Length;
496 GroupName.Buffer = Current;
497
498 /* Now loop the driver list */
499 NextEntry = DriverListHead->Flink;
500 while (NextEntry != DriverListHead)
501 {
502 /* Get this node */
503 CurrentNode = CONTAINING_RECORD(NextEntry,
504 BOOT_DRIVER_NODE,
505 ListEntry.Link);
506
507 /* Get the next entry now since we'll do a relink */
508 NextEntry = CurrentNode->ListEntry.Link.Flink;
509
510 /* Is there a group name and does it match the current group? */
511 if ((CurrentNode->Group.Buffer) &&
512 (RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE)))
513 {
514 /* Remove from this location and re-link in the new one */
515 RemoveEntryList(&CurrentNode->ListEntry.Link);
516 InsertHeadList(DriverListHead, &CurrentNode->ListEntry.Link);
517 }
518 }
519
520 /* Move on */
521 Current--;
522 }
523
524 /* All done */
525 return TRUE;
526 }
527
528 BOOLEAN
529 NTAPI
530 INIT_FUNCTION
531 CmpSortDriverList(IN PHHIVE Hive,
532 IN HCELL_INDEX ControlSet,
533 IN PLIST_ENTRY DriverListHead)
534 {
535 HCELL_INDEX Controls, GroupOrder, ListCell;
536 UNICODE_STRING Name, DependList;
537 PCM_KEY_VALUE ListNode;
538 ULONG Length;
539 PCM_KEY_NODE Node;
540 ASSERT(Hive->ReleaseCellRoutine == NULL);
541
542 /* Open the control key */
543 Node = HvGetCell(Hive, ControlSet);
544 ASSERT(Node);
545 RtlInitUnicodeString(&Name, L"Control");
546 Controls = CmpFindSubKeyByName(Hive, Node, &Name);
547 if (Controls == HCELL_NIL) return FALSE;
548
549 /* Open the service group order */
550 Node = HvGetCell(Hive, Controls);
551 ASSERT(Node);
552 RtlInitUnicodeString(&Name, L"ServiceGroupOrder");
553 GroupOrder = CmpFindSubKeyByName(Hive, Node, &Name);
554 if (GroupOrder == HCELL_NIL) return FALSE;
555
556 /* Open the list key */
557 Node = HvGetCell(Hive, GroupOrder);
558 ASSERT(Node);
559 RtlInitUnicodeString(&Name, L"list");
560 ListCell = CmpFindValueByName(Hive, Node, &Name);
561 if (ListCell == HCELL_NIL) return FALSE;
562
563 /* Now read the actual list */
564 ListNode = HvGetCell(Hive, ListCell);
565 ASSERT(ListNode);
566 if (ListNode->Type != REG_MULTI_SZ) return FALSE;
567
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);
572
573 /* And start the recurive sort algorithm */
574 return CmpDoSort(DriverListHead, &DependList);
575 }
576
577 BOOLEAN
578 NTAPI
579 INIT_FUNCTION
580 CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode,
581 IN PBOOT_DRIVER_NODE EndNode)
582 {
583 PBOOT_DRIVER_NODE CurrentNode, PreviousNode;
584 PLIST_ENTRY ListEntry;
585
586 /* Base case, nothing to do */
587 if (StartNode == EndNode) return TRUE;
588
589 /* Loop the nodes */
590 CurrentNode = StartNode;
591 do
592 {
593 /* Save this as the previous node */
594 PreviousNode = CurrentNode;
595
596 /* And move to the next one */
597 ListEntry = CurrentNode->ListEntry.Link.Flink;
598 CurrentNode = CONTAINING_RECORD(ListEntry,
599 BOOT_DRIVER_NODE,
600 ListEntry.Link);
601
602 /* Check if the previous driver had a bigger tag */
603 if (PreviousNode->Tag > CurrentNode->Tag)
604 {
605 /* Check if we need to update the tail */
606 if (CurrentNode == EndNode)
607 {
608 /* Update the tail */
609 ListEntry = CurrentNode->ListEntry.Link.Blink;
610 EndNode = CONTAINING_RECORD(ListEntry,
611 BOOT_DRIVER_NODE,
612 ListEntry.Link);
613 }
614
615 /* Remove this driver since we need to move it */
616 RemoveEntryList(&CurrentNode->ListEntry.Link);
617
618 /* Keep looping until we find a driver with a lower tag than ours */
619 while ((PreviousNode->Tag > CurrentNode->Tag) && (PreviousNode != StartNode))
620 {
621 /* We'll be re-inserted at this spot */
622 ListEntry = PreviousNode->ListEntry.Link.Blink;
623 PreviousNode = CONTAINING_RECORD(ListEntry,
624 BOOT_DRIVER_NODE,
625 ListEntry.Link);
626 }
627
628 /* Do the insert in the new location */
629 InsertTailList(&PreviousNode->ListEntry.Link, &CurrentNode->ListEntry.Link);
630
631 /* Update the head, if needed */
632 if (PreviousNode == StartNode) StartNode = CurrentNode;
633 }
634 } while (CurrentNode != EndNode);
635
636 /* All done */
637 return TRUE;
638 }
639
640 BOOLEAN
641 NTAPI
642 INIT_FUNCTION
643 CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead)
644 {
645 PLIST_ENTRY NextEntry;
646 PBOOT_DRIVER_NODE StartNode, EndNode, CurrentNode;
647
648 /* Loop the list */
649 NextEntry = DriverListHead->Flink;
650 while (NextEntry != DriverListHead)
651 {
652 /* Find the first entry */
653 StartNode = CONTAINING_RECORD(NextEntry,
654 BOOT_DRIVER_NODE,
655 ListEntry.Link);
656 do
657 {
658 /* Find the last entry */
659 EndNode = CONTAINING_RECORD(NextEntry,
660 BOOT_DRIVER_NODE,
661 ListEntry.Link);
662
663 /* Get the next entry */
664 NextEntry = NextEntry->Flink;
665 CurrentNode = CONTAINING_RECORD(NextEntry,
666 BOOT_DRIVER_NODE,
667 ListEntry.Link);
668
669 /* If the next entry is back to the top, break out */
670 if (NextEntry == DriverListHead) break;
671
672 /* Otherwise, check if this entry is equal */
673 if (!RtlEqualUnicodeString(&StartNode->Group,
674 &CurrentNode->Group,
675 TRUE))
676 {
677 /* It is, so we've detected a cycle, break out */
678 break;
679 }
680 } while (NextEntry != DriverListHead);
681
682 /* Now we have the correct start and end pointers, so do the sort */
683 CmpOrderGroup(StartNode, EndNode);
684 }
685
686 /* We're done */
687 return TRUE;
688 }
689
690 /* EOF */