ReactOS 0.4.16-dev-91-g764881a
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.
49
50CODE_SEG("INIT")
51static
54 _In_ PHHIVE Hive,
55 _In_ HCELL_INDEX SafeBootCell,
56 _In_ HCELL_INDEX DriverCell);
57
81CODE_SEG("INIT")
86 _In_ HCELL_INDEX RootCell,
87 _In_ PCUNICODE_STRING SelectKeyName,
88 _Out_ PBOOLEAN AutoSelect)
89{
92 HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell;
93 HCELL_INDEX CurrentValueCell;
97 PULONG CurrentData;
98 PULONG ControlSetId;
99 WCHAR Buffer[128];
100
101 /* Sanity check: We shouldn't need to release any acquired cells */
103
104 /* Get the Select key */
105 RtlInitUnicodeString(&Name, L"select");
107 if (!Node) return HCELL_NIL;
108 SelectCell = CmpFindSubKeyByName(SystemHive, Node, &Name);
109 if (SelectCell == HCELL_NIL) return HCELL_NIL;
110
111 /* Get AutoSelect value */
112 RtlInitUnicodeString(&Name, L"AutoSelect");
113 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
114 if (!Node) return HCELL_NIL;
115 AutoSelectCell = CmpFindValueByName(SystemHive, Node, &Name);
116 if (AutoSelectCell == HCELL_NIL)
117 {
118 /* Assume TRUE if the value is missing */
119 *AutoSelect = TRUE;
120 }
121 else
122 {
123 /* Read the value */
124 Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell);
125 if (!Value) return HCELL_NIL;
126 // if (Value->Type != REG_DWORD) return HCELL_NIL;
127
128 /* Convert it to a boolean */
129 CurrentData = (PULONG)CmpValueToData(SystemHive, Value, &Length);
130 if (!CurrentData) return HCELL_NIL;
131 // if (Length < sizeof(ULONG)) return HCELL_NIL;
132
133 *AutoSelect = *(PBOOLEAN)CurrentData;
134 }
135
136 /* Now find the control set being looked up */
137 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
138 if (!Node) return HCELL_NIL;
139 SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName);
140 if (SelectValueCell == HCELL_NIL) return HCELL_NIL;
141
142 /* Read the value (corresponding to the CCS ID) */
143 Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell);
144 if (!Value) return HCELL_NIL;
145 if (Value->Type != REG_DWORD) return HCELL_NIL;
146 ControlSetId = (PULONG)CmpValueToData(SystemHive, Value, &Length);
147 if (!ControlSetId) return HCELL_NIL;
148 if (Length < sizeof(ULONG)) return HCELL_NIL;
149
150 /* Now build the CCS's Name */
152 L"ControlSet%03lu", *ControlSetId);
153 if (!NT_SUCCESS(Status)) return HCELL_NIL;
154 /* RtlStringCbPrintfW ensures the buffer to be NULL-terminated */
156
157 /* Now open it */
159 if (!Node) return HCELL_NIL;
160 ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &Name);
161 if (ControlSetCell == HCELL_NIL) return HCELL_NIL;
162
163 /* Get the value of the "Current" CCS */
164 RtlInitUnicodeString(&Name, L"Current");
165 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell);
166 if (!Node) return HCELL_NIL;
167 CurrentValueCell = CmpFindValueByName(SystemHive, Node, &Name);
168
169 /* Make sure it exists */
170 if (CurrentValueCell != HCELL_NIL)
171 {
172 /* Get the current value and make sure it's a ULONG */
173 Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell);
174 if (!Value) return HCELL_NIL;
175 if (Value->Type == REG_DWORD)
176 {
177 /* Get the data and update it */
178 CurrentData = (PULONG)CmpValueToData(SystemHive, Value, &Length);
179 if (!CurrentData) return HCELL_NIL;
180 if (Length < sizeof(ULONG)) return HCELL_NIL;
181
182 *CurrentData = *ControlSetId;
183 }
184 }
185
186 /* Return the CCS cell */
187 return ControlSetCell;
188}
189
212CODE_SEG("INIT")
213static
214ULONG
216 _In_ PHHIVE Hive,
217 _In_ HCELL_INDEX TagCell,
218 _In_ HCELL_INDEX GroupOrderCell,
219 _In_ PCUNICODE_STRING GroupName)
220{
221 PCM_KEY_VALUE TagValue, Value;
223 HCELL_INDEX OrderCell;
224 PULONG DriverTag, TagOrder;
225 ULONG CurrentTag, Length;
226 BOOLEAN BufferAllocated;
227
228 /* Sanity check: We shouldn't need to release any acquired cells */
229 ASSERT(Hive->ReleaseCellRoutine == NULL);
230
231 /* Get the tag */
232 Value = (PCM_KEY_VALUE)HvGetCell(Hive, TagCell);
233 if (!Value) return -2;
234 if (Value->Type != REG_DWORD) return -2;
235 DriverTag = (PULONG)CmpValueToData(Hive, Value, &Length);
236 if (!DriverTag) return -2;
237 if (Length < sizeof(ULONG)) return -2;
238
239 /* Get the order array */
240 Node = (PCM_KEY_NODE)HvGetCell(Hive, GroupOrderCell);
241 if (!Node) return -2;
242 OrderCell = CmpFindValueByName(Hive, Node, GroupName);
243 if (OrderCell == HCELL_NIL) return -2;
244
245 /* And read it */
246 TagValue = (PCM_KEY_VALUE)HvGetCell(Hive, OrderCell);
247 if (!TagValue) return -2;
248 if (!CmpGetValueData(Hive,
249 TagValue,
250 &Length,
251 (PVOID*)&TagOrder,
252 &BufferAllocated,
253 &OrderCell)
254 || !TagOrder)
255 {
256 return -2;
257 }
258
259 /* Parse each tag */
260 for (CurrentTag = 1; CurrentTag <= TagOrder[0]; CurrentTag++)
261 {
262 /* Find a match */
263 if (TagOrder[CurrentTag] == *DriverTag)
264 {
265 /* Found it -- return the tag */
266 if (BufferAllocated) Hive->Free(TagOrder, Length);
267 return CurrentTag;
268 }
269 }
270
271 /* No matches, so assume next to last ordering */
272 if (BufferAllocated) Hive->Free(TagOrder, Length);
273 return -2;
274}
275
276#ifdef _BLDR_
277
298CODE_SEG("INIT")
300NTAPI
301CmpIsDriverInList(
302 _In_ PLIST_ENTRY DriverListHead,
303 _In_ PCUNICODE_STRING DriverName,
304 _Out_opt_ PBOOT_DRIVER_NODE* FoundDriver)
305{
307 PBOOT_DRIVER_NODE DriverNode;
308
309 for (Entry = DriverListHead->Flink;
310 Entry != DriverListHead;
311 Entry = Entry->Flink)
312 {
313 DriverNode = CONTAINING_RECORD(Entry,
315 ListEntry.Link);
316
317 if (RtlEqualUnicodeString(&DriverNode->Name,
318 DriverName,
319 TRUE))
320 {
321 /* The driver node has been found */
322 if (FoundDriver)
323 *FoundDriver = DriverNode;
324 return TRUE;
325 }
326 }
327
328 /* None has been found */
329 if (FoundDriver)
330 *FoundDriver = NULL;
331 return FALSE;
332}
333
334#endif /* _BLDR_ */
335
361CODE_SEG("INIT")
363NTAPI
365 _In_ PHHIVE Hive,
366 _In_ HCELL_INDEX DriverCell,
367 _In_ HCELL_INDEX GroupOrderCell,
369 _Inout_ PLIST_ENTRY DriverListHead)
370{
371 PBOOT_DRIVER_NODE DriverNode;
376 USHORT NameLength;
377 HCELL_INDEX ValueCell, TagCell;
378 PUNICODE_STRING FilePath, RegistryString;
380 PULONG ErrorControl;
382
383 /* Sanity check: We shouldn't need to release any acquired cells */
384 ASSERT(Hive->ReleaseCellRoutine == NULL);
385
386 /* Allocate a driver node and initialize it */
387 DriverNode = Hive->Allocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM);
388 if (!DriverNode)
389 return FALSE;
390
391 RtlZeroMemory(DriverNode, sizeof(BOOT_DRIVER_NODE));
392 DriverEntry = &DriverNode->ListEntry;
393
394 /* Get the driver cell */
395 Node = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell);
396 if (!Node)
397 goto Failure;
398
399 /* Get the name from the cell */
400 NameLength = (Node->Flags & KEY_COMP_NAME) ?
401 CmpCompressedNameSize(Node->Name, Node->NameLength) :
402 Node->NameLength;
403 if (NameLength < sizeof(WCHAR))
404 goto Failure;
405
406 /* Now allocate the buffer for it and copy the name */
407 RtlInitEmptyUnicodeString(&DriverNode->Name,
408 Hive->Allocate(NameLength, FALSE, TAG_CM),
409 NameLength);
410 if (!DriverNode->Name.Buffer)
411 goto Failure;
412
413 DriverNode->Name.Length = NameLength;
414 if (Node->Flags & KEY_COMP_NAME)
415 {
416 /* Compressed name */
418 DriverNode->Name.Length,
419 Node->Name,
420 Node->NameLength);
421 }
422 else
423 {
424 /* Normal name */
425 RtlCopyMemory(DriverNode->Name.Buffer, Node->Name, Node->NameLength);
426 }
427
428 /* Now find the image path */
429 RtlInitUnicodeString(&Name, L"ImagePath");
430 ValueCell = CmpFindValueByName(Hive, Node, &Name);
431 if (ValueCell == HCELL_NIL)
432 {
433 /* Could not find it, so assume the drivers path */
434 Length = sizeof(L"System32\\Drivers\\") + NameLength + sizeof(L".sys");
435
436 /* Allocate the path name */
437 FilePath = &DriverEntry->FilePath;
438 RtlInitEmptyUnicodeString(FilePath,
439 Hive->Allocate(Length, FALSE, TAG_CM),
440 (USHORT)Length);
441 if (!FilePath->Buffer)
442 goto Failure;
443
444 /* Write the path name */
445 if (!NT_SUCCESS(RtlAppendUnicodeToString(FilePath, L"System32\\Drivers\\")) ||
448 {
449 goto Failure;
450 }
451 }
452 else
453 {
454 /* Path name exists, so grab it */
455 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
456 if (!Value)
457 goto Failure;
458 if ((Value->Type != REG_SZ) && (Value->Type != REG_EXPAND_SZ))
459 goto Failure;
461 if (!Buffer)
462 goto Failure;
464 Length -= sizeof(UNICODE_NULL);
465 if (Length < sizeof(WCHAR))
466 goto Failure;
467
468 /* Allocate and setup the path name */
469 FilePath = &DriverEntry->FilePath;
470 RtlInitEmptyUnicodeString(FilePath,
471 Hive->Allocate(Length, FALSE, TAG_CM),
472 (USHORT)Length);
473 if (!FilePath->Buffer)
474 goto Failure;
475
476 /* Transfer the data */
478 FilePath->Length = (USHORT)Length;
479 }
480
481 /* Now build the registry path */
482 RegistryString = &DriverEntry->RegistryPath;
483 Length = RegistryPath->Length + NameLength;
484 RtlInitEmptyUnicodeString(RegistryString,
485 Hive->Allocate(Length, FALSE, TAG_CM),
486 (USHORT)Length);
487 if (!RegistryString->Buffer)
488 goto Failure;
489
490 /* Add the driver name to it */
492 !NT_SUCCESS(RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name)))
493 {
494 goto Failure;
495 }
496
497 /* The entry is done, add it */
498 InsertHeadList(DriverListHead, &DriverEntry->Link);
499
500 /* Now find error control settings */
501 RtlInitUnicodeString(&Name, L"ErrorControl");
502 ValueCell = CmpFindValueByName(Hive, Node, &Name);
503 if (ValueCell == HCELL_NIL)
504 {
505 /* Could not find it, so assume default */
506 DriverNode->ErrorControl = NormalError;
507 }
508 else
509 {
510 /* Otherwise, read whatever the data says */
511 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
512 if (!Value)
513 goto Failure;
514 if (Value->Type != REG_DWORD)
515 goto Failure;
516 ErrorControl = (PULONG)CmpValueToData(Hive, Value, &Length);
517 if (!ErrorControl)
518 goto Failure;
519 if (Length < sizeof(ULONG))
520 goto Failure;
521
522 DriverNode->ErrorControl = *ErrorControl;
523 }
524
525 /* Next, get the group cell */
526 RtlInitUnicodeString(&Name, L"group");
527 ValueCell = CmpFindValueByName(Hive, Node, &Name);
528 if (ValueCell == HCELL_NIL)
529 {
530 /* Could not find it, so set an empty string */
531 RtlInitEmptyUnicodeString(&DriverNode->Group, NULL, 0);
532 }
533 else
534 {
535 /* Found it, read the group value */
536 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
537 if (!Value)
538 goto Failure;
539 if (Value->Type != REG_SZ) // REG_EXPAND_SZ not really allowed there.
540 goto Failure;
541
542 /* Copy it into the node */
544 if (!Buffer)
545 goto Failure;
547 Length -= sizeof(UNICODE_NULL);
548
549 DriverNode->Group.Buffer = Buffer;
550 DriverNode->Group.Length = (USHORT)Length;
551 DriverNode->Group.MaximumLength = DriverNode->Group.Length;
552 }
553
554 /* Finally, find the tag */
556 TagCell = CmpFindValueByName(Hive, Node, &Name);
557 if (TagCell == HCELL_NIL)
558 {
559 /* No tag, so load last */
560 DriverNode->Tag = -1;
561 }
562 else
563 {
564 /* Otherwise, decode it based on tag order */
565 DriverNode->Tag = CmpFindTagIndex(Hive,
566 TagCell,
567 GroupOrderCell,
568 &DriverNode->Group);
569 }
570
571 CMTRACE(CM_BOOT_DEBUG, "Adding boot driver: '%wZ', '%wZ'\n",
572 &DriverNode->Name, &DriverEntry->FilePath);
573
574 /* All done! */
575 return TRUE;
576
577Failure:
578 if (DriverEntry->RegistryPath.Buffer)
579 {
580 Hive->Free(DriverEntry->RegistryPath.Buffer,
581 DriverEntry->RegistryPath.MaximumLength);
582 }
583 if (DriverEntry->FilePath.Buffer)
584 {
585 Hive->Free(DriverEntry->FilePath.Buffer,
586 DriverEntry->FilePath.MaximumLength);
587 }
588 if (DriverNode->Name.Buffer)
589 {
590 Hive->Free(DriverNode->Name.Buffer,
591 DriverNode->Name.MaximumLength);
592 }
593 Hive->Free(DriverNode, sizeof(BOOT_DRIVER_NODE));
594
595 return FALSE;
596}
597
615CODE_SEG("INIT")
616static
619 _In_ PHHIVE Hive,
620 _In_ HCELL_INDEX Cell,
621 _In_ SERVICE_LOAD_TYPE LoadType)
622{
626 HCELL_INDEX ValueCell;
628 PULONG Data;
629
630 /* Sanity check: We shouldn't need to release any acquired cells */
631 ASSERT(Hive->ReleaseCellRoutine == NULL);
632
633 /* Open the start cell */
634 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
635 if (!Node) return FALSE;
636 ValueCell = CmpFindValueByName(Hive, Node, &Name);
637 if (ValueCell == HCELL_NIL) return FALSE;
638
639 /* Read the start value */
640 Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
641 if (!Value) return FALSE;
642 if (Value->Type != REG_DWORD) return FALSE;
644 if (!Data) return FALSE;
645 if (Length < sizeof(ULONG)) return FALSE;
646
647 /* Return if the type matches */
648 return (*Data == LoadType);
649}
650
676CODE_SEG("INIT")
678NTAPI
680 _In_ PHHIVE Hive,
681 _In_ HCELL_INDEX ControlSet,
682 _In_ SERVICE_LOAD_TYPE LoadType,
684 _Inout_ PLIST_ENTRY DriverListHead)
685{
686 HCELL_INDEX ServicesCell, ControlCell, GroupOrderCell, DriverCell;
687 HCELL_INDEX SafeBootCell = HCELL_NIL;
688 ULONG i;
690 UNICODE_STRING KeyPath;
691 PCM_KEY_NODE ControlNode, ServicesNode, Node;
692 PBOOT_DRIVER_NODE FsNode;
693
694 /* Sanity check: We shouldn't need to release any acquired cells */
695 ASSERT(Hive->ReleaseCellRoutine == NULL);
696
697 /* Open the control set key */
698 ControlNode = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet);
699 if (!ControlNode) return FALSE;
700
701 /* Get services cell */
702 RtlInitUnicodeString(&Name, L"Services");
703 ServicesCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
704 if (ServicesCell == HCELL_NIL) return FALSE;
705
706 /* Open services key */
707 ServicesNode = (PCM_KEY_NODE)HvGetCell(Hive, ServicesCell);
708 if (!ServicesNode) return FALSE;
709
710 /* Get control cell */
711 RtlInitUnicodeString(&Name, L"Control");
712 ControlCell = CmpFindSubKeyByName(Hive, ControlNode, &Name);
713 if (ControlCell == HCELL_NIL) return FALSE;
714
715 /* Get the group order cell and read it */
716 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
717 if (!Node) return FALSE;
718 RtlInitUnicodeString(&Name, L"GroupOrderList");
719 GroupOrderCell = CmpFindSubKeyByName(Hive, Node, &Name);
720 if (GroupOrderCell == HCELL_NIL) return FALSE;
721
722 /* Get Safe Boot cell */
724 {
725 /* Open the Safe Boot key */
726 RtlInitUnicodeString(&Name, L"SafeBoot");
727 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
728 if (!Node) return FALSE;
729 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
730 if (SafeBootCell == HCELL_NIL) return FALSE;
731
732 /* Open the correct start key (depending on the mode) */
733 Node = (PCM_KEY_NODE)HvGetCell(Hive, SafeBootCell);
734 if (!Node) return FALSE;
735 switch (InitSafeBootMode)
736 {
737 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
738 case 1:
739 case 3: RtlInitUnicodeString(&Name, L"Minimal"); break;
740 case 2: RtlInitUnicodeString(&Name, L"Network"); break;
741 default: return FALSE;
742 }
743 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name);
744 if (SafeBootCell == HCELL_NIL) return FALSE;
745 }
746
747 /* Build the root registry path */
748 RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
749
750 /* Enumerate each sub-key */
751 i = 0;
752 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, i);
753 while (DriverCell != HCELL_NIL)
754 {
755 /* Make sure it's a driver of this start type AND is "safe" to load */
756 if (CmpIsLoadType(Hive, DriverCell, LoadType) &&
757 CmpIsSafe(Hive, SafeBootCell, DriverCell))
758 {
759 /* Add it to the list */
760 if (!CmpAddDriverToList(Hive,
761 DriverCell,
762 GroupOrderCell,
763 &KeyPath,
764 DriverListHead))
765 {
766 CMTRACE(CM_BOOT_DEBUG, " Failed to add boot driver\n");
767 }
768 }
769
770 /* Go to the next sub-key */
771 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, ++i);
772 }
773
774 /* Check if we have a boot file system */
775 if (BootFileSystem)
776 {
777 /* Find it */
779 DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &Name);
780 if (DriverCell != HCELL_NIL)
781 {
782 CMTRACE(CM_BOOT_DEBUG, "Adding Boot FileSystem '%S'\n",
784
785 /* Always add it to the list */
786 if (!CmpAddDriverToList(Hive,
787 DriverCell,
788 GroupOrderCell,
789 &KeyPath,
790 DriverListHead))
791 {
792 CMTRACE(CM_BOOT_DEBUG, " Failed to add boot driver\n");
793 }
794 else
795 {
796 /* Mark it as critical so it always loads */
797 FsNode = CONTAINING_RECORD(DriverListHead->Flink,
799 ListEntry.Link);
801 }
802 }
803 }
804
805 /* We're done! */
806 return TRUE;
807}
808
825CODE_SEG("INIT")
826static
829 _Inout_ PLIST_ENTRY DriverListHead,
830 _In_ PCUNICODE_STRING OrderList)
831{
832 PWCHAR Current, End = NULL;
833 UNICODE_STRING GroupName;
834 PLIST_ENTRY NextEntry;
835 PBOOT_DRIVER_NODE CurrentNode;
836
837 /* We're going from end to start, so get to the last group and keep going */
838 Current = &OrderList->Buffer[OrderList->Length / sizeof(WCHAR)];
839 while (Current > OrderList->Buffer)
840 {
841 /* Scan the current string */
842 do
843 {
844 if (*Current == UNICODE_NULL) End = Current;
845 } while ((*(--Current - 1) != UNICODE_NULL) && (Current != OrderList->Buffer));
846
847 /* This is our cleaned up string for this specific group */
848 ASSERT(End != NULL);
849 GroupName.Length = (USHORT)(End - Current) * sizeof(WCHAR);
850 GroupName.MaximumLength = GroupName.Length;
851 GroupName.Buffer = Current;
852
853 /* Now loop the driver list */
854 NextEntry = DriverListHead->Flink;
855 while (NextEntry != DriverListHead)
856 {
857 /* Get this node */
858 CurrentNode = CONTAINING_RECORD(NextEntry,
860 ListEntry.Link);
861
862 /* Get the next entry now since we'll do a relink */
863 NextEntry = NextEntry->Flink;
864
865 /* Is there a group name and does it match the current group? */
866 if (CurrentNode->Group.Buffer &&
867 RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE))
868 {
869 /* Remove from this location and re-link in the new one */
870 RemoveEntryList(&CurrentNode->ListEntry.Link);
871 InsertHeadList(DriverListHead, &CurrentNode->ListEntry.Link);
872 }
873 }
874
875 /* Move on */
876 --Current;
877 }
878
879 /* All done */
880 return TRUE;
881}
882
899CODE_SEG("INIT")
901NTAPI
903 _In_ PHHIVE Hive,
904 _In_ HCELL_INDEX ControlSet,
905 _Inout_ PLIST_ENTRY DriverListHead)
906{
908 PCM_KEY_VALUE ListValue;
909 HCELL_INDEX ControlCell, GroupOrder, ListCell;
910 UNICODE_STRING Name, OrderList;
912
913 /* Sanity check: We shouldn't need to release any acquired cells */
914 ASSERT(Hive->ReleaseCellRoutine == NULL);
915
916 /* Open the control key */
917 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet);
918 if (!Node) return FALSE;
919 RtlInitUnicodeString(&Name, L"Control");
920 ControlCell = CmpFindSubKeyByName(Hive, Node, &Name);
921 if (ControlCell == HCELL_NIL) return FALSE;
922
923 /* Open the service group order */
924 Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlCell);
925 if (!Node) return FALSE;
926 RtlInitUnicodeString(&Name, L"ServiceGroupOrder");
927 GroupOrder = CmpFindSubKeyByName(Hive, Node, &Name);
928 if (GroupOrder == HCELL_NIL) return FALSE;
929
930 /* Open the list key */
931 Node = (PCM_KEY_NODE)HvGetCell(Hive, GroupOrder);
932 if (!Node) return FALSE;
933 RtlInitUnicodeString(&Name, L"list");
934 ListCell = CmpFindValueByName(Hive, Node, &Name);
935 if (ListCell == HCELL_NIL) return FALSE;
936
937 /* Read the actual list */
938 ListValue = (PCM_KEY_VALUE)HvGetCell(Hive, ListCell);
939 if (!ListValue) return FALSE;
940 if (ListValue->Type != REG_MULTI_SZ) return FALSE;
941
942 /* Copy it into a buffer */
943 OrderList.Buffer = (PWCHAR)CmpValueToData(Hive, ListValue, &Length);
944 if (!OrderList.Buffer) return FALSE;
945 if (!IS_NULL_TERMINATED(OrderList.Buffer, Length)) return FALSE;
946 OrderList.Length = (USHORT)Length - sizeof(UNICODE_NULL);
947 OrderList.MaximumLength = OrderList.Length;
948
949 /* And start the sort algorithm */
950 return CmpDoSort(DriverListHead, &OrderList);
951}
952
953CODE_SEG("INIT")
954static
957 _In_ PBOOT_DRIVER_NODE StartNode,
958 _In_ PBOOT_DRIVER_NODE EndNode)
959{
960 PBOOT_DRIVER_NODE CurrentNode, PreviousNode;
961 PLIST_ENTRY ListEntry;
962
963 /* Base case, nothing to do */
964 if (StartNode == EndNode) return TRUE;
965
966 /* Loop the nodes */
967 CurrentNode = StartNode;
968 do
969 {
970 /* Save this as the previous node */
971 PreviousNode = CurrentNode;
972
973 /* And move to the next one */
974 ListEntry = CurrentNode->ListEntry.Link.Flink;
975 CurrentNode = CONTAINING_RECORD(ListEntry,
977 ListEntry.Link);
978
979 /* Check if the previous driver had a bigger tag */
980 if (PreviousNode->Tag > CurrentNode->Tag)
981 {
982 /* Check if we need to update the tail */
983 if (CurrentNode == EndNode)
984 {
985 /* Update the tail */
986 ListEntry = CurrentNode->ListEntry.Link.Blink;
987 EndNode = CONTAINING_RECORD(ListEntry,
989 ListEntry.Link);
990 }
991
992 /* Remove this driver since we need to move it */
993 RemoveEntryList(&CurrentNode->ListEntry.Link);
994
995 /* Keep looping until we find a driver with a lower tag than ours */
996 while ((PreviousNode->Tag > CurrentNode->Tag) && (PreviousNode != StartNode))
997 {
998 /* We'll be re-inserted at this spot */
999 ListEntry = PreviousNode->ListEntry.Link.Blink;
1000 PreviousNode = CONTAINING_RECORD(ListEntry,
1002 ListEntry.Link);
1003 }
1004
1005 /* Do the insert in the new location */
1006 InsertTailList(&PreviousNode->ListEntry.Link, &CurrentNode->ListEntry.Link);
1007
1008 /* Update the head, if needed */
1009 if (PreviousNode == StartNode) StartNode = CurrentNode;
1010 }
1011 } while (CurrentNode != EndNode);
1012
1013 /* All done */
1014 return TRUE;
1015}
1016
1027CODE_SEG("INIT")
1028BOOLEAN
1029NTAPI
1031 _Inout_ PLIST_ENTRY DriverListHead)
1032{
1033 PLIST_ENTRY NextEntry;
1034 PBOOT_DRIVER_NODE StartNode, EndNode, CurrentNode;
1035
1036 /* Loop the list */
1037 NextEntry = DriverListHead->Flink;
1038 while (NextEntry != DriverListHead)
1039 {
1040 /* Find the first entry */
1041 StartNode = CONTAINING_RECORD(NextEntry,
1043 ListEntry.Link);
1044 do
1045 {
1046 /* Find the last entry */
1047 EndNode = CONTAINING_RECORD(NextEntry,
1049 ListEntry.Link);
1050
1051 /* Get the next entry */
1052 NextEntry = NextEntry->Flink;
1053 CurrentNode = CONTAINING_RECORD(NextEntry,
1055 ListEntry.Link);
1056
1057 /* If the next entry is back to the top, break out */
1058 if (NextEntry == DriverListHead) break;
1059
1060 /* Otherwise, check if this entry is equal */
1061 if (!RtlEqualUnicodeString(&StartNode->Group,
1062 &CurrentNode->Group,
1063 TRUE))
1064 {
1065 /* It is, so we've detected a cycle, break out */
1066 break;
1067 }
1068 } while (NextEntry != DriverListHead);
1069
1070 /* Now we have the correct start and end pointers, so do the sort */
1071 CmpOrderGroup(StartNode, EndNode);
1072 }
1073
1074 /* We're done */
1075 return TRUE;
1076}
1077
1078CODE_SEG("INIT")
1079static
1080BOOLEAN
1082 _In_ PHHIVE Hive,
1083 _In_ HCELL_INDEX SafeBootCell,
1084 _In_ HCELL_INDEX DriverCell)
1085{
1086 PCM_KEY_NODE SafeBootNode;
1087 PCM_KEY_NODE DriverNode;
1088 PCM_KEY_VALUE KeyValue;
1089 HCELL_INDEX CellIndex;
1090 ULONG Length;
1092 PWCHAR Buffer;
1093
1094 /* Sanity check: We shouldn't need to release any acquired cells */
1095 ASSERT(Hive->ReleaseCellRoutine == NULL);
1096
1097 /* Driver key node (mandatory) */
1098 ASSERT(DriverCell != HCELL_NIL);
1099 DriverNode = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell);
1100 if (!DriverNode) return FALSE;
1101
1102 /* Safe boot key node (optional but return TRUE if not present) */
1103 if (SafeBootCell == HCELL_NIL) return TRUE;
1104 SafeBootNode = (PCM_KEY_NODE)HvGetCell(Hive, SafeBootCell);
1105 if (!SafeBootNode) return FALSE;
1106
1107 /* Search by the name from the group */
1108 RtlInitUnicodeString(&Name, L"Group");
1109 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
1110 if (CellIndex != HCELL_NIL)
1111 {
1112 KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
1113 if (!KeyValue) return FALSE;
1114
1115 if (KeyValue->Type == REG_SZ) // REG_EXPAND_SZ not really allowed there.
1116 {
1117 /* Compose the search 'key' */
1118 Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
1119 if (!Buffer)
1120 return FALSE;
1122 Length -= sizeof(UNICODE_NULL);
1123
1124 Name.Buffer = Buffer;
1125 Name.Length = (USHORT)Length;
1126 Name.MaximumLength = Name.Length;
1127
1128 /* Search for corresponding key in the Safe Boot key */
1129 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
1130 if (CellIndex != HCELL_NIL) return TRUE;
1131 }
1132 }
1133
1134 /* Group has not been found - find driver name */
1135 Length = (DriverNode->Flags & KEY_COMP_NAME) ?
1136 CmpCompressedNameSize(DriverNode->Name, DriverNode->NameLength) :
1137 DriverNode->NameLength;
1138 if (Length < sizeof(WCHAR))
1139 return FALSE;
1140
1141 /* Now allocate the buffer for it and copy the name */
1142 RtlInitEmptyUnicodeString(&Name,
1143 Hive->Allocate(Length, FALSE, TAG_CM),
1144 (USHORT)Length);
1145 if (!Name.Buffer)
1146 return FALSE;
1147
1148 Name.Length = (USHORT)Length;
1149 if (DriverNode->Flags & KEY_COMP_NAME)
1150 {
1151 /* Compressed name */
1153 Name.Length,
1154 DriverNode->Name,
1155 DriverNode->NameLength);
1156 }
1157 else
1158 {
1159 /* Normal name */
1160 RtlCopyMemory(Name.Buffer, DriverNode->Name, DriverNode->NameLength);
1161 }
1162
1163 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
1164 Hive->Free(Name.Buffer, Name.MaximumLength);
1165 if (CellIndex != HCELL_NIL) return TRUE;
1166
1167 /* Not group or driver name - search by image name */
1168 RtlInitUnicodeString(&Name, L"ImagePath");
1169 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name);
1170 if (CellIndex != HCELL_NIL)
1171 {
1172 KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
1173 if (!KeyValue) return FALSE;
1174
1175 if ((KeyValue->Type == REG_SZ) || (KeyValue->Type == REG_EXPAND_SZ))
1176 {
1177 /* Compose the search 'key' */
1178 Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length);
1179 if (!Buffer) return FALSE;
1180 if (Length < sizeof(WCHAR)) return FALSE;
1181
1182 /* Get the base image file name */
1183 // FIXME: wcsrchr() may fail if Buffer is *not* NULL-terminated!
1185 if (!Name.Buffer) return FALSE;
1186 ++Name.Buffer;
1187
1188 /* Length of the base name must be >=1 WCHAR */
1189 if (((ULONG_PTR)Name.Buffer - (ULONG_PTR)Buffer) >= Length)
1190 return FALSE;
1191 Length -= ((ULONG_PTR)Name.Buffer - (ULONG_PTR)Buffer);
1192 if (IS_NULL_TERMINATED(Name.Buffer, Length))
1193 Length -= sizeof(UNICODE_NULL);
1194 if (Length < sizeof(WCHAR)) return FALSE;
1195
1196 Name.Length = (USHORT)Length;
1197 Name.MaximumLength = Name.Length;
1198
1199 /* Search for corresponding key in the Safe Boot key */
1200 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name);
1201 if (CellIndex != HCELL_NIL) return TRUE;
1202 }
1203 }
1204
1205 /* Nothing found - nothing else to search */
1206 return FALSE;
1207}
1208
1221CODE_SEG("INIT")
1222VOID
1223NTAPI
1225 _In_ PHHIVE Hive,
1226 _Inout_ PLIST_ENTRY DriverListHead)
1227{
1229 PBOOT_DRIVER_NODE DriverNode;
1230
1231 /* Loop through the list and remove each driver node */
1232 while (!IsListEmpty(DriverListHead))
1233 {
1234 /* Get the driver node */
1235 Entry = RemoveHeadList(DriverListHead);
1236 DriverNode = CONTAINING_RECORD(Entry,
1238 ListEntry.Link);
1239
1240 /* Free any allocated string buffers, then the node */
1241 if (DriverNode->ListEntry.RegistryPath.Buffer)
1242 {
1243 Hive->Free(DriverNode->ListEntry.RegistryPath.Buffer,
1245 }
1246 if (DriverNode->ListEntry.FilePath.Buffer)
1247 {
1248 Hive->Free(DriverNode->ListEntry.FilePath.Buffer,
1249 DriverNode->ListEntry.FilePath.MaximumLength);
1250 }
1251 if (DriverNode->Name.Buffer)
1252 {
1253 Hive->Free(DriverNode->Name.Buffer,
1254 DriverNode->Name.MaximumLength);
1255 }
1256 Hive->Free(DriverNode, sizeof(BOOT_DRIVER_NODE));
1257 }
1258}
1259
1260/* EOF */
#define CODE_SEG(...)
PCWSTR FilePath
unsigned char BOOLEAN
struct NameRec_ * Name
Definition: cdprocs.h:460
#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
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:679
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:618
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:215
BOOLEAN NTAPI CmpResolveDriverDependencies(_Inout_ PLIST_ENTRY DriverListHead)
Removes potential circular dependencies (cycles) and sorts the driver list.
Definition: cmboot.c:1030
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:84
static BOOLEAN CmpIsSafe(_In_ PHHIVE Hive, _In_ HCELL_INDEX SafeBootCell, _In_ HCELL_INDEX DriverCell)
Definition: cmboot.c:1081
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:364
#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:828
static BOOLEAN CmpOrderGroup(_In_ PBOOT_DRIVER_NODE StartNode, _In_ PBOOT_DRIVER_NODE EndNode)
Definition: cmboot.c:956
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:902
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:1224
ULONG InitSafeBootMode
Definition: init.c:71
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:457
#define TAG_CM
Definition: cmlib.h:212
#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 wcsrchr
Definition: compat.h:16
DRIVER_INITIALIZE DriverEntry
Definition: condrv.c:21
#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:25
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
#define REG_SZ
Definition: layer.c:22
#define ASSERT(a)
Definition: mode.c:44
#define _Out_opt_
Definition: ms_sal.h:346
#define _Inout_
Definition: ms_sal.h:378
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
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:1501
#define REG_EXPAND_SZ
Definition: nt_native.h:1494
#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
#define L(x)
Definition: ntvdm.h:50
unsigned short USHORT
Definition: pedump.c:61
#define REG_DWORD
Definition: sdbapi.c:596
base of all file and directory entries
Definition: entries.h:83
Definition: arc.h:246
LIST_ENTRY Link
Definition: arc.h:247
UNICODE_STRING RegistryPath
Definition: arc.h:249
UNICODE_STRING FilePath
Definition: arc.h:248
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
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
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:30
@ NormalError
Definition: cmtypes.h:1005
#define SERVICE_ERROR_CRITICAL
Definition: cmtypes.h:984
enum _CM_SERVICE_LOAD_TYPE SERVICE_LOAD_TYPE
__wchar_t WCHAR
Definition: xmlstorage.h:180