ReactOS  0.4.14-dev-57-g333b8f1
cmboot.c
Go to the documentation of this file.
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 INIT_FUNCTION
24 NTAPI
26  IN HCELL_INDEX RootCell,
27  IN PUNICODE_STRING SelectKeyName,
28  OUT PBOOLEAN AutoSelect)
29 {
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];
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;
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 INIT_FUNCTION
133 ULONG
134 NTAPI
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;
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 INIT_FUNCTION
183 BOOLEAN
184 NTAPI
186  IN HCELL_INDEX DriverCell,
187  IN HCELL_INDEX GroupOrderCell,
189  IN PLIST_ENTRY BootDriverListHead)
190 {
191  PBOOT_DRIVER_NODE DriverNode;
194  ULONG Length;
195  USHORT NameLength;
196  HCELL_INDEX ValueCell, TagCell; PCM_KEY_VALUE Value;
197  PUNICODE_STRING FileName, RegistryString;
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\\");
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;
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 */
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 */
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 */
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 INIT_FUNCTION
350 BOOLEAN
351 NTAPI
354  IN SERVICE_LOAD_TYPE LoadType)
355 {
357  HCELL_INDEX ValueCell;
358  UNICODE_STRING ValueString = RTL_CONSTANT_STRING(L"Start");
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 INIT_FUNCTION
381 BOOLEAN
382 NTAPI
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;
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,
493  ListEntry.Link);
495  }
496  }
497 
498  /* We're done! */
499  return TRUE;
500 }
501 
502 INIT_FUNCTION
503 BOOLEAN
504 NTAPI
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,
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 INIT_FUNCTION
560 BOOLEAN
561 NTAPI
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;
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 INIT_FUNCTION
609 BOOLEAN
610 NTAPI
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,
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,
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,
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 INIT_FUNCTION
672 BOOLEAN
673 NTAPI
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,
686  ListEntry.Link);
687  do
688  {
689  /* Find the last entry */
690  EndNode = CONTAINING_RECORD(NextEntry,
692  ListEntry.Link);
693 
694  /* Get the next entry */
695  NextEntry = NextEntry->Flink;
696  CurrentNode = CONTAINING_RECORD(NextEntry,
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 INIT_FUNCTION
722 BOOLEAN
723 NTAPI
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;
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 */
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);
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 */
INIT_FUNCTION BOOLEAN NTAPI CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode, IN PBOOT_DRIVER_NODE EndNode)
Definition: cmboot.c:611
_In_opt_ ULONG _Out_ PULONG Value
Definition: rtlfuncs.h:2343
#define KEY_COMP_NAME
Definition: cmdata.h:35
INIT_FUNCTION BOOLEAN NTAPI CmpSortDriverList(IN PHHIVE Hive, IN HCELL_INDEX ControlSet, IN PLIST_ENTRY DriverListHead)
Definition: cmboot.c:562
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4711
#define IN
Definition: typedefs.h:38
WCHAR Name[ANYSIZE_ARRAY]
Definition: cmdata.h:116
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
BOOT_DRIVER_LIST_ENTRY ListEntry
Definition: io.h:426
*BytesInUnicodeString PWCH UnicodeString
Definition: rtlfuncs.h:1980
USHORT MaximumLength
Definition: env_spec_w32.h:370
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
struct _LIST_ENTRY * Blink
Definition: typedefs.h:120
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
unsigned char * PUCHAR
Definition: retypes.h:3
ULONG ErrorControl
Definition: io.h:430
char CHAR
Definition: xmlstorage.h:175
BOOLEAN NTAPI CmpGetValueData(IN PHHIVE Hive, IN PCM_KEY_VALUE Value, OUT PULONG Length, OUT PVOID *Buffer, OUT PBOOLEAN BufferAllocated, OUT PHCELL_INDEX CellToRelease)
Definition: cmvalue.c:125
enum _CM_SERVICE_LOAD_TYPE SERVICE_LOAD_TYPE
PVOID NTAPI CmpAllocate(_In_ SIZE_T Size, _In_ BOOLEAN Paged, _In_ ULONG Tag)
Definition: bootreg.c:90
LONG NTSTATUS
Definition: precomp.h:26
HCELL_INDEX NTAPI CmpFindSubKeyByNumber(IN PHHIVE Hive, IN PCM_KEY_NODE Node, IN ULONG Number)
Definition: cmindex.c:600
#define HCELL_NIL
Definition: hivedata.h:85
INIT_FUNCTION BOOLEAN NTAPI CmpFindDrivers(IN PHHIVE Hive, IN HCELL_INDEX ControlSet, IN SERVICE_LOAD_TYPE LoadType, IN PWCHAR BootFileSystem OPTIONAL, IN PLIST_ENTRY DriverListHead)
Definition: cmboot.c:383
uint16_t * PWCHAR
Definition: typedefs.h:54
INIT_FUNCTION BOOLEAN NTAPI CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead)
Definition: cmboot.c:674
#define InsertTailList(ListHead, Entry)
USHORT NameLength
Definition: cmdata.h:114
Definition: arc.h:198
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
#define sprintf(buf, format,...)
Definition: sprintf.c:55
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define UNICODE_NULL
union node Node
Definition: types.h:1255
VOID NTAPI CmpCopyCompressedName(OUT PWCHAR Destination, IN ULONG DestinationLength, IN PWCHAR Source, IN ULONG SourceLength)
Definition: cmname.c:56
#define REG_MULTI_SZ
Definition: nt_native.h:1501
PVOID CMAPI HvGetCell(PHHIVE RegistryHive, HCELL_INDEX CellOffset)
Definition: hivecell.c:67
struct NameRec_ * Name
Definition: cdprocs.h:464
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
struct _CM_KEY_NODE * PCM_KEY_NODE
_In_ LPGUID _In_ PVOID Data
Definition: classpnp.h:778
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcsrchr(_In_z_ const wchar_t *_Str, _In_ wchar_t _Ch)
Definition: bufpool.h:45
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
NTSTATUS RtlAppendUnicodeToString(IN PUNICODE_STRING Str1, IN PWSTR Str2)
Definition: string_lib.cpp:62
USHORT MaximumLength
Definition: env_spec_w32.h:377
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
PCELL_DATA NTAPI CmpValueToData(IN PHHIVE Hive, IN PCM_KEY_VALUE Value, OUT PULONG Length)
Definition: cmvalue.c:167
UNICODE_STRING Name
Definition: io.h:428
HCELL_INDEX NTAPI CmpFindValueByName(IN PHHIVE Hive, IN PCM_KEY_NODE KeyNode, IN PUNICODE_STRING Name)
Definition: cmvalue.c:99
ULONG Tag
Definition: io.h:429
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
ULONG HCELL_INDEX
Definition: hivedata.h:80
Definition: bzip2.c:1694
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
INIT_FUNCTION HCELL_INDEX NTAPI CmpFindControlSet(IN PHHIVE SystemHive, IN HCELL_INDEX RootCell, IN PUNICODE_STRING SelectKeyName, OUT PBOOLEAN AutoSelect)
Definition: cmboot.c:25
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define TAG_CM
Definition: cmlib.h:203
char * PBOOLEAN
Definition: retypes.h:11
static const WCHAR L[]
Definition: oid.c:1250
Definition: typedefs.h:117
UNICODE_STRING Group
Definition: io.h:427
Status
Definition: gdiplustypes.h:24
struct _FileName FileName
Definition: fatprocs.h:884
DRIVER_INITIALIZE DriverEntry
Definition: condrv.c:21
INIT_FUNCTION BOOLEAN NTAPI CmpIsSafe(IN PHHIVE Hive, IN HCELL_INDEX SafeBootCell, IN HCELL_INDEX DriverCell)
Definition: cmboot.c:724
unsigned short USHORT
Definition: pedump.c:61
struct _CM_KEY_VALUE * PCM_KEY_VALUE
NTSYSAPI NTSTATUS NTAPI RtlAnsiStringToUnicodeString(PUNICODE_STRING DestinationString, PANSI_STRING SourceString, BOOLEAN AllocateDestinationString)
ULONG Type
Definition: cmdata.h:128
#define REG_EXPAND_SZ
Definition: nt_native.h:1494
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
unsigned int * PULONG
Definition: retypes.h:1
INIT_FUNCTION BOOLEAN NTAPI CmpDoSort(IN PLIST_ENTRY DriverListHead, IN PUNICODE_STRING OrderList)
Definition: cmboot.c:505
static CMHIVE SystemHive
Definition: registry.c:57
INIT_FUNCTION ULONG NTAPI CmpFindTagIndex(IN PHHIVE Hive, IN HCELL_INDEX TagCell, IN HCELL_INDEX GroupOrderCell, IN PUNICODE_STRING GroupName)
Definition: cmboot.c:135
ULONG InitSafeBootMode
Definition: init.c:68
INIT_FUNCTION BOOLEAN NTAPI CmpIsLoadType(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN SERVICE_LOAD_TYPE LoadType)
Definition: cmboot.c:352
LIST_ENTRY Link
Definition: arc.h:200
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
INIT_FUNCTION BOOLEAN NTAPI CmpAddDriverToList(IN PHHIVE Hive, IN HCELL_INDEX DriverCell, IN HCELL_INDEX GroupOrderCell, IN PUNICODE_STRING RegistryPath, IN PLIST_ENTRY BootDriverListHead)
Definition: cmboot.c:185
_In_ PUNICODE_STRING RegistryPath
Definition: wmip.h:27
#define SERVICE_ERROR_CRITICAL
Definition: cmtypes.h:982
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
#define REG_DWORD
Definition: sdbapi.c:596
signed int * PLONG
Definition: retypes.h:5
HCELL_INDEX NTAPI CmpFindSubKeyByName(IN PHHIVE Hive, IN PCM_KEY_NODE Parent, IN PCUNICODE_STRING SearchName)
Definition: cmindex.c:683
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
USHORT NTAPI CmpCompressedNameSize(IN PWCHAR Name, IN ULONG Length)
Definition: cmname.c:95
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
USHORT Flags
Definition: cmdata.h:93
Definition: dlist.c:348
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
#define REG_SZ
Definition: layer.c:22
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68