ReactOS 0.4.17-dev-1281-g065abb3
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 * PURPOSE: Configuration Manager - Boot Initialization
5 * COPYRIGHT: Copyright 2007 Alex Ionescu (alex.ionescu@reactos.org)
6 * Copyright 2010 ReactOS Portable Systems Group
7 * Copyright 2022 Hermès Bélusca-Maïto
8 *
9 * NOTE: This module is shared by both the kernel and the bootloader.
10 */
11
12/* INCLUDES *******************************************************************/
13
14#include <ntoskrnl.h>
15
16#define NDEBUG
17#include <debug.h>
18
19#ifdef _BLDR_
20
21#undef CODE_SEG
22#define CODE_SEG(...)
23
24#include <ntstrsafe.h>
25#include <cmlib.h>
26#include "internal/cmboot.h"
27
28// HACK: This is part of non-NT-compatible SafeBoot support in kernel.
30
31DBG_DEFAULT_CHANNEL(REGISTRY);
32#define CMTRACE(x, fmt, ...) TRACE(fmt, ##__VA_ARGS__) // DPRINT
33
34#endif /* _BLDR_ */
35
36
37/* DEFINES ********************************************************************/
38
39#define CM_BOOT_DEBUG 0x20
40
41#define IS_NULL_TERMINATED(Buffer, Size) \
42 (((Size) >= sizeof(WCHAR)) && ((Buffer)[(Size) / sizeof(WCHAR) - 1] == UNICODE_NULL))
43
44
45/* FUNCTIONS ******************************************************************/
46
47// HACK: This is part of non-NT-compatible SafeBoot support in kernel.
48CODE_SEG("INIT")
49static
52 _In_ PHHIVE Hive,
53 _In_ HCELL_INDEX SafeBootCell,
54 _In_ HCELL_INDEX DriverCell);
55
84 _In_ HCELL_INDEX RootCell,
85 _In_ PCUNICODE_STRING SelectKeyName,
86 _Out_ PBOOLEAN AutoSelect)
87{
90 HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell;
91 HCELL_INDEX CurrentValueCell;
95 PULONG CurrentData;
96 PULONG ControlSetId;
97 WCHAR Buffer[128];
98
99 /* Sanity check: We shouldn't need to release any acquired cells */
101
102 /* Get the Select key */
103 RtlInitUnicodeString(&Name, L"select");
105 if (!Node) return HCELL_NIL;
106 SelectCell = CmpFindSubKeyByName(SystemHive, Node, &Name);
107 if (SelectCell == HCELL_NIL) return HCELL_NIL;
108
109 /* Get AutoSelect value */
110 RtlInitUnicodeString(&Name, L"AutoSelect");
111 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
112 if (!Node) return HCELL_NIL;
113 AutoSelectCell = CmpFindValueByName(SystemHive, Node, &Name);
114 if (AutoSelectCell == HCELL_NIL)
115 {
116 /* Assume TRUE if the value is missing */
117 *AutoSelect = TRUE;
118 }
119 else
120 {
121 /* Read the value */
122 Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell);
123 if (!Value) return HCELL_NIL;
124 // if (Value->Type != REG_DWORD) return HCELL_NIL;
125
126 /* Convert it to a boolean */
127 CurrentData = (PULONG)CmpValueToData(SystemHive, Value, &Length);
128 if (!CurrentData) return HCELL_NIL;
129 // if (Length < sizeof(ULONG)) return HCELL_NIL;
130
131 *AutoSelect = *(PBOOLEAN)CurrentData;
132 }
133
134 /* Now find the control set being looked up */
135 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
136 if (!Node) return HCELL_NIL;
137 SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName);
138 if (SelectValueCell == HCELL_NIL) return HCELL_NIL;
139
140 /* Read the value (corresponding to the CCS ID) */
141 Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell);
142 if (!Value) return HCELL_NIL;
143 if (Value->Type != REG_DWORD) return HCELL_NIL;
144 ControlSetId = (PULONG)CmpValueToData(SystemHive, Value, &Length);
145 if (!ControlSetId) return HCELL_NIL;
146 if (Length < sizeof(ULONG)) return HCELL_NIL;
147
148 /* Now build the CCS's Name */
150 L"ControlSet%03lu", *ControlSetId);
151 if (!NT_SUCCESS(Status)) return HCELL_NIL;
152 /* RtlStringCbPrintfW ensures the buffer to be NULL-terminated */
154
155 /* Now open it */
157 if (!Node) return HCELL_NIL;
158 ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &Name);
159 if (ControlSetCell == HCELL_NIL) return HCELL_NIL;
160
161 /* Get the value of the "Current" CCS */
162 RtlInitUnicodeString(&Name, L"Current");
163 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
164 if (!Node) return HCELL_NIL;
165 CurrentValueCell = CmpFindValueByName(SystemHive, Node, &Name);
166
167 /* Make sure it exists */
168 if (CurrentValueCell != HCELL_NIL)
169 {
170 /* Get the current value and make sure it's a ULONG */
171 Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell);
172 if (!Value) return HCELL_NIL;
173 if (Value->Type == REG_DWORD)
174 {
175 /* Get the data and update it */
176 CurrentData = (PULONG)CmpValueToData(SystemHive, Value, &Length);
177 if (!CurrentData) return HCELL_NIL;
178 if (Length < sizeof(ULONG)) return HCELL_NIL;
179
180 *CurrentData = *ControlSetId;
181 }
182 }
183
184 /* Return the CCS cell */
185 return ControlSetCell;
186}
187
210CODE_SEG("INIT")
211static
212ULONG
214 _In_ PHHIVE Hive,
215 _In_ HCELL_INDEX TagCell,
216 _In_ HCELL_INDEX GroupOrderCell,
217 _In_ PCUNICODE_STRING GroupName)
218{
219 PCM_KEY_VALUE TagValue, Value;
221 HCELL_INDEX OrderCell;
222 PULONG DriverTag, TagOrder;
223 ULONG CurrentTag, Length;
224 BOOLEAN BufferAllocated;
225
226 /* Sanity check: We shouldn't need to release any acquired cells */
227 ASSERT(Hive->ReleaseCellRoutine == NULL);
228
229 /* Get the tag */
230 Value = (PCM_KEY_VALUE)HvGetCell(Hive, TagCell);
231 if (!Value) return -2;
232 if (Value->Type != REG_DWORD) return -2;
233 DriverTag = (PULONG)CmpValueToData(Hive, Value, &Length);
234 if (!DriverTag) return -2;
235 if (Length < sizeof(ULONG)) return -2;
236
237 /* Get the order array */
238 Node = (PCM_KEY_NODE)HvGetCell(Hive, GroupOrderCell);
239 if (!Node) return -2;
240 OrderCell = CmpFindValueByName(Hive, Node, GroupName);
241 if (OrderCell == HCELL_NIL) return -2;
242
243 /* And read it */
244 TagValue = (PCM_KEY_VALUE)HvGetCell(Hive, OrderCell);
245 if (!TagValue) return -2;
246 if (!CmpGetValueData(Hive,
247 TagValue,
248 &Length,
249 (PVOID*)&TagOrder,
250 &BufferAllocated,
251 &OrderCell)
252 || !TagOrder)
253 {
254 return -2;
255 }
256
257 /* Parse each tag */
258 for (CurrentTag = 1; CurrentTag <= TagOrder[0]; CurrentTag++)
259 {
260 /* Find a match */
261 if (TagOrder[CurrentTag] == *DriverTag)
262 {
263 /* Found it -- return the tag */
264 if (BufferAllocated) Hive->Free(TagOrder, Length);
265 return CurrentTag;
266 }
267 }
268
269 /* No matches, so assume next to last ordering */
270 if (BufferAllocated) Hive->Free(TagOrder, Length);
271 return -2;
272}
273
274#ifdef _BLDR_
275
296CODE_SEG("INIT")
298NTAPI
299CmpIsDriverInList(
300 _In_ PLIST_ENTRY DriverListHead,
301 _In_ PCUNICODE_STRING DriverName,
302 _Out_opt_ PBOOT_DRIVER_NODE* FoundDriver)
303{
305 PBOOT_DRIVER_NODE DriverNode;
306
307 for (Entry = DriverListHead->Flink;
308 Entry != DriverListHead;
309 Entry = Entry->Flink)
310 {
311 DriverNode = CONTAINING_RECORD(Entry,
313 ListEntry.Link);
314
315 if (RtlEqualUnicodeString(&DriverNode->Name,
316 DriverName,
317 TRUE))
318 {
319 /* The driver node has been found */
320 if (FoundDriver)
321 *FoundDriver = DriverNode;
322 return TRUE;
323 }
324 }
325
326 /* None has been found */
327 if (FoundDriver)
328 *FoundDriver = NULL;
329 return FALSE;
330}
331
332#endif /* _BLDR_ */
333
359CODE_SEG("INIT")
361NTAPI
363 _In_ PHHIVE Hive,
364 _In_ HCELL_INDEX DriverCell,
365 _In_ HCELL_INDEX GroupOrderCell,
367 _Inout_ PLIST_ENTRY DriverListHead)
368{
369 PBOOT_DRIVER_NODE DriverNode;
375 HCELL_INDEX ValueCell, TagCell;
376 PUNICODE_STRING FilePath, RegistryString;
378 PULONG ErrorControl;
380
381 /* Sanity check: We shouldn't need to release any acquired cells */
382 ASSERT(Hive->ReleaseCellRoutine == NULL);
383
384 /* Allocate a driver node and initialize it */
385 DriverNode = Hive->Allocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM);
386 if (!DriverNode)
387 return FALSE;
388
389 RtlZeroMemory(DriverNode, sizeof(BOOT_DRIVER_NODE));
390 DriverEntry = &DriverNode->ListEntry;
391
392 /* Get the driver cell */
393 Node = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell);
394 if (!Node)
395 goto Failure;
396
397 /* Get the name from the cell */
398 NameLength = (Node->Flags & KEY_COMP_NAME) ?
399 CmpCompressedNameSize(Node->Name, Node->NameLength) :
400 Node->NameLength;
401 if (NameLength < sizeof(WCHAR))
402 goto Failure;
403
404 /* Now allocate the buffer for it and copy the name */
405 RtlInitEmptyUnicodeString(&DriverNode->Name,
406 Hive->Allocate(NameLength, FALSE, TAG_CM),
407 NameLength);
408 if (!DriverNode->Name.Buffer)
409 goto Failure;
410
411 DriverNode->Name.Length = NameLength;
412 if (Node->Flags & KEY_COMP_NAME)
413 {
414 /* Compressed name */
416 DriverNode->Name.Length,
417 Node->Name,
418 Node->NameLength);
419 }
420 else
421 {
422 /* Normal name */
423 RtlCopyMemory(DriverNode->Name.Buffer, Node->Name, Node->NameLength);
424 }
425
426 /* Now find the image path */
427 RtlInitUnicodeString(&Name, L"ImagePath");
428 ValueCell = CmpFindValueByName(Hive, Node, &Name);
429 if (ValueCell == HCELL_NIL)
430 {
431 /* Could not find it, so assume the drivers path */
432 Length = sizeof(L"System32\\Drivers\\") + NameLength + sizeof(L".sys");
433
434 /* Allocate the path name */
435 FilePath = &DriverEntry->FilePath;
437 Hive->Allocate(Length, FALSE, TAG_CM),
438 (USHORT)Length);
439 if (!FilePath->Buffer)
440 goto Failure;
441
442 /* Write the path name */
443 if (!NT_SUCCESS(RtlAppendUnicodeToString(FilePath, L"System32\\Drivers\\")) ||
446 {
447 goto Failure;
448 }
449 }
450 else
451 {
452 /* Path name exists, so grab it */
453 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
454 if (!Value)
455 goto Failure;
456 if ((Value->Type != REG_SZ) && (Value->Type != REG_EXPAND_SZ))
457 goto Failure;
459 if (!Buffer)
460 goto Failure;
462 Length -= sizeof(UNICODE_NULL);
463 if (Length < sizeof(WCHAR))
464 goto Failure;
465
466 /* Allocate and setup the path name */
467 FilePath = &DriverEntry->FilePath;
469 Hive->Allocate(Length, FALSE, TAG_CM),
470 (USHORT)Length);
471 if (!FilePath->Buffer)
472 goto Failure;
473
474 /* Transfer the data */
476 FilePath->Length = (USHORT)Length;
477 }
478
479 /* Now build the registry path */
480 RegistryString = &DriverEntry->RegistryPath;
481 Length = RegistryPath->Length + NameLength;
482 RtlInitEmptyUnicodeString(RegistryString,
483 Hive->Allocate(Length, FALSE, TAG_CM),
484 (USHORT)Length);
485 if (!RegistryString->Buffer)
486 goto Failure;
487
488 /* Add the driver name to it */
490 !NT_SUCCESS(RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name)))
491 {
492 goto Failure;
493 }
494
495 /* The entry is done, add it */
496 InsertHeadList(DriverListHead, &DriverEntry->Link);
497
498 /* Now find error control settings */
499 RtlInitUnicodeString(&Name, L"ErrorControl");
500 ValueCell = CmpFindValueByName(Hive, Node, &Name);
501 if (ValueCell == HCELL_NIL)
502 {
503 /* Could not find it, so assume default */
504 DriverNode->ErrorControl = NormalError;
505 }
506 else
507 {
508 /* Otherwise, read whatever the data says */
509 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
510 if (!Value)
511 goto Failure;
512 if (Value->Type != REG_DWORD)
513 goto Failure;
514 ErrorControl = (PULONG)CmpValueToData(Hive, Value, &Length);
515 if (!ErrorControl)
516 goto Failure;
517 if (Length < sizeof(ULONG))
518 goto Failure;
519
520 DriverNode->ErrorControl = *ErrorControl;
521 }
522
523 /* Next, get the group cell */
524 RtlInitUnicodeString(&Name, L"group");
525 ValueCell = CmpFindValueByName(Hive, Node, &Name);
526 if (ValueCell == HCELL_NIL)
527 {
528 /* Could not find it, so set an empty string */
529 RtlInitEmptyUnicodeString(&DriverNode->Group, NULL, 0);
530 }
531 else
532 {
533 /* Found it, read the group value */
534 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
535 if (!Value)
536 goto Failure;
537 if (Value->Type != REG_SZ) // REG_EXPAND_SZ not really allowed there.
538 goto Failure;
539
540 /* Copy it into the node */
542 if (!Buffer)
543 goto Failure;
545 Length -= sizeof(UNICODE_NULL);
546
547 DriverNode->Group.Buffer = Buffer;
548 DriverNode->Group.Length = (USHORT)Length;
549 DriverNode->Group.MaximumLength = DriverNode->Group.Length;
550 }
551
552 /* Finally, find the tag */
554 TagCell = CmpFindValueByName(Hive, Node, &Name);
555 if (TagCell == HCELL_NIL)
556 {
557 /* No tag, so load last */
558 DriverNode->Tag = -1;
559 }
560 else
561 {
562 /* Otherwise, decode it based on tag order */
563 DriverNode->Tag = CmpFindTagIndex(Hive,
564 TagCell,
565 GroupOrderCell,
566 &DriverNode->Group);
567 }
568
569 CMTRACE(CM_BOOT_DEBUG, "Adding boot driver: '%wZ', '%wZ'\n",
570 &DriverNode->Name, &DriverEntry->FilePath);
571
572 /* All done! */
573 return TRUE;
574
575Failure:
576 if (DriverEntry->RegistryPath.Buffer)
577 {
578 Hive->Free(DriverEntry->RegistryPath.Buffer,
579 DriverEntry->RegistryPath.MaximumLength);
580 }
581 if (DriverEntry->FilePath.Buffer)
582 {
583 Hive->Free(DriverEntry->FilePath.Buffer,
584 DriverEntry->FilePath.MaximumLength);
585 }
586 if (DriverNode->Name.Buffer)
587 {
588 Hive->Free(DriverNode->Name.Buffer,
589 DriverNode->Name.MaximumLength);
590 }
591 Hive->Free(DriverNode, sizeof(BOOT_DRIVER_NODE));
592
593 return FALSE;
594}
595
613CODE_SEG("INIT")
614static
617 _In_ PHHIVE Hive,
618 _In_ HCELL_INDEX Cell,
619 _In_ SERVICE_LOAD_TYPE LoadType)
620{
624 HCELL_INDEX ValueCell;
626 PULONG Data;
627
628 /* Sanity check: We shouldn't need to release any acquired cells */
629 ASSERT(Hive->ReleaseCellRoutine == NULL);
630
631 /* Open the start cell */
632 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
633 if (!Node) return FALSE;
634 ValueCell = CmpFindValueByName(Hive, Node, &Name);
635 if (ValueCell == HCELL_NIL) return FALSE;
636
637 /* Read the start value */
638 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
639 if (!Value) return FALSE;
640 if (Value->Type != REG_DWORD) return FALSE;
642 if (!Data) return FALSE;
643 if (Length < sizeof(ULONG)) return FALSE;
644
645 /* Return if the type matches */
646 return (*Data == LoadType);
647}
648
674CODE_SEG("INIT")
676NTAPI
678 _In_ PHHIVE Hive,
679 _In_ HCELL_INDEX ControlSet,
680 _In_ SERVICE_LOAD_TYPE LoadType,
682 _Inout_ PLIST_ENTRY DriverListHead)
683{
684 HCELL_INDEX ServicesCell, ControlCell, GroupOrderCell, DriverCell;
685 HCELL_INDEX SafeBootCell = HCELL_NIL;
686 ULONG i;
689 PCM_KEY_NODE ControlNode, ServicesNode, Node;
690 PBOOT_DRIVER_NODE FsNode;
691
692 /* Sanity check: We shouldn't need to release any acquired cells */
693 ASSERT(Hive->ReleaseCellRoutine == NULL);
694
695 /* Open the control set key */
696 ControlNode = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet);
697 if (!ControlNode) return FALSE;
698
699 /* Get services cell */
700 RtlInitUnicodeString(&Name, L"Services");
701 ServicesCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
702 if (ServicesCell == HCELL_NIL) return FALSE;
703
704 /* Open services key */
705 ServicesNode = (PCM_KEY_NODE)HvGetCell(Hive, ServicesCell);
706 if (!ServicesNode) return FALSE;
707
708 /* Get control cell */
709 RtlInitUnicodeString(&Name, L"Control");
710 ControlCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
711 if (ControlCell == HCELL_NIL) return FALSE;
712
713 /* Get the group order cell and read it */
714 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
715 if (!Node) return FALSE;
716 RtlInitUnicodeString(&Name, L"GroupOrderList");
717 GroupOrderCell = CmpFindSubKeyByName(Hive, Node, &Name);
718 if (GroupOrderCell == HCELL_NIL) return FALSE;
719
720 /* Get Safe Boot cell */
722 {
723 /* Open the Safe Boot key */
724 RtlInitUnicodeString(&Name, L"SafeBoot");
725 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
726 if (!Node) return FALSE;
727 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
728 if (SafeBootCell == HCELL_NIL) return FALSE;
729
730 /* Open the correct start key (depending on the mode) */
731 Node = (PCM_KEY_NODE)HvGetCell(Hive, SafeBootCell);
732 if (!Node) return FALSE;
733 switch (InitSafeBootMode)
734 {
735 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
736 case 1:
737 case 3: RtlInitUnicodeString(&Name, L"Minimal"); break;
738 case 2: RtlInitUnicodeString(&Name, L"Network"); break;
739 default: return FALSE;
740 }
741 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
742 if (SafeBootCell == HCELL_NIL) return FALSE;
743 }
744
745 /* Build the root registry path */
746 RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
747
748 /* Enumerate each sub-key */
749 i = 0;
750 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, i);
751 while (DriverCell != HCELL_NIL)
752 {
753 /* Make sure it's a driver of this start type AND is "safe" to load */
754 if (CmpIsLoadType(Hive, DriverCell, LoadType) &&
755 CmpIsSafe(Hive, SafeBootCell, DriverCell))
756 {
757 /* Add it to the list */
758 if (!CmpAddDriverToList(Hive,
759 DriverCell,
760 GroupOrderCell,
761 &KeyPath,
762 DriverListHead))
763 {
764 CMTRACE(CM_BOOT_DEBUG, " Failed to add boot driver\n");
765 }
766 }
767
768 /* Go to the next sub-key */
769 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, ++i);
770 }
771
772 /* Check if we have a boot file system */
773 if (BootFileSystem)
774 {
775 /* Find it */
777 DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &Name);
778 if (DriverCell != HCELL_NIL)
779 {
780 CMTRACE(CM_BOOT_DEBUG, "Adding Boot FileSystem '%S'\n",
782
783 /* Always add it to the list */
784 if (!CmpAddDriverToList(Hive,
785 DriverCell,
786 GroupOrderCell,
787 &KeyPath,
788 DriverListHead))
789 {
790 CMTRACE(CM_BOOT_DEBUG, " Failed to add boot driver\n");
791 }
792 else
793 {
794 /* Mark it as critical so it always loads */
795 FsNode = CONTAINING_RECORD(DriverListHead->Flink,
797 ListEntry.Link);
799 }
800 }
801 }
802
803 /* We're done! */
804 return TRUE;
805}
806
823CODE_SEG("INIT")
824static
827 _Inout_ PLIST_ENTRY DriverListHead,
828 _In_ PCUNICODE_STRING OrderList)
829{
831 UNICODE_STRING GroupName;
832 PLIST_ENTRY NextEntry;
833 PBOOT_DRIVER_NODE CurrentNode;
834
835 /* We're going from end to start, so get to the last group and keep going */
836 Current = &OrderList->Buffer[OrderList->Length / sizeof(WCHAR)];
837 while (Current > OrderList->Buffer)
838 {
839 /* Scan the current string */
840 do
841 {
842 if (*Current == UNICODE_NULL) End = Current;
843 } while ((*(--Current - 1) != UNICODE_NULL) && (Current != OrderList->Buffer));
844
845 /* This is our cleaned up string for this specific group */
846 ASSERT(End != NULL);
847 GroupName.Length = (USHORT)(End - Current) * sizeof(WCHAR);
848 GroupName.MaximumLength = GroupName.Length;
849 GroupName.Buffer = Current;
850
851 /* Now loop the driver list */
852 NextEntry = DriverListHead->Flink;
853 while (NextEntry != DriverListHead)
854 {
855 /* Get this node */
856 CurrentNode = CONTAINING_RECORD(NextEntry,
858 ListEntry.Link);
859
860 /* Get the next entry now since we'll do a relink */
861 NextEntry = NextEntry->Flink;
862
863 /* Is there a group name and does it match the current group? */
864 if (CurrentNode->Group.Buffer &&
865 RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE))
866 {
867 /* Remove from this location and re-link in the new one */
868 RemoveEntryList(&CurrentNode->ListEntry.Link);
869 InsertHeadList(DriverListHead, &CurrentNode->ListEntry.Link);
870 }
871 }
872
873 /* Move on */
874 --Current;
875 }
876
877 /* All done */
878 return TRUE;
879}
880
897CODE_SEG("INIT")
899NTAPI
901 _In_ PHHIVE Hive,
902 _In_ HCELL_INDEX ControlSet,
903 _Inout_ PLIST_ENTRY DriverListHead)
904{
906 PCM_KEY_VALUE ListValue;
907 HCELL_INDEX ControlCell, GroupOrder, ListCell;
908 UNICODE_STRING Name, OrderList;
910
911 /* Sanity check: We shouldn't need to release any acquired cells */
912 ASSERT(Hive->ReleaseCellRoutine == NULL);
913
914 /* Open the control key */
915 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet);
916 if (!Node) return FALSE;
917 RtlInitUnicodeString(&Name, L"Control");
918 ControlCell = CmpFindSubKeyByName(Hive, Node, &Name);
919 if (ControlCell == HCELL_NIL) return FALSE;
920
921 /* Open the service group order */
922 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
923 if (!Node) return FALSE;
924 RtlInitUnicodeString(&Name, L"ServiceGroupOrder");
925 GroupOrder = CmpFindSubKeyByName(Hive, Node, &Name);
926 if (GroupOrder == HCELL_NIL) return FALSE;
927
928 /* Open the list key */
929 Node = (PCM_KEY_NODE)HvGetCell(Hive, GroupOrder);
930 if (!Node) return FALSE;
931 RtlInitUnicodeString(&Name, L"list");
932 ListCell = CmpFindValueByName(Hive, Node, &Name);
933 if (ListCell == HCELL_NIL) return FALSE;
934
935 /* Read the actual list */
936 ListValue = (PCM_KEY_VALUE)HvGetCell(Hive, ListCell);
937 if (!ListValue) return FALSE;
938 if (ListValue->Type != REG_MULTI_SZ) return FALSE;
939
940 /* Copy it into a buffer */
941 OrderList.Buffer = (PWCHAR)CmpValueToData(Hive, ListValue, &Length);
942 if (!OrderList.Buffer) return FALSE;
943 if (!IS_NULL_TERMINATED(OrderList.Buffer, Length)) return FALSE;
944 OrderList.Length = (USHORT)Length - sizeof(UNICODE_NULL);
945 OrderList.MaximumLength = OrderList.Length;
946
947 /* And start the sort algorithm */
948 return CmpDoSort(DriverListHead, &OrderList);
949}
950
951CODE_SEG("INIT")
952static
955 _In_ PBOOT_DRIVER_NODE StartNode,
956 _In_ PBOOT_DRIVER_NODE EndNode)
957{
958 PBOOT_DRIVER_NODE CurrentNode, PreviousNode;
959 PLIST_ENTRY ListEntry;
960
961 /* Base case, nothing to do */
962 if (StartNode == EndNode) return TRUE;
963
964 /* Loop the nodes */
965 CurrentNode = StartNode;
966 do
967 {
968 /* Save this as the previous node */
969 PreviousNode = CurrentNode;
970
971 /* And move to the next one */
972 ListEntry = CurrentNode->ListEntry.Link.Flink;
973 CurrentNode = CONTAINING_RECORD(ListEntry,
975 ListEntry.Link);
976
977 /* Check if the previous driver had a bigger tag */
978 if (PreviousNode->Tag > CurrentNode->Tag)
979 {
980 /* Check if we need to update the tail */
981 if (CurrentNode == EndNode)
982 {
983 /* Update the tail */
984 ListEntry = CurrentNode->ListEntry.Link.Blink;
985 EndNode = CONTAINING_RECORD(ListEntry,
987 ListEntry.Link);
988 }
989
990 /* Remove this driver since we need to move it */
991 RemoveEntryList(&CurrentNode->ListEntry.Link);
992
993 /* Keep looping until we find a driver with a lower tag than ours */
994 while ((PreviousNode->Tag > CurrentNode->Tag) && (PreviousNode != StartNode))
995 {
996 /* We'll be re-inserted at this spot */
997 ListEntry = PreviousNode->ListEntry.Link.Blink;
998 PreviousNode = CONTAINING_RECORD(ListEntry,
1000 ListEntry.Link);
1001 }
1002
1003 /* Do the insert in the new location */
1004 InsertTailList(&PreviousNode->ListEntry.Link, &CurrentNode->ListEntry.Link);
1005
1006 /* Update the head, if needed */
1007 if (PreviousNode == StartNode) StartNode = CurrentNode;
1008 }
1009 } while (CurrentNode != EndNode);
1010
1011 /* All done */
1012 return TRUE;
1013}
1014
1025CODE_SEG("INIT")
1026BOOLEAN
1027NTAPI
1029 _Inout_ PLIST_ENTRY DriverListHead)
1030{
1031 PLIST_ENTRY NextEntry;
1032 PBOOT_DRIVER_NODE StartNode, EndNode, CurrentNode;
1033
1034 /* Loop the list */
1035 NextEntry = DriverListHead->Flink;
1036 while (NextEntry != DriverListHead)
1037 {
1038 /* Find the first entry */
1039 StartNode = CONTAINING_RECORD(NextEntry,
1041 ListEntry.Link);
1042 do
1043 {
1044 /* Find the last entry */
1045 EndNode = CONTAINING_RECORD(NextEntry,
1047 ListEntry.Link);
1048
1049 /* Get the next entry */
1050 NextEntry = NextEntry->Flink;
1051 CurrentNode = CONTAINING_RECORD(NextEntry,
1053 ListEntry.Link);
1054
1055 /* If the next entry is back to the top, break out */
1056 if (NextEntry == DriverListHead) break;
1057
1058 /* Otherwise, check if this entry is equal */
1059 if (!RtlEqualUnicodeString(&StartNode->Group,
1060 &CurrentNode->Group,
1061 TRUE))
1062 {
1063 /* It is, so we've detected a cycle, break out */
1064 break;
1065 }
1066 } while (NextEntry != DriverListHead);
1067
1068 /* Now we have the correct start and end pointers, so do the sort */
1069 CmpOrderGroup(StartNode, EndNode);
1070 }
1071
1072 /* We're done */
1073 return TRUE;
1074}
1075
1076CODE_SEG("INIT")
1077static
1078BOOLEAN
1080 _In_ PHHIVE Hive,
1081 _In_ HCELL_INDEX SafeBootCell,
1082 _In_ HCELL_INDEX DriverCell)
1083{
1084 PCM_KEY_NODE SafeBootNode;
1085 PCM_KEY_NODE DriverNode;
1086 PCM_KEY_VALUE KeyValue;
1087 HCELL_INDEX CellIndex;
1088 ULONG Length;
1090 PWCHAR Buffer;
1091
1092 /* Sanity check: We shouldn't need to release any acquired cells */
1093 ASSERT(Hive->ReleaseCellRoutine == NULL);
1094
1095 /* Driver key node (mandatory) */
1096 ASSERT(DriverCell != HCELL_NIL);
1097 DriverNode = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell);
1098 if (!DriverNode) return FALSE;
1099
1100 /* Safe boot key node (optional but return TRUE if not present) */
1101 if (SafeBootCell == HCELL_NIL) return TRUE;
1102 SafeBootNode = (PCM_KEY_NODE)HvGetCell(Hive, SafeBootCell);
1103 if (!SafeBootNode) return FALSE;
1104
1105 /* Search by the name from the group */
1106 RtlInitUnicodeString(&Name, L"Group");
1107 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
1108 if (CellIndex != HCELL_NIL)
1109 {
1110 KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
1111 if (!KeyValue) return FALSE;
1112
1113 if (KeyValue->Type == REG_SZ) // REG_EXPAND_SZ not really allowed there.
1114 {
1115 /* Compose the search 'key' */
1116 Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
1117 if (!Buffer)
1118 return FALSE;
1120 Length -= sizeof(UNICODE_NULL);
1121
1122 Name.Buffer = Buffer;
1123 Name.Length = (USHORT)Length;
1124 Name.MaximumLength = Name.Length;
1125
1126 /* Search for corresponding key in the Safe Boot key */
1127 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
1128 if (CellIndex != HCELL_NIL) return TRUE;
1129 }
1130 }
1131
1132 /* Group has not been found - find driver name */
1133 Length = (DriverNode->Flags & KEY_COMP_NAME) ?
1134 CmpCompressedNameSize(DriverNode->Name, DriverNode->NameLength) :
1135 DriverNode->NameLength;
1136 if (Length < sizeof(WCHAR))
1137 return FALSE;
1138
1139 /* Now allocate the buffer for it and copy the name */
1141 Hive->Allocate(Length, FALSE, TAG_CM),
1142 (USHORT)Length);
1143 if (!Name.Buffer)
1144 return FALSE;
1145
1146 Name.Length = (USHORT)Length;
1147 if (DriverNode->Flags & KEY_COMP_NAME)
1148 {
1149 /* Compressed name */
1151 Name.Length,
1152 DriverNode->Name,
1153 DriverNode->NameLength);
1154 }
1155 else
1156 {
1157 /* Normal name */
1158 RtlCopyMemory(Name.Buffer, DriverNode->Name, DriverNode->NameLength);
1159 }
1160
1161 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
1162 Hive->Free(Name.Buffer, Name.MaximumLength);
1163 if (CellIndex != HCELL_NIL) return TRUE;
1164
1165 /* Not group or driver name - search by image name */
1166 RtlInitUnicodeString(&Name, L"ImagePath");
1167 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
1168 if (CellIndex != HCELL_NIL)
1169 {
1170 KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
1171 if (!KeyValue) return FALSE;
1172
1173 if ((KeyValue->Type == REG_SZ) || (KeyValue->Type == REG_EXPAND_SZ))
1174 {
1175 /* Compose the search 'key' */
1176 Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
1177 if (!Buffer) return FALSE;
1178 if (Length < sizeof(WCHAR)) return FALSE;
1179
1180 /* Get the base image file name */
1181 // FIXME: wcsrchr() may fail if Buffer is *not* NULL-terminated!
1183 if (!Name.Buffer) return FALSE;
1184 ++Name.Buffer;
1185
1186 /* Length of the base name must be >=1 WCHAR */
1187 if (((ULONG_PTR)Name.Buffer - (ULONG_PTR)Buffer) >= Length)
1188 return FALSE;
1189 Length -= ((ULONG_PTR)Name.Buffer - (ULONG_PTR)Buffer);
1190 if (IS_NULL_TERMINATED(Name.Buffer, Length))
1191 Length -= sizeof(UNICODE_NULL);
1192 if (Length < sizeof(WCHAR)) return FALSE;
1193
1194 Name.Length = (USHORT)Length;
1195 Name.MaximumLength = Name.Length;
1196
1197 /* Search for corresponding key in the Safe Boot key */
1198 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
1199 if (CellIndex != HCELL_NIL) return TRUE;
1200 }
1201 }
1202
1203 /* Nothing found - nothing else to search */
1204 return FALSE;
1205}
1206
1219CODE_SEG("INIT")
1220VOID
1221NTAPI
1223 _In_ PHHIVE Hive,
1224 _Inout_ PLIST_ENTRY DriverListHead)
1225{
1227 PBOOT_DRIVER_NODE DriverNode;
1228
1229 /* Loop through the list and remove each driver node */
1230 while (!IsListEmpty(DriverListHead))
1231 {
1232 /* Get the driver node */
1233 Entry = RemoveHeadList(DriverListHead);
1234 DriverNode = CONTAINING_RECORD(Entry,
1236 ListEntry.Link);
1237
1238 /* Free any allocated string buffers, then the node */
1239 if (DriverNode->ListEntry.RegistryPath.Buffer)
1240 {
1241 Hive->Free(DriverNode->ListEntry.RegistryPath.Buffer,
1243 }
1244 if (DriverNode->ListEntry.FilePath.Buffer)
1245 {
1246 Hive->Free(DriverNode->ListEntry.FilePath.Buffer,
1247 DriverNode->ListEntry.FilePath.MaximumLength);
1248 }
1249 if (DriverNode->Name.Buffer)
1250 {
1251 Hive->Free(DriverNode->Name.Buffer,
1252 DriverNode->Name.MaximumLength);
1253 }
1254 Hive->Free(DriverNode, sizeof(BOOT_DRIVER_NODE));
1255 }
1256}
1257
1258/* EOF */
#define CODE_SEG(...)
PCWSTR FilePath
unsigned char BOOLEAN
Definition: actypes.h:127
#define REG_SZ
Definition: layer.c:22
@ INIT
Definition: arabic.c:42
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
LONG NTSTATUS
Definition: precomp.h:26
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
PHHIVE SystemHive
Definition: registry.c:33
RtlInitEmptyUnicodeString(SymbolicLinkName, NULL, 0)
Definition: bufpool.h:45
#define CMTRACE(x, fmt,...)
Definition: cm.h:40
#define CM_BOOT_DEBUG
Definition: cmboot.c:39
BOOLEAN NTAPI CmpFindDrivers(_In_ PHHIVE Hive, _In_ HCELL_INDEX ControlSet, _In_ SERVICE_LOAD_TYPE LoadType, _In_opt_ PCWSTR BootFileSystem, _Inout_ PLIST_ENTRY DriverListHead)
Enumerates all drivers within the given control set and load type, present in the "Services" sub-key,...
Definition: cmboot.c:677
static BOOLEAN CmpIsLoadType(_In_ PHHIVE Hive, _In_ HCELL_INDEX Cell, _In_ SERVICE_LOAD_TYPE LoadType)
Checks whether the specified driver has the expected load type.
Definition: cmboot.c:616
static ULONG CmpFindTagIndex(_In_ PHHIVE Hive, _In_ HCELL_INDEX TagCell, _In_ HCELL_INDEX GroupOrderCell, _In_ PCUNICODE_STRING GroupName)
Finds the index of the driver's "Tag" value in its corresponding group ordering list.
Definition: cmboot.c:213
BOOLEAN NTAPI CmpResolveDriverDependencies(_Inout_ PLIST_ENTRY DriverListHead)
Removes potential circular dependencies (cycles) and sorts the driver list.
Definition: cmboot.c:1028
HCELL_INDEX NTAPI CmpFindControlSet(_In_ PHHIVE SystemHive, _In_ HCELL_INDEX RootCell, _In_ PCUNICODE_STRING SelectKeyName, _Out_ PBOOLEAN AutoSelect)
Finds the corresponding "HKLM\SYSTEM\ControlSetXXX" system control set registry key,...
Definition: cmboot.c:82
static BOOLEAN CmpIsSafe(_In_ PHHIVE Hive, _In_ HCELL_INDEX SafeBootCell, _In_ HCELL_INDEX DriverCell)
Definition: cmboot.c:1079
BOOLEAN NTAPI CmpAddDriverToList(_In_ PHHIVE Hive, _In_ HCELL_INDEX DriverCell, _In_ HCELL_INDEX GroupOrderCell, _In_ PCUNICODE_STRING RegistryPath, _Inout_ PLIST_ENTRY DriverListHead)
Inserts the specified driver entry into the driver list.
Definition: cmboot.c:362
#define IS_NULL_TERMINATED(Buffer, Size)
Definition: cmboot.c:41
static BOOLEAN CmpDoSort(_Inout_ PLIST_ENTRY DriverListHead, _In_ PCUNICODE_STRING OrderList)
Performs the driver list sorting, according to the ordering list.
Definition: cmboot.c:826
static BOOLEAN CmpOrderGroup(_In_ PBOOT_DRIVER_NODE StartNode, _In_ PBOOT_DRIVER_NODE EndNode)
Definition: cmboot.c:954
BOOLEAN NTAPI CmpSortDriverList(_In_ PHHIVE Hive, _In_ HCELL_INDEX ControlSet, _Inout_ PLIST_ENTRY DriverListHead)
Sorts the driver list, according to the drivers' group load ordering.
Definition: cmboot.c:900
VOID NTAPI CmpFreeDriverList(_In_ PHHIVE Hive, _Inout_ PLIST_ENTRY DriverListHead)
Empties the driver list and frees all allocated driver nodes in it.
Definition: cmboot.c:1222
struct _CM_KEY_NODE * PCM_KEY_NODE
#define KEY_COMP_NAME
Definition: cmdata.h:35
struct _CM_KEY_VALUE * PCM_KEY_VALUE
HCELL_INDEX NTAPI CmpFindSubKeyByNumber(IN PHHIVE Hive, IN PCM_KEY_NODE Node, IN ULONG Number)
Definition: cmindex.c:600
HCELL_INDEX NTAPI CmpFindSubKeyByName(IN PHHIVE Hive, IN PCM_KEY_NODE Parent, IN PCUNICODE_STRING SearchName)
Definition: cmindex.c:683
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
VOID NTAPI CmpCopyCompressedName(OUT PWCHAR Destination, IN ULONG DestinationLength, IN PWCHAR Source, IN ULONG SourceLength)
Definition: cmname.c:56
HCELL_INDEX NTAPI CmpFindValueByName(IN PHHIVE Hive, IN PCM_KEY_NODE KeyNode, IN PCUNICODE_STRING Name)
Definition: cmvalue.c:99
PCELL_DATA NTAPI CmpValueToData(IN PHHIVE Hive, IN PCM_KEY_VALUE Value, OUT PULONG Length)
Definition: cmvalue.c:167
USHORT NTAPI CmpCompressedNameSize(IN PWCHAR Name, IN ULONG Length)
Definition: cmname.c:95
#define HvGetCell(Hive, Cell)
Definition: cmlib.h:473
#define TAG_CM
Definition: cmlib.h:219
PUCHAR End
Definition: desccheck.cpp:2229
LPWSTR Name
Definition: desk.c:124
PLIST_ENTRY Entry
Definition: devhcd.cpp:1262
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
union node Node
Definition: types.h:1255
#define RTL_CONSTANT_STRING(s)
Definition: combase.c:35
#define wcsrchr
Definition: compat.h:16
DRIVER_INITIALIZE DriverEntry
Definition: condrv.c:21
#define L(x)
Definition: resources.c:13
PULONG InitSafeBootMode
Definition: init.c:75
#define ULONG_PTR
Definition: config.h:101
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
NTSTATUS RtlAppendUnicodeToString(IN PUNICODE_STRING Str1, IN PWSTR Str2)
Definition: string_lib.cpp:62
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
Status
Definition: gdiplustypes.h:24
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
#define HCELL_NIL
Definition: hivedata.h:110
ULONG HCELL_INDEX
Definition: hivedata.h:105
UNICODE_STRING KeyPath
HubUxdSettings Current
#define ASSERT(a)
Definition: mode.c:44
#define _Out_opt_
Definition: no_sal2.h:214
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
#define REG_MULTI_SZ
Definition: nt_native.h:1504
#define REG_EXPAND_SZ
Definition: nt_native.h:1497
#define UNICODE_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTRSAFEVAPI RtlStringCbPrintfW(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1173
short WCHAR
Definition: pedump.c:58
unsigned short USHORT
Definition: pedump.c:61
Input NameLength
Definition: portacpi.cpp:298
#define REG_DWORD
Definition: sdbapi.c:615
Definition: arc.h:334
LIST_ENTRY Link
Definition: arc.h:335
UNICODE_STRING RegistryPath
Definition: arc.h:337
UNICODE_STRING FilePath
Definition: arc.h:336
UNICODE_STRING Group
Definition: cmboot.h:16
BOOT_DRIVER_LIST_ENTRY ListEntry
Definition: cmboot.h:15
ULONG ErrorControl
Definition: cmboot.h:19
UNICODE_STRING Name
Definition: cmboot.h:17
WCHAR Name[ANYSIZE_ARRAY]
Definition: cmdata.h:116
USHORT NameLength
Definition: cmdata.h:114
USHORT Flags
Definition: cmdata.h:93
ULONG Type
Definition: cmdata.h:128
PRELEASE_CELL_ROUTINE ReleaseCellRoutine
Definition: hivedata.h:317
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
USHORT MaximumLength
Definition: env_spec_w32.h:370
uint32_t * PULONG
Definition: typedefs.h:59
const uint16_t * PCWSTR
Definition: typedefs.h:57
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
Definition: dlist.c:348
_Must_inspect_result_ _In_ PDRIVER_OBJECT _In_ PCUNICODE_STRING RegistryPath
Definition: wdfdriver.h:215
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
PCWSTR BootFileSystem
Definition: winldr.c:31
@ NormalError
Definition: cmtypes.h:1006
#define SERVICE_ERROR_CRITICAL
Definition: cmtypes.h:985
enum _CM_SERVICE_LOAD_TYPE SERVICE_LOAD_TYPE