2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/config/cmsysini.c
5 * PURPOSE: Configuration Manager - System Initialization Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES *******************************************************************/
16 POBJECT_TYPE CmpKeyObjectType
;
17 PCMHIVE CmiVolatileHive
;
18 LIST_ENTRY CmpHiveListHead
;
19 ERESOURCE CmpRegistryLock
;
20 KGUARDED_MUTEX CmpSelfHealQueueLock
;
21 LIST_ENTRY CmpSelfHealQueueListHead
;
22 KEVENT CmpLoadWorkerEvent
;
23 LONG CmpLoadWorkerIncrement
;
24 PEPROCESS CmpSystemProcess
;
25 BOOLEAN HvShutdownComplete
;
26 PVOID CmpRegistryLockCallerCaller
, CmpRegistryLockCaller
;
27 BOOLEAN CmpFlushOnLockRelease
;
28 BOOLEAN CmpSpecialBootCondition
;
30 BOOLEAN CmpWasSetupBoot
;
31 BOOLEAN CmpProfileLoaded
;
32 ULONG CmpTraceLevel
= 0;
34 extern LONG CmpFlushStarveWriters
;
35 extern BOOLEAN CmFirstTime
;
37 /* FUNCTIONS ******************************************************************/
42 _In_z_ PWSTR LinkKeyName
,
43 _In_z_ PWSTR TargetKeyName
)
45 OBJECT_ATTRIBUTES ObjectAttributes
;
46 UNICODE_STRING LinkKeyName_U
;
47 HANDLE TargetKeyHandle
;
52 /* Initialize the object attributes */
53 RtlInitUnicodeString(&LinkKeyName_U
, LinkKeyName
);
54 InitializeObjectAttributes(&ObjectAttributes
,
56 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
60 /* Create the link key */
61 Status
= ZwCreateKey(&TargetKeyHandle
,
66 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
68 if (!NT_SUCCESS(Status
))
70 DPRINT1("CM: CmpLinkKeyToHive: couldn't create %S Status = 0x%lx\n",
75 /* Check if the new key was actually created */
76 if (Disposition
!= REG_CREATED_NEW_KEY
)
78 DPRINT1("CM: CmpLinkKeyToHive: %S already exists!\n", LinkKeyName
);
79 ZwClose(TargetKeyHandle
);
83 /* Set the target key name as link target */
84 Status
= ZwSetValueKey(TargetKeyHandle
,
85 &CmSymbolicLinkValueName
,
89 wcslen(TargetKeyName
) * sizeof(WCHAR
));
91 /* Close the link key handle */
92 ObCloseHandle(TargetKeyHandle
, KernelMode
);
94 if (!NT_SUCCESS(Status
))
96 DPRINT1("CM: CmpLinkKeyToHive: couldn't create symbolic link for %S\n",
106 CmpDeleteKeyObject(PVOID DeletedObject
)
108 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)DeletedObject
;
109 PCM_KEY_CONTROL_BLOCK Kcb
;
110 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo
;
111 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
115 /* First off, prepare the handle close information callback */
116 PostOperationInfo
.Object
= KeyBody
;
117 KeyHandleCloseInfo
.Object
= KeyBody
;
118 Status
= CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose
,
119 &KeyHandleCloseInfo
);
120 if (!NT_SUCCESS(Status
))
122 /* If we failed, notify the post routine */
123 PostOperationInfo
.Status
= Status
;
124 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
128 /* Acquire hive lock */
131 /* Make sure this is a valid key body */
132 if (KeyBody
->Type
== CM_KEY_BODY_TYPE
)
135 Kcb
= KeyBody
->KeyControlBlock
;
139 DelistKeyBodyFromKCB(KeyBody
, FALSE
);
141 /* Dereference the KCB */
142 CmpDelayDerefKeyControlBlock(Kcb
);
146 /* Release the registry lock */
149 /* Do the post callback */
150 PostOperationInfo
.Status
= STATUS_SUCCESS
;
151 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
156 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL
,
158 IN ACCESS_MASK GrantedAccess
,
159 IN ULONG ProcessHandleCount
,
160 IN ULONG SystemHandleCount
)
162 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)Object
;
165 /* Don't do anything if we're not the last handle */
166 if (SystemHandleCount
> 1) return;
168 /* Make sure we're a valid key body */
169 if (KeyBody
->Type
== CM_KEY_BODY_TYPE
)
171 /* Don't do anything if we don't have a notify block */
172 if (!KeyBody
->NotifyBlock
) return;
174 /* This shouldn't happen yet */
181 CmpQueryKeyName(IN PVOID ObjectBody
,
183 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
185 OUT PULONG ReturnLength
,
186 IN KPROCESSOR_MODE PreviousMode
)
188 PUNICODE_STRING KeyName
;
190 NTSTATUS Status
= STATUS_SUCCESS
;
191 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)ObjectBody
;
192 PCM_KEY_CONTROL_BLOCK Kcb
= KeyBody
->KeyControlBlock
;
194 /* Acquire hive lock */
197 /* Lock KCB shared */
198 CmpAcquireKcbLockShared(Kcb
);
200 /* Check if it's a deleted block */
203 /* Release the locks */
204 CmpReleaseKcbLock(Kcb
);
207 /* Let the caller know it's deleted */
208 return STATUS_KEY_DELETED
;
212 KeyName
= CmpConstructName(Kcb
);
214 /* Release the locks */
215 CmpReleaseKcbLock(Kcb
);
218 /* Check if we got the name */
219 if (!KeyName
) return STATUS_INSUFFICIENT_RESOURCES
;
221 /* Set the returned length */
222 *ReturnLength
= KeyName
->Length
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
);
224 /* Calculate amount of bytes to copy into the buffer */
225 BytesToCopy
= KeyName
->Length
+ sizeof(WCHAR
);
227 /* Check if the provided buffer is too small to fit even anything */
228 if ((Length
<= sizeof(OBJECT_NAME_INFORMATION
)) ||
229 ((Length
< (*ReturnLength
)) && (BytesToCopy
< sizeof(WCHAR
))))
231 /* Free the buffer allocated by CmpConstructName */
232 ExFreePoolWithTag(KeyName
, TAG_CM
);
234 /* Return buffer length failure without writing anything there because nothing fits */
235 return STATUS_INFO_LENGTH_MISMATCH
;
238 /* Check if the provided buffer can be partially written */
239 if (Length
< (*ReturnLength
))
241 /* Yes, indicate so in the return status */
242 Status
= STATUS_INFO_LENGTH_MISMATCH
;
244 /* Calculate amount of bytes which the provided buffer could handle */
245 BytesToCopy
= Length
- sizeof(OBJECT_NAME_INFORMATION
);
248 /* Remove the null termination character from the size */
249 BytesToCopy
-= sizeof(WCHAR
);
251 /* Fill in the result */
254 /* Return data to user */
255 ObjectNameInfo
->Name
.Buffer
= (PWCHAR
)(ObjectNameInfo
+ 1);
256 ObjectNameInfo
->Name
.MaximumLength
= KeyName
->Length
;
257 ObjectNameInfo
->Name
.Length
= KeyName
->Length
;
259 /* Copy string content*/
260 RtlCopyMemory(ObjectNameInfo
->Name
.Buffer
,
264 /* Null terminate it */
265 ObjectNameInfo
->Name
.Buffer
[BytesToCopy
/ sizeof(WCHAR
)] = 0;
267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
270 Status
= _SEH2_GetExceptionCode();
274 /* Free the buffer allocated by CmpConstructName */
275 ExFreePoolWithTag(KeyName
, TAG_CM
);
283 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName
,
289 ULONG HiveDisposition
, LogDisposition
;
290 HANDLE FileHandle
= NULL
, LogHandle
= NULL
;
292 ULONG Operation
, FileType
;
299 /* Open or create the hive files */
300 Status
= CmpOpenHiveFiles(HiveName
,
310 if (!NT_SUCCESS(Status
)) return Status
;
312 /* Check if we have a log handle */
313 FileType
= (LogHandle
) ? HFILE_TYPE_LOG
: HFILE_TYPE_PRIMARY
;
315 /* Check if we created or opened the hive */
316 if (HiveDisposition
== FILE_CREATED
)
318 /* Do a create operation */
319 Operation
= HINIT_CREATE
;
324 /* Open it as a file */
325 Operation
= HINIT_FILE
;
329 /* Check if we're sharing hives */
330 if (CmpShareSystemHives
)
332 /* Then force using the primary hive */
333 FileType
= HFILE_TYPE_PRIMARY
;
336 /* Get rid of the log handle */
342 /* Check if we're too late */
343 if (HvShutdownComplete
)
347 if (LogHandle
) ZwClose(LogHandle
);
348 return STATUS_TOO_LATE
;
351 /* Initialize the hive */
352 Status
= CmpInitializeHive((PCMHIVE
*)&NewHive
,
362 if (!NT_SUCCESS(Status
))
366 if (LogHandle
) ZwClose(LogHandle
);
370 /* Success, return hive */
373 /* HACK: ROS: Init root key cell and prepare the hive */
374 if (Operation
== HINIT_CREATE
) CmCreateRootNode(&NewHive
->Hive
, L
"");
376 /* Duplicate the hive name */
377 NewHive
->FileFullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
380 if (NewHive
->FileFullPath
.Buffer
)
382 /* Copy the string */
383 RtlCopyMemory(NewHive
->FileFullPath
.Buffer
,
386 NewHive
->FileFullPath
.Length
= HiveName
->Length
;
387 NewHive
->FileFullPath
.MaximumLength
= HiveName
->MaximumLength
;
391 return STATUS_SUCCESS
;
397 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
399 OBJECT_ATTRIBUTES ObjectAttributes
;
400 UNICODE_STRING KeyName
, ValueName
= { 0, 0, NULL
};
401 HANDLE KeyHandle
= NULL
;
403 ASSERT(LoaderBlock
!= NULL
);
405 /* Setup attributes for loader options */
406 RtlInitUnicodeString(&KeyName
,
407 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
409 InitializeObjectAttributes(&ObjectAttributes
,
411 OBJ_CASE_INSENSITIVE
,
414 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
415 if (!NT_SUCCESS(Status
)) goto Quickie
;
417 /* Key opened, now write to the key */
418 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
419 Status
= NtSetValueKey(KeyHandle
,
423 CmpLoadOptions
.Buffer
,
424 CmpLoadOptions
.Length
);
425 if (!NT_SUCCESS(Status
)) goto Quickie
;
427 /* Setup value name for system boot device in ARC format */
428 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
429 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->ArcBootDeviceName
);
430 Status
= NtSetValueKey(KeyHandle
,
438 /* Free the buffers */
439 RtlFreeUnicodeString(&ValueName
);
441 /* Close the key and return */
442 if (KeyHandle
) NtClose(KeyHandle
);
444 /* Return the status */
445 return (ExpInTextModeSetup
? STATUS_SUCCESS
: Status
);
451 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
453 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
454 UNICODE_STRING SelectName
=
455 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
456 UNICODE_STRING KeyName
;
457 OBJECT_ATTRIBUTES ObjectAttributes
;
458 CHAR ValueInfoBuffer
[128];
459 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
461 WCHAR UnicodeBuffer
[128];
462 HANDLE SelectHandle
, KeyHandle
, ConfigHandle
= NULL
, ProfileHandle
= NULL
;
463 HANDLE ParentHandle
= NULL
;
464 ULONG ControlSet
, HwProfile
;
465 ANSI_STRING TempString
;
467 ULONG ResultLength
, Disposition
;
468 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
471 /* Open the select key */
472 InitializeObjectAttributes(&ObjectAttributes
,
474 OBJ_CASE_INSENSITIVE
,
477 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
478 if (!NT_SUCCESS(Status
))
480 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
481 if (!LoaderBlock
->RegistryBase
)
483 /* Build the ControlSet001 key */
484 RtlInitUnicodeString(&KeyName
,
485 L
"\\Registry\\Machine\\System\\ControlSet001");
486 InitializeObjectAttributes(&ObjectAttributes
,
488 OBJ_CASE_INSENSITIVE
,
491 Status
= NtCreateKey(&KeyHandle
,
498 if (!NT_SUCCESS(Status
)) return Status
;
500 /* Don't need the handle */
503 /* Use hard-coded setting */
508 /* Fail for real boots */
512 /* Open the current value */
513 RtlInitUnicodeString(&KeyName
, L
"Current");
514 Status
= NtQueryValueKey(SelectHandle
,
516 KeyValueFullInformation
,
518 sizeof(ValueInfoBuffer
),
520 NtClose(SelectHandle
);
521 if (!NT_SUCCESS(Status
)) return Status
;
523 /* Get the actual value pointer, and get the control set ID */
524 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
525 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
527 /* Create the current control set key */
529 RtlInitUnicodeString(&KeyName
,
530 L
"\\Registry\\Machine\\System\\CurrentControlSet");
531 InitializeObjectAttributes(&ObjectAttributes
,
533 OBJ_CASE_INSENSITIVE
,
536 Status
= NtCreateKey(&KeyHandle
,
541 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
543 if (!NT_SUCCESS(Status
)) return Status
;
546 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
548 /* Initialize the symbolic link name */
550 "\\Registry\\Machine\\System\\ControlSet%03ld",
552 RtlInitAnsiString(&TempString
, Buffer
);
554 /* Create a Unicode string out of it */
555 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
556 KeyName
.Buffer
= UnicodeBuffer
;
557 Status
= RtlAnsiStringToUnicodeString(&KeyName
, &TempString
, FALSE
);
560 Status
= NtSetValueKey(KeyHandle
,
561 &CmSymbolicLinkValueName
,
566 if (!NT_SUCCESS(Status
)) return Status
;
568 /* Get the configuration database key */
569 InitializeObjectAttributes(&ObjectAttributes
,
571 OBJ_CASE_INSENSITIVE
,
574 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
577 /* Check if we don't have one */
578 if (!NT_SUCCESS(Status
))
580 /* Cleanup and exit */
585 /* Now get the current config */
586 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
587 Status
= NtQueryValueKey(ConfigHandle
,
589 KeyValueFullInformation
,
591 sizeof(ValueInfoBuffer
),
594 /* Set pointer to buffer */
595 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
597 /* Check if we failed or got a non DWORD-value */
598 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
)) goto Cleanup
;
600 /* Get the hadware profile */
601 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
603 /* Open the hardware profile key */
604 RtlInitUnicodeString(&KeyName
,
605 L
"\\Registry\\Machine\\System\\CurrentControlSet"
606 L
"\\Hardware Profiles");
607 InitializeObjectAttributes(&ObjectAttributes
,
609 OBJ_CASE_INSENSITIVE
,
612 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
613 if (!NT_SUCCESS(Status
))
615 /* Exit and clean up */
620 /* Build the profile name */
621 sprintf(Buffer
, "%04ld", HwProfile
);
622 RtlInitAnsiString(&TempString
, Buffer
);
624 /* Convert it to Unicode */
625 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
626 KeyName
.Buffer
= UnicodeBuffer
;
627 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
630 ASSERT(Status
== STATUS_SUCCESS
);
632 /* Open the associated key */
633 InitializeObjectAttributes(&ObjectAttributes
,
635 OBJ_CASE_INSENSITIVE
,
638 Status
= NtOpenKey(&ProfileHandle
,
639 KEY_READ
| KEY_WRITE
,
641 if (!NT_SUCCESS (Status
))
643 /* Cleanup and exit */
648 /* Check if we have a loader block extension */
649 LoaderExtension
= LoaderBlock
->Extension
;
652 DPRINT("ReactOS doesn't support NTLDR Profiles yet!\n");
655 /* Create the current hardware profile key */
656 RtlInitUnicodeString(&KeyName
,
657 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
658 L
"Hardware Profiles\\Current");
659 InitializeObjectAttributes(&ObjectAttributes
,
661 OBJ_CASE_INSENSITIVE
,
664 Status
= NtCreateKey(&KeyHandle
,
669 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
671 if (NT_SUCCESS(Status
))
674 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
676 /* Create the profile name */
678 "\\Registry\\Machine\\System\\CurrentControlSet\\"
679 "Hardware Profiles\\%04ld",
681 RtlInitAnsiString(&TempString
, Buffer
);
683 /* Convert it to Unicode */
684 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
685 KeyName
.Buffer
= UnicodeBuffer
;
686 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
689 ASSERT(STATUS_SUCCESS
== Status
);
692 Status
= NtSetValueKey(KeyHandle
,
693 &CmSymbolicLinkValueName
,
701 /* Close every opened handle */
703 if (ConfigHandle
) NtClose(ConfigHandle
);
704 if (ProfileHandle
) NtClose(ProfileHandle
);
705 if (ParentHandle
) NtClose(ParentHandle
);
708 return STATUS_SUCCESS
;
713 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName
,
714 IN HANDLE RootDirectory
,
715 IN PCMHIVE RegistryHive
,
717 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
719 OBJECT_ATTRIBUTES ObjectAttributes
;
721 CM_PARSE_CONTEXT ParseContext
= {0};
723 PCM_KEY_BODY KeyBody
;
726 /* Setup the object attributes */
727 InitializeObjectAttributes(&ObjectAttributes
,
729 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
733 /* Setup the parse context */
734 ParseContext
.CreateLink
= TRUE
;
735 ParseContext
.CreateOperation
= TRUE
;
736 ParseContext
.ChildHive
.KeyHive
= &RegistryHive
->Hive
;
738 /* Check if we have a root keycell or if we need to create it */
742 ParseContext
.ChildHive
.KeyCell
= HCELL_NIL
;
747 ParseContext
.ChildHive
.KeyCell
= RegistryHive
->Hive
.BaseBlock
->RootCell
;
750 /* Create the link node */
751 Status
= ObOpenObjectByName(&ObjectAttributes
,
755 KEY_READ
| KEY_WRITE
,
756 (PVOID
)&ParseContext
,
758 if (!NT_SUCCESS(Status
)) return Status
;
760 /* Mark the hive as clean */
761 RegistryHive
->Hive
.DirtyFlag
= FALSE
;
763 /* ReactOS Hack: Keep alive */
764 Status
= ObReferenceObjectByHandle(KeyHandle
,
770 ASSERT(NT_SUCCESS(Status
));
772 /* Close the extra handle */
774 return STATUS_SUCCESS
;
780 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
783 ANSI_STRING LoadString
;
788 UNICODE_STRING KeyName
;
789 PCMHIVE SystemHive
= NULL
;
790 UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
791 PSECURITY_DESCRIPTOR SecurityDescriptor
;
794 /* Setup the ansi string */
795 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
797 /* Allocate the unicode buffer */
798 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
799 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
803 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
806 /* Setup the unicode string */
807 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, (USHORT
)Length
);
809 /* Add the load options and null-terminate */
810 RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
811 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
812 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
814 /* Get the System Hive base address */
815 HiveBase
= LoaderBlock
->RegistryBase
;
819 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
829 if (!NT_SUCCESS(Status
)) return FALSE
;
831 /* Set the hive filename */
832 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
833 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
835 /* We imported, no need to create a new hive */
838 /* Manually set the hive as volatile, if in Live CD mode */
839 if (CmpShareSystemHives
) SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
844 Status
= CmpInitializeHive(&SystemHive
,
854 if (!NT_SUCCESS(Status
)) return FALSE
;
856 /* Set the hive filename */
857 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
858 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
860 /* Tell CmpLinkHiveToMaster to allocate a hive */
864 /* Save the boot type */
865 CmpBootType
= SystemHive
->Hive
.BaseBlock
->BootType
;
867 /* Are we in self-healing mode? */
870 /* Disable self-healing internally and check if boot type wanted it */
874 /* We're disabled, so bugcheck */
875 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
,
878 (ULONG_PTR
)SystemHive
,
883 /* Create the default security descriptor */
884 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
886 /* Attach it to the system key */
887 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM");
888 Status
= CmpLinkHiveToMaster(&KeyName
,
894 /* Free the security descriptor */
895 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
896 if (!NT_SUCCESS(Status
)) return FALSE
;
898 /* Add the hive to the hive list */
899 CmpMachineHiveList
[3].CmHive
= (PCMHIVE
)SystemHive
;
908 CmpCreateObjectTypes(VOID
)
910 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
912 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
918 /* Initialize the Key object type */
919 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
920 RtlInitUnicodeString(&Name
, L
"Key");
921 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
922 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
923 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
924 ObjectTypeInitializer
.PoolType
= PagedPool
;
925 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
926 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
927 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
928 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
929 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
930 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
931 ObjectTypeInitializer
.CloseProcedure
= CmpCloseKeyObject
;
932 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
933 ObjectTypeInitializer
.InvalidAttributes
= OBJ_EXCLUSIVE
| OBJ_PERMANENT
;
936 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
942 CmpCreateRootNode(IN PHHIVE Hive
,
944 OUT PHCELL_INDEX Index
)
946 UNICODE_STRING KeyName
;
947 PCM_KEY_NODE KeyCell
;
948 LARGE_INTEGER SystemTime
;
951 /* Initialize the node name and allocate it */
952 RtlInitUnicodeString(&KeyName
, Name
);
953 *Index
= HvAllocateCell(Hive
,
954 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
955 CmpNameSize(Hive
, &KeyName
),
958 if (*Index
== HCELL_NIL
) return FALSE
;
960 /* Set the cell index and get the data */
961 Hive
->BaseBlock
->RootCell
= *Index
;
962 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
963 if (!KeyCell
) return FALSE
;
966 KeyCell
->Signature
= (USHORT
)CM_KEY_NODE_SIGNATURE
;
967 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
968 KeQuerySystemTime(&SystemTime
);
969 KeyCell
->LastWriteTime
= SystemTime
;
970 KeyCell
->Parent
= HCELL_NIL
;
971 KeyCell
->SubKeyCounts
[Stable
] = 0;
972 KeyCell
->SubKeyCounts
[Volatile
] = 0;
973 KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
974 KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
975 KeyCell
->ValueList
.Count
= 0;
976 KeyCell
->ValueList
.List
= HCELL_NIL
;
977 KeyCell
->Security
= HCELL_NIL
;
978 KeyCell
->Class
= HCELL_NIL
;
979 KeyCell
->ClassLength
= 0;
980 KeyCell
->MaxNameLen
= 0;
981 KeyCell
->MaxClassLen
= 0;
982 KeyCell
->MaxValueNameLen
= 0;
983 KeyCell
->MaxValueDataLen
= 0;
985 /* Copy the name (this will also set the length) */
986 KeyCell
->NameLength
= CmpCopyName(Hive
, (PWCHAR
)KeyCell
->Name
, &KeyName
);
988 /* Check if the name was compressed */
989 if (KeyCell
->NameLength
< KeyName
.Length
)
992 KeyCell
->Flags
|= KEY_COMP_NAME
;
996 HvReleaseCell(Hive
, *Index
);
1003 CmpCreateRegistryRoot(VOID
)
1005 UNICODE_STRING KeyName
;
1006 OBJECT_ATTRIBUTES ObjectAttributes
;
1007 PCM_KEY_BODY RootKey
;
1008 HCELL_INDEX RootIndex
;
1010 PCM_KEY_NODE KeyCell
;
1011 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1012 PCM_KEY_CONTROL_BLOCK Kcb
;
1015 /* Setup the root node */
1016 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
1022 /* Create '\Registry' key. */
1023 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
1024 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1025 InitializeObjectAttributes(&ObjectAttributes
,
1027 OBJ_CASE_INSENSITIVE
,
1030 Status
= ObCreateObject(KernelMode
,
1035 sizeof(CM_KEY_BODY
),
1039 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1040 if (!NT_SUCCESS(Status
)) return FALSE
;
1042 /* Sanity check, and get the key cell */
1043 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
1044 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
1045 if (!KeyCell
) return FALSE
;
1047 /* Create the KCB */
1048 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
1049 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
1057 ObDereferenceObject(RootKey
);
1061 /* Initialize the object */
1062 RootKey
->KeyControlBlock
= Kcb
;
1063 RootKey
->Type
= CM_KEY_BODY_TYPE
;
1064 RootKey
->NotifyBlock
= NULL
;
1065 RootKey
->ProcessID
= PsGetCurrentProcessId();
1068 EnlistKeyBodyWithKCB(RootKey
, 0);
1070 /* Insert the key into the namespace */
1071 Status
= ObInsertObject(RootKey
,
1076 &CmpRegistryRootHandle
);
1077 if (!NT_SUCCESS(Status
))
1079 ObDereferenceObject(RootKey
);
1083 /* Reference the key again so that we never lose it */
1084 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
1090 if (!NT_SUCCESS(Status
))
1092 ObDereferenceObject(RootKey
);
1096 /* Completely sucessful */
1102 CmpGetRegistryPath(IN PWCHAR ConfigPath
)
1104 OBJECT_ATTRIBUTES ObjectAttributes
;
1107 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1108 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1109 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1110 ULONG BufferSize
, ResultSize
;
1112 /* Check if we are booted in setup */
1113 if (ExpInTextModeSetup
)
1115 /* Setup the object attributes */
1116 InitializeObjectAttributes(&ObjectAttributes
,
1118 OBJ_CASE_INSENSITIVE
,
1122 Status
= ZwOpenKey(&KeyHandle
,
1125 if (!NT_SUCCESS(Status
)) return Status
;
1127 /* Allocate the buffer */
1128 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1129 ValueInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_CM
);
1134 return STATUS_INSUFFICIENT_RESOURCES
;
1137 /* Query the value */
1138 Status
= ZwQueryValueKey(KeyHandle
,
1140 KeyValuePartialInformation
,
1145 if (!NT_SUCCESS(Status
))
1148 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1152 /* Copy the config path and null-terminate it */
1153 RtlCopyMemory(ConfigPath
,
1155 ValueInfo
->DataLength
);
1156 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1157 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1161 /* Just use default path */
1162 wcscpy(ConfigPath
, L
"\\SystemRoot");
1165 /* Add registry path */
1166 wcscat(ConfigPath
, L
"\\System32\\Config\\");
1169 return STATUS_SUCCESS
;
1174 CmpLoadHiveThread(IN PVOID StartContext
)
1176 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1177 UNICODE_STRING TempName
, FileName
, RegName
;
1178 ULONG i
, ErrorResponse
, WorkerCount
, Length
;
1181 ULONG PrimaryDisposition
, SecondaryDisposition
, ClusterSize
;
1183 HANDLE PrimaryHandle
= NULL
, LogHandle
= NULL
;
1184 NTSTATUS Status
= STATUS_SUCCESS
;
1185 PVOID ErrorParameters
;
1188 /* Get the hive index, make sure it makes sense */
1189 i
= PtrToUlong(StartContext
);
1190 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1192 /* We were started */
1193 CmpMachineHiveList
[i
].ThreadStarted
= TRUE
;
1195 /* Build the file name and registry name strings */
1196 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1197 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1199 /* Now build the system root path */
1200 CmpGetRegistryPath(ConfigPath
);
1201 RtlInitUnicodeString(&TempName
, ConfigPath
);
1202 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1203 FileStart
= FileName
.Length
;
1205 /* And build the registry root path */
1206 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1207 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1208 //RegStart = RegName.Length;
1210 /* Build the base name */
1211 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1212 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1214 /* Check if this is a child of the root */
1215 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1217 /* Then setup the whole name */
1218 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1219 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1222 /* Now add the rest of the file name */
1223 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1224 FileName
.Length
= FileStart
;
1225 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1226 if (!CmpMachineHiveList
[i
].CmHive
)
1228 /* We need to allocate a new hive structure */
1229 CmpMachineHiveList
[i
].Allocate
= TRUE
;
1231 /* Load the hive file */
1232 Status
= CmpInitHiveFromFile(&FileName
,
1233 CmpMachineHiveList
[i
].HHiveFlags
,
1235 &CmpMachineHiveList
[i
].Allocate
,
1237 if (!(NT_SUCCESS(Status
)) ||
1238 (!(CmHive
->FileHandles
[HFILE_TYPE_LOG
]) && !(CmpMiniNTBoot
))) // HACK
1240 /* We failed or couldn't get a log file, raise a hard error */
1241 ErrorParameters
= &FileName
;
1242 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1245 (PULONG_PTR
)&ErrorParameters
,
1250 /* Set the hive flags and newly allocated hive pointer */
1251 CmHive
->Flags
= CmpMachineHiveList
[i
].CmHiveFlags
;
1252 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1256 /* We already have a hive, is it volatile? */
1257 CmHive
= CmpMachineHiveList
[i
].CmHive
;
1258 if (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
1260 /* It's now, open the hive file and log */
1261 Status
= CmpOpenHiveFiles(&FileName
,
1265 &PrimaryDisposition
,
1266 &SecondaryDisposition
,
1271 if (!(NT_SUCCESS(Status
)) || !(LogHandle
))
1273 /* Couldn't open the hive or its log file, raise a hard error */
1274 ErrorParameters
= &FileName
;
1275 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1278 (PULONG_PTR
)&ErrorParameters
,
1282 /* And bugcheck for posterity's sake */
1283 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 0, i
, Status
);
1286 /* Save the file handles. This should remove our sync hacks */
1287 CmHive
->FileHandles
[HFILE_TYPE_LOG
] = LogHandle
;
1288 CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = PrimaryHandle
;
1290 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1291 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1292 CmHive
->Hive
.HiveFlags
&= ~HIVE_NOLAZYFLUSH
;
1294 /* Get the real size of the hive */
1295 Length
= CmHive
->Hive
.Storage
[Stable
].Length
+ HBLOCK_SIZE
;
1297 /* Check if the cluster size doesn't match */
1298 if (CmHive
->Hive
.Cluster
!= ClusterSize
) ASSERT(FALSE
);
1300 /* Set the file size */
1301 DPRINT("FIXME: Should set file size: %lx\n", Length
);
1302 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1304 /* This shouldn't fail */
1308 /* Another thing we don't support is NTLDR-recovery */
1309 if (CmHive
->Hive
.BaseBlock
->BootRecover
) ASSERT(FALSE
);
1311 /* Finally, set our allocated hive to the same hive we've had */
1312 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1313 ASSERT(CmpMachineHiveList
[i
].CmHive
== CmpMachineHiveList
[i
].CmHive2
);
1318 CmpMachineHiveList
[i
].ThreadFinished
= TRUE
;
1320 /* Check if we're the last worker */
1321 WorkerCount
= InterlockedIncrement(&CmpLoadWorkerIncrement
);
1322 if (WorkerCount
== CM_NUMBER_OF_MACHINE_HIVES
)
1324 /* Signal the event */
1325 KeSetEvent(&CmpLoadWorkerEvent
, 0, FALSE
);
1328 /* Kill the thread */
1329 PsTerminateSystemThread(Status
);
1334 CmpInitializeHiveList(IN USHORT Flag
)
1336 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1337 UNICODE_STRING TempName
, FileName
, RegName
;
1342 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1345 /* Allow writing for now */
1348 /* Build the file name and registry name strings */
1349 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1350 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1352 /* Now build the system root path */
1353 CmpGetRegistryPath(ConfigPath
);
1354 RtlInitUnicodeString(&TempName
, ConfigPath
);
1355 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1357 /* And build the registry root path */
1358 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1359 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1360 RegStart
= RegName
.Length
;
1362 /* Setup the event to synchronize workers */
1363 KeInitializeEvent(&CmpLoadWorkerEvent
, SynchronizationEvent
, FALSE
);
1365 /* Enter special boot condition */
1366 CmpSpecialBootCondition
= TRUE
;
1368 /* Create the SD for the root hives */
1369 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1371 /* Loop every hive we care about */
1372 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1374 /* Make sure the list is setup */
1375 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1377 /* Create a thread to handle this hive */
1378 Status
= PsCreateSystemThread(&Thread
,
1385 if (NT_SUCCESS(Status
))
1387 /* We don't care about the handle -- the thread self-terminates */
1392 /* Can't imagine this happening */
1393 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 3, i
, Status
);
1397 /* Make sure we've reached the end of the list */
1398 ASSERT(CmpMachineHiveList
[i
].Name
== NULL
);
1400 /* Wait for hive loading to finish */
1401 KeWaitForSingleObject(&CmpLoadWorkerEvent
,
1407 /* Exit the special boot condition and make sure all workers completed */
1408 CmpSpecialBootCondition
= FALSE
;
1409 ASSERT(CmpLoadWorkerIncrement
== CM_NUMBER_OF_MACHINE_HIVES
);
1411 /* Loop hives again */
1412 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1414 /* Make sure the thread ran and finished */
1415 ASSERT(CmpMachineHiveList
[i
].ThreadFinished
== TRUE
);
1416 ASSERT(CmpMachineHiveList
[i
].ThreadStarted
== TRUE
);
1418 /* Check if this was a new hive */
1419 if (!CmpMachineHiveList
[i
].CmHive
)
1421 /* Make sure we allocated something */
1422 ASSERT(CmpMachineHiveList
[i
].CmHive2
!= NULL
);
1424 /* Build the base name */
1425 RegName
.Length
= RegStart
;
1426 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1427 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1429 /* Check if this is a child of the root */
1430 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1432 /* Then setup the whole name */
1433 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1434 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1437 /* Now link the hive to its master */
1438 Status
= CmpLinkHiveToMaster(&RegName
,
1440 CmpMachineHiveList
[i
].CmHive2
,
1441 CmpMachineHiveList
[i
].Allocate
,
1442 SecurityDescriptor
);
1443 if (Status
!= STATUS_SUCCESS
)
1445 /* Linking needs to work */
1446 KeBugCheckEx(CONFIG_LIST_FAILED
, 11, Status
, i
, (ULONG_PTR
)&RegName
);
1449 /* Check if we had to allocate a new hive */
1450 if (CmpMachineHiveList
[i
].Allocate
)
1452 /* Sync the new hive */
1453 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1457 /* Check if we created a new hive */
1458 if (CmpMachineHiveList
[i
].CmHive2
)
1460 /* Add to HiveList key */
1461 CmpAddToHiveFileList(CmpMachineHiveList
[i
].CmHive2
);
1465 /* Get rid of the SD */
1466 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1468 /* Link SECURITY to SAM */
1469 CmpLinkKeyToHive(L
"\\Registry\\Machine\\Security\\SAM",
1470 L
"\\Registry\\Machine\\SAM\\SAM");
1472 /* Link S-1-5-18 to .Default */
1473 CmpLinkKeyToHive(L
"\\Registry\\User\\S-1-5-18",
1474 L
"\\Registry\\User\\.Default");
1482 OBJECT_ATTRIBUTES ObjectAttributes
;
1483 UNICODE_STRING KeyName
;
1486 PCMHIVE HardwareHive
;
1487 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1490 /* Check if this is PE-boot */
1491 if (InitIsWinPEMode
)
1493 /* Set registry to PE mode */
1494 CmpMiniNTBoot
= TRUE
;
1495 CmpShareSystemHives
= TRUE
;
1498 /* Initialize the hive list and lock */
1499 InitializeListHead(&CmpHiveListHead
);
1500 ExInitializePushLock(&CmpHiveListHeadLock
);
1501 ExInitializePushLock(&CmpLoadHiveLock
);
1503 /* Initialize registry lock */
1504 ExInitializeResourceLite(&CmpRegistryLock
);
1506 /* Initialize the cache */
1507 CmpInitializeCache();
1509 /* Initialize allocation and delayed dereferencing */
1510 CmpInitCmPrivateAlloc();
1511 CmpInitCmPrivateDelayAlloc();
1512 CmpInitDelayDerefKCBEngine();
1514 /* Initialize callbacks */
1517 /* Initialize self healing */
1518 KeInitializeGuardedMutex(&CmpSelfHealQueueLock
);
1519 InitializeListHead(&CmpSelfHealQueueListHead
);
1521 /* Save the current process and lock the registry */
1522 CmpSystemProcess
= PsGetCurrentProcess();
1524 /* Create the key object types */
1525 Status
= CmpCreateObjectTypes();
1526 if (!NT_SUCCESS(Status
))
1529 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 1, Status
, 0);
1532 /* Build the master hive */
1533 Status
= CmpInitializeHive((PCMHIVE
*)&CmiVolatileHive
,
1543 if (!NT_SUCCESS(Status
))
1546 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 2, Status
, 0);
1549 /* Create the \REGISTRY key node */
1550 if (!CmpCreateRegistryRoot())
1553 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 3, 0, 0);
1556 /* Create the default security descriptor */
1557 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1559 /* Create '\Registry\Machine' key. */
1560 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE");
1561 InitializeObjectAttributes(&ObjectAttributes
,
1563 OBJ_CASE_INSENSITIVE
,
1565 SecurityDescriptor
);
1566 Status
= NtCreateKey(&KeyHandle
,
1567 KEY_READ
| KEY_WRITE
,
1573 if (!NT_SUCCESS(Status
))
1576 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 5, Status
, 0);
1579 /* Close the handle */
1582 /* Create '\Registry\User' key. */
1583 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\USER");
1584 InitializeObjectAttributes(&ObjectAttributes
,
1586 OBJ_CASE_INSENSITIVE
,
1588 SecurityDescriptor
);
1589 Status
= NtCreateKey(&KeyHandle
,
1590 KEY_READ
| KEY_WRITE
,
1596 if (!NT_SUCCESS(Status
))
1599 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 6, Status
, 0);
1602 /* Close the handle */
1605 /* Initialize the system hive */
1606 if (!CmpInitializeSystemHive(KeLoaderBlock
))
1609 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 7, 0, 0);
1612 /* Create the 'CurrentControlSet' link. */
1613 Status
= CmpCreateControlSet(KeLoaderBlock
);
1614 if (!NT_SUCCESS(Status
))
1617 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 8, Status
, 0);
1620 /* Create the hardware hive */
1621 Status
= CmpInitializeHive((PCMHIVE
*)&HardwareHive
,
1631 if (!NT_SUCCESS(Status
))
1634 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 11, Status
, 0);
1637 /* Add the hive to the hive list */
1638 CmpMachineHiveList
[0].CmHive
= (PCMHIVE
)HardwareHive
;
1640 /* Attach it to the machine key */
1641 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE");
1642 Status
= CmpLinkHiveToMaster(&KeyName
,
1644 (PCMHIVE
)HardwareHive
,
1646 SecurityDescriptor
);
1647 if (!NT_SUCCESS(Status
))
1650 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 12, Status
, 0);
1653 /* Add to HiveList key */
1654 CmpAddToHiveFileList(HardwareHive
);
1656 /* Free the security descriptor */
1657 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1659 /* Fill out the Hardware key with the ARC Data from the Loader */
1660 Status
= CmpInitializeHardwareConfiguration(KeLoaderBlock
);
1661 if (!NT_SUCCESS(Status
))
1664 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 13, Status
, 0);
1667 /* Initialize machine-dependent information into the registry */
1668 Status
= CmpInitializeMachineDependentConfiguration(KeLoaderBlock
);
1669 if (!NT_SUCCESS(Status
))
1672 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 14, Status
, 0);
1675 /* Initialize volatile registry settings */
1676 Status
= CmpSetSystemValues(KeLoaderBlock
);
1677 if (!NT_SUCCESS(Status
))
1680 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 15, Status
, 0);
1683 /* Free the load options */
1684 ExFreePoolWithTag(CmpLoadOptions
.Buffer
, TAG_CM
);
1686 /* If we got here, all went well */
1693 CmpFreeDriverList(IN PHHIVE Hive
,
1694 IN PLIST_ENTRY DriverList
)
1696 PLIST_ENTRY NextEntry
, OldEntry
;
1697 PBOOT_DRIVER_NODE DriverNode
;
1700 /* Parse the current list */
1701 NextEntry
= DriverList
->Flink
;
1702 while (NextEntry
!= DriverList
)
1704 /* Get the driver node */
1705 DriverNode
= CONTAINING_RECORD(NextEntry
, BOOT_DRIVER_NODE
, ListEntry
.Link
);
1707 /* Get the next entry now, since we're going to free it later */
1708 OldEntry
= NextEntry
;
1709 NextEntry
= NextEntry
->Flink
;
1711 /* Was there a name? */
1712 if (DriverNode
->Name
.Buffer
)
1715 CmpFree(DriverNode
->Name
.Buffer
, DriverNode
->Name
.Length
);
1718 /* Was there a registry path? */
1719 if (DriverNode
->ListEntry
.RegistryPath
.Buffer
)
1722 CmpFree(DriverNode
->ListEntry
.RegistryPath
.Buffer
,
1723 DriverNode
->ListEntry
.RegistryPath
.MaximumLength
);
1726 /* Was there a file path? */
1727 if (DriverNode
->ListEntry
.FilePath
.Buffer
)
1730 CmpFree(DriverNode
->ListEntry
.FilePath
.Buffer
,
1731 DriverNode
->ListEntry
.FilePath
.MaximumLength
);
1734 /* Now free the node, and move on */
1735 CmpFree(OldEntry
, sizeof(BOOT_DRIVER_NODE
));
1742 CmGetSystemDriverList(VOID
)
1744 LIST_ENTRY DriverList
;
1745 OBJECT_ATTRIBUTES ObjectAttributes
;
1747 PCM_KEY_BODY KeyBody
;
1749 HCELL_INDEX RootCell
, ControlCell
;
1751 UNICODE_STRING KeyName
;
1752 PLIST_ENTRY NextEntry
;
1754 PUNICODE_STRING
* ServicePath
= NULL
;
1755 BOOLEAN Success
, AutoSelect
;
1756 PBOOT_DRIVER_LIST_ENTRY DriverEntry
;
1759 /* Initialize the driver list */
1760 InitializeListHead(&DriverList
);
1762 /* Open the system hive key */
1763 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System");
1764 InitializeObjectAttributes(&ObjectAttributes
,
1766 OBJ_CASE_INSENSITIVE
,
1769 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
1770 if (!NT_SUCCESS(Status
)) return NULL
;
1772 /* Reference the key object to get the root hive/cell to access directly */
1773 Status
= ObReferenceObjectByHandle(KeyHandle
,
1779 if (!NT_SUCCESS(Status
))
1786 /* Do all this under the registry lock */
1787 CmpLockRegistryExclusive();
1789 /* Get the hive and key cell */
1790 Hive
= KeyBody
->KeyControlBlock
->KeyHive
;
1791 RootCell
= KeyBody
->KeyControlBlock
->KeyCell
;
1793 /* Open the current control set key */
1794 RtlInitUnicodeString(&KeyName
, L
"Current");
1795 ControlCell
= CmpFindControlSet(Hive
, RootCell
, &KeyName
, &AutoSelect
);
1796 if (ControlCell
== HCELL_NIL
) goto EndPath
;
1798 /* Find all system drivers */
1799 Success
= CmpFindDrivers(Hive
, ControlCell
, SystemLoad
, NULL
, &DriverList
);
1800 if (!Success
) goto EndPath
;
1802 /* Sort by group/tag */
1803 if (!CmpSortDriverList(Hive
, ControlCell
, &DriverList
)) goto EndPath
;
1805 /* Remove circular dependencies (cycles) and sort */
1806 if (!CmpResolveDriverDependencies(&DriverList
)) goto EndPath
;
1808 /* Loop the list to count drivers */
1809 for (i
= 0, NextEntry
= DriverList
.Flink
;
1810 NextEntry
!= &DriverList
;
1811 i
++, NextEntry
= NextEntry
->Flink
);
1813 /* Allocate the array */
1814 ServicePath
= ExAllocatePool(NonPagedPool
, (i
+ 1) * sizeof(PUNICODE_STRING
));
1815 if (!ServicePath
) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 2, 1, 0, 0);
1817 /* Loop the driver list */
1818 for (i
= 0, NextEntry
= DriverList
.Flink
;
1819 NextEntry
!= &DriverList
;
1820 i
++, NextEntry
= NextEntry
->Flink
)
1823 DriverEntry
= CONTAINING_RECORD(NextEntry
, BOOT_DRIVER_LIST_ENTRY
, Link
);
1825 /* Allocate the path for the caller and duplicate the registry path */
1826 ServicePath
[i
] = ExAllocatePool(NonPagedPool
, sizeof(UNICODE_STRING
));
1827 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1828 &DriverEntry
->RegistryPath
,
1832 /* Terminate the list */
1833 ServicePath
[i
] = NULL
;
1836 /* Free the driver list if we had one */
1837 if (!IsListEmpty(&DriverList
)) CmpFreeDriverList(Hive
, &DriverList
);
1839 /* Unlock the registry */
1840 CmpUnlockRegistry();
1842 /* Close the key handle and dereference the object, then return the path */
1843 ObDereferenceObject(KeyBody
);
1850 CmpLockRegistryExclusive(VOID
)
1852 /* Enter a critical region and lock the registry */
1853 KeEnterCriticalRegion();
1854 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1857 ASSERT(CmpFlushStarveWriters
== 0);
1858 RtlGetCallersAddress(&CmpRegistryLockCaller
, &CmpRegistryLockCallerCaller
);
1863 CmpLockRegistry(VOID
)
1865 /* Enter a critical region */
1866 KeEnterCriticalRegion();
1868 /* Check if we have to starve writers */
1869 if (CmpFlushStarveWriters
)
1871 /* Starve exlusive waiters */
1872 ExAcquireSharedStarveExclusive(&CmpRegistryLock
, TRUE
);
1876 /* Just grab the lock */
1877 ExAcquireResourceSharedLite(&CmpRegistryLock
, TRUE
);
1883 CmpTestRegistryLock(VOID
)
1886 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1891 CmpTestRegistryLockExclusive(VOID
)
1894 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1899 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive
)
1901 /* Lock the flusher. We should already be in a critical section */
1902 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1903 ASSERT((ExIsResourceAcquiredShared(Hive
->FlusherLock
) == 0) &&
1904 (ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) == 0));
1905 ExAcquireResourceExclusiveLite(Hive
->FlusherLock
, TRUE
);
1910 CmpLockHiveFlusherShared(IN PCMHIVE Hive
)
1912 /* Lock the flusher. We should already be in a critical section */
1913 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1914 ASSERT((ExIsResourceAcquiredShared(Hive
->FlusherLock
) == 0) &&
1915 (ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) == 0));
1916 ExAcquireResourceSharedLite(Hive
->FlusherLock
, TRUE
);
1921 CmpUnlockHiveFlusher(IN PCMHIVE Hive
)
1924 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1925 CMP_ASSERT_FLUSH_LOCK(Hive
);
1927 /* Release the lock */
1928 ExReleaseResourceLite(Hive
->FlusherLock
);
1933 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive
)
1936 return !ExIsResourceAcquiredSharedLite(Hive
->FlusherLock
) ? FALSE
: TRUE
;
1941 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive
)
1944 return !ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) ? FALSE
: TRUE
;
1949 CmpUnlockRegistry(VOID
)
1952 CMP_ASSERT_REGISTRY_LOCK();
1954 /* Check if we should flush the registry */
1955 if (CmpFlushOnLockRelease
)
1957 /* The registry should be exclusively locked for this */
1958 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1960 /* Flush the registry */
1961 CmpDoFlushAll(TRUE
);
1962 CmpFlushOnLockRelease
= FALSE
;
1966 /* Lazy flush the registry */
1970 /* Release the lock and leave the critical region */
1971 ExReleaseResourceLite(&CmpRegistryLock
);
1972 KeLeaveCriticalRegion();
1977 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1
,
1980 ULONG Index1
, Index2
;
1983 CMP_ASSERT_REGISTRY_LOCK();
1985 /* Get hash indexes */
1986 Index1
= GET_HASH_INDEX(ConvKey1
);
1987 Index2
= GET_HASH_INDEX(ConvKey2
);
1989 /* See which one is highest */
1990 if (Index1
< Index2
)
1992 /* Grab them in the proper order */
1993 CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1994 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1998 /* Grab the second one first, then the first */
1999 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
2000 if (Index1
!= Index2
) CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
2006 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1
,
2009 ULONG Index1
, Index2
;
2012 CMP_ASSERT_REGISTRY_LOCK();
2014 /* Get hash indexes */
2015 Index1
= GET_HASH_INDEX(ConvKey1
);
2016 Index2
= GET_HASH_INDEX(ConvKey2
);
2017 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey2
).Owner
== KeGetCurrentThread()) ||
2018 (CmpTestRegistryLockExclusive()));
2020 /* See which one is highest */
2021 if (Index1
< Index2
)
2023 /* Grab them in the proper order */
2024 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
2025 (CmpTestRegistryLockExclusive()));
2026 CmpReleaseKcbLockByKey(ConvKey2
);
2027 CmpReleaseKcbLockByKey(ConvKey1
);
2031 /* Release the first one first, then the second */
2032 if (Index1
!= Index2
)
2034 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
2035 (CmpTestRegistryLockExclusive()));
2036 CmpReleaseKcbLockByKey(ConvKey1
);
2038 CmpReleaseKcbLockByKey(ConvKey2
);
2044 CmShutdownSystem(VOID
)
2046 PLIST_ENTRY ListEntry
;
2050 /* Kill the workers */
2051 if (!CmFirstTime
) CmpShutdownWorkers();
2053 /* Flush all hives */
2054 CmpLockRegistryExclusive();
2055 CmpDoFlushAll(TRUE
);
2057 /* Close all hive files */
2058 ListEntry
= CmpHiveListHead
.Flink
;
2059 while (ListEntry
!= &CmpHiveListHead
)
2061 Hive
= CONTAINING_RECORD(ListEntry
, CMHIVE
, HiveList
);
2063 for (i
= 0; i
< HFILE_TYPE_MAX
; i
++)
2065 if (Hive
->FileHandles
[i
] != NULL
)
2067 ZwClose(Hive
->FileHandles
[i
]);
2068 Hive
->FileHandles
[i
] = NULL
;
2072 ListEntry
= ListEntry
->Flink
;
2075 CmpUnlockRegistry();
2080 CmpSetVersionData(VOID
)
2082 OBJECT_ATTRIBUTES ObjectAttributes
;
2083 UNICODE_STRING KeyName
;
2084 UNICODE_STRING ValueName
;
2085 UNICODE_STRING ValueData
;
2086 HANDLE SoftwareKeyHandle
= NULL
;
2087 HANDLE MicrosoftKeyHandle
= NULL
;
2088 HANDLE WindowsNtKeyHandle
= NULL
;
2089 HANDLE CurrentVersionKeyHandle
= NULL
;
2093 /* Open the 'CurrentVersion' key */
2094 RtlInitUnicodeString(&KeyName
,
2095 L
"\\REGISTRY\\MACHINE\\SOFTWARE");
2097 InitializeObjectAttributes(&ObjectAttributes
,
2099 OBJ_CASE_INSENSITIVE
,
2103 Status
= NtCreateKey(&SoftwareKeyHandle
,
2110 if (!NT_SUCCESS(Status
))
2112 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2116 /* Open the 'CurrentVersion' key */
2117 RtlInitUnicodeString(&KeyName
,
2120 InitializeObjectAttributes(&ObjectAttributes
,
2122 OBJ_CASE_INSENSITIVE
,
2126 Status
= NtCreateKey(&MicrosoftKeyHandle
,
2133 if (!NT_SUCCESS(Status
))
2135 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2139 /* Open the 'CurrentVersion' key */
2140 RtlInitUnicodeString(&KeyName
,
2143 InitializeObjectAttributes(&ObjectAttributes
,
2145 OBJ_CASE_INSENSITIVE
,
2149 Status
= NtCreateKey(&WindowsNtKeyHandle
,
2156 if (!NT_SUCCESS(Status
))
2158 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2162 /* Open the 'CurrentVersion' key */
2163 RtlInitUnicodeString(&KeyName
,
2166 InitializeObjectAttributes(&ObjectAttributes
,
2168 OBJ_CASE_INSENSITIVE
,
2172 Status
= NtCreateKey(&CurrentVersionKeyHandle
,
2173 KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
2179 if (!NT_SUCCESS(Status
))
2181 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2185 /* Set the 'CurrentType' value */
2186 RtlInitUnicodeString(&ValueName
,
2190 wcscpy(Buffer
, L
"Multiprocessor");
2192 wcscpy(Buffer
, L
"Uniprocessor");
2195 wcscat(Buffer
, L
" ");
2198 wcscat(Buffer
, L
"Checked");
2200 wcscat(Buffer
, L
"Free");
2203 RtlInitUnicodeString(&ValueData
,
2206 NtSetValueKey(CurrentVersionKeyHandle
,
2211 ValueData
.Length
+ sizeof(WCHAR
));
2214 /* Close the keys */
2215 if (CurrentVersionKeyHandle
!= NULL
)
2216 NtClose(CurrentVersionKeyHandle
);
2218 if (WindowsNtKeyHandle
!= NULL
)
2219 NtClose(WindowsNtKeyHandle
);
2221 if (MicrosoftKeyHandle
!= NULL
)
2222 NtClose(MicrosoftKeyHandle
);
2224 if (SoftwareKeyHandle
!= NULL
)
2225 NtClose(SoftwareKeyHandle
);