2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmsysini.c
5 * PURPOSE: Configuration Manager - System Initialization Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 POBJECT_TYPE CmpKeyObjectType
;
16 PCMHIVE CmiVolatileHive
;
17 LIST_ENTRY CmpHiveListHead
;
18 ERESOURCE CmpRegistryLock
;
19 KGUARDED_MUTEX CmpSelfHealQueueLock
;
20 LIST_ENTRY CmpSelfHealQueueListHead
;
21 KEVENT CmpLoadWorkerEvent
;
22 LONG CmpLoadWorkerIncrement
;
23 PEPROCESS CmpSystemProcess
;
24 BOOLEAN HvShutdownComplete
;
25 PVOID CmpRegistryLockCallerCaller
, CmpRegistryLockCaller
;
26 BOOLEAN CmpFlushStarveWriters
;
27 BOOLEAN CmpFlushOnLockRelease
;
28 BOOLEAN CmpSpecialBootCondition
;
30 BOOLEAN CmpForceForceFlush
;
31 BOOLEAN CmpWasSetupBoot
;
32 ULONG CmpTraceLevel
= 0;
34 extern BOOLEAN CmFirstTime
;
36 /* FUNCTIONS *****************************************************************/
40 CmpDeleteKeyObject(PVOID DeletedObject
)
42 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)DeletedObject
;
43 PCM_KEY_CONTROL_BLOCK Kcb
;
44 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo
;
45 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
49 /* First off, prepare the handle close information callback */
50 PostOperationInfo
.Object
= KeyBody
;
51 KeyHandleCloseInfo
.Object
= KeyBody
;
52 Status
= CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose
,
54 if (!NT_SUCCESS(Status
))
56 /* If we failed, notify the post routine */
57 PostOperationInfo
.Status
= Status
;
58 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
62 /* Acquire hive lock */
65 /* Make sure this is a valid key body */
66 if (KeyBody
->Type
== TAG('k', 'y', '0', '2'))
69 Kcb
= KeyBody
->KeyControlBlock
;
73 DelistKeyBodyFromKCB(KeyBody
, FALSE
);
75 /* Dereference the KCB */
76 CmpDelayDerefKeyControlBlock(Kcb
);
80 /* Release the registry lock */
83 /* Do the post callback */
84 PostOperationInfo
.Status
= STATUS_SUCCESS
;
85 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
90 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL
,
92 IN ACCESS_MASK GrantedAccess
,
93 IN ULONG ProcessHandleCount
,
94 IN ULONG SystemHandleCount
)
96 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)Object
;
99 /* Don't do anything if we're not the last handle */
100 if (SystemHandleCount
> 1) return;
102 /* Make sure we're a valid key body */
103 if (KeyBody
->Type
== TAG('k', 'y', '0', '2'))
105 /* Don't do anything if we don't have a notify block */
106 if (!KeyBody
->NotifyBlock
) return;
108 /* This shouldn't happen yet */
115 CmpQueryKeyName(IN PVOID ObjectBody
,
117 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
119 OUT PULONG ReturnLength
,
120 IN KPROCESSOR_MODE PreviousMode
)
122 PUNICODE_STRING KeyName
;
123 NTSTATUS Status
= STATUS_SUCCESS
;
124 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)ObjectBody
;
125 PCM_KEY_CONTROL_BLOCK Kcb
= KeyBody
->KeyControlBlock
;
127 /* Acquire hive lock */
130 /* Lock KCB shared */
131 CmpAcquireKcbLockShared(Kcb
);
133 /* Check if it's a deleted block */
136 /* Release the locks */
137 CmpReleaseKcbLock(Kcb
);
140 /* Let the caller know it's deleted */
141 return STATUS_KEY_DELETED
;
145 KeyName
= CmpConstructName(Kcb
);
147 /* Release the locks */
148 CmpReleaseKcbLock(Kcb
);
151 /* Check if we got the name */
152 if (!KeyName
) return STATUS_INSUFFICIENT_RESOURCES
;
154 /* Set the returned length */
155 *ReturnLength
= KeyName
->Length
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
);
157 /* Check if it fits into the provided buffer */
158 if ((Length
< sizeof(OBJECT_NAME_INFORMATION
)) ||
159 (Length
< (*ReturnLength
- sizeof(OBJECT_NAME_INFORMATION
))))
161 /* Free the buffer allocated by CmpConstructName */
164 /* Return buffer length failure */
165 return STATUS_INFO_LENGTH_MISMATCH
;
168 /* Fill in the result */
171 /* Return data to user */
172 ObjectNameInfo
->Name
.Buffer
= (PWCHAR
)(ObjectNameInfo
+ 1);
173 ObjectNameInfo
->Name
.MaximumLength
= KeyName
->Length
;
174 ObjectNameInfo
->Name
.Length
= KeyName
->Length
;
176 /* Copy string content*/
177 RtlCopyMemory(ObjectNameInfo
->Name
.Buffer
,
181 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
184 Status
= _SEH2_GetExceptionCode();
188 /* Free the buffer allocated by CmpConstructName */
197 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName
,
203 ULONG HiveDisposition
, LogDisposition
;
204 HANDLE FileHandle
= NULL
, LogHandle
= NULL
;
206 ULONG Operation
, FileType
;
213 /* Open or create the hive files */
214 Status
= CmpOpenHiveFiles(HiveName
,
224 if (!NT_SUCCESS(Status
)) return Status
;
226 /* Check if we have a log handle */
227 FileType
= (LogHandle
) ? HFILE_TYPE_LOG
: HFILE_TYPE_PRIMARY
;
229 /* Check if we created or opened the hive */
230 if (HiveDisposition
== FILE_CREATED
)
232 /* Do a create operation */
233 Operation
= HINIT_CREATE
;
238 /* Open it as a file */
239 Operation
= HINIT_FILE
;
243 /* Check if we're sharing hives */
244 if (CmpShareSystemHives
)
246 /* Then force using the primary hive */
247 FileType
= HFILE_TYPE_PRIMARY
;
250 /* Get rid of the log handle */
256 /* Check if we're too late */
257 if (HvShutdownComplete
)
261 if (LogHandle
) ZwClose(LogHandle
);
262 return STATUS_TOO_LATE
;
265 /* Initialize the hive */
266 Status
= CmpInitializeHive((PCMHIVE
*)&NewHive
,
276 if (!NT_SUCCESS(Status
))
280 if (LogHandle
) ZwClose(LogHandle
);
284 /* Success, return hive */
287 /* ROS: Init root key cell and prepare the hive */
288 if (Operation
== HINIT_CREATE
) CmCreateRootNode(&NewHive
->Hive
, L
"");
290 /* Duplicate the hive name */
291 NewHive
->FileFullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
294 if (NewHive
->FileFullPath
.Buffer
)
296 /* Copy the string */
297 RtlCopyMemory(NewHive
->FileFullPath
.Buffer
,
300 NewHive
->FileFullPath
.Length
= HiveName
->Length
;
301 NewHive
->FileFullPath
.MaximumLength
= HiveName
->MaximumLength
;
305 return STATUS_SUCCESS
;
310 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
312 OBJECT_ATTRIBUTES ObjectAttributes
;
313 UNICODE_STRING KeyName
, ValueName
= { 0, 0, NULL
};
316 ASSERT(LoaderBlock
!= NULL
);
318 /* Setup attributes for loader options */
319 RtlInitUnicodeString(&KeyName
,
320 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
322 InitializeObjectAttributes(&ObjectAttributes
,
324 OBJ_CASE_INSENSITIVE
,
327 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
328 if (!NT_SUCCESS(Status
)) goto Quickie
;
330 /* Key opened, now write to the key */
331 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
332 Status
= NtSetValueKey(KeyHandle
,
336 CmpLoadOptions
.Buffer
,
337 CmpLoadOptions
.Length
);
338 if (!NT_SUCCESS(Status
)) goto Quickie
;
340 /* Setup value name for system boot device */
341 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
342 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->NtBootPathName
);
343 Status
= NtSetValueKey(KeyHandle
,
351 /* Free the buffers */
352 RtlFreeUnicodeString(&ValueName
);
354 /* Close the key and return */
357 /* Return the status */
358 return (ExpInTextModeSetup
? STATUS_SUCCESS
: Status
);
363 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
365 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
366 UNICODE_STRING SelectName
=
367 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
368 UNICODE_STRING KeyName
;
369 OBJECT_ATTRIBUTES ObjectAttributes
;
370 CHAR ValueInfoBuffer
[128];
371 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
373 WCHAR UnicodeBuffer
[128];
374 HANDLE SelectHandle
, KeyHandle
, ConfigHandle
= NULL
, ProfileHandle
= NULL
;
375 HANDLE ParentHandle
= NULL
;
376 ULONG ControlSet
, HwProfile
;
377 ANSI_STRING TempString
;
379 ULONG ResultLength
, Disposition
;
380 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
383 /* Open the select key */
384 InitializeObjectAttributes(&ObjectAttributes
,
386 OBJ_CASE_INSENSITIVE
,
389 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
390 if (!NT_SUCCESS(Status
))
392 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
393 if (!LoaderBlock
->RegistryBase
)
395 /* Build the ControlSet001 key */
396 RtlInitUnicodeString(&KeyName
,
397 L
"\\Registry\\Machine\\System\\ControlSet001");
398 InitializeObjectAttributes(&ObjectAttributes
,
400 OBJ_CASE_INSENSITIVE
,
403 Status
= NtCreateKey(&KeyHandle
,
410 if (!NT_SUCCESS(Status
)) return Status
;
412 /* Don't need the handle */
415 /* Use hard-coded setting */
420 /* Fail for real boots */
424 /* Open the current value */
425 RtlInitUnicodeString(&KeyName
, L
"Current");
426 Status
= NtQueryValueKey(SelectHandle
,
428 KeyValueFullInformation
,
430 sizeof(ValueInfoBuffer
),
432 NtClose(SelectHandle
);
433 if (!NT_SUCCESS(Status
)) return Status
;
435 /* Get the actual value pointer, and get the control set ID */
436 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
437 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
439 /* Create the current control set key */
441 RtlInitUnicodeString(&KeyName
,
442 L
"\\Registry\\Machine\\System\\CurrentControlSet");
443 InitializeObjectAttributes(&ObjectAttributes
,
445 OBJ_CASE_INSENSITIVE
,
448 Status
= NtCreateKey(&KeyHandle
,
453 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
455 if (!NT_SUCCESS(Status
)) return Status
;
458 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
460 /* Initialize the symbolic link name */
462 "\\Registry\\Machine\\System\\ControlSet%03ld",
464 RtlInitAnsiString(&TempString
, Buffer
);
466 /* Create a Unicode string out of it */
467 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
468 KeyName
.Buffer
= UnicodeBuffer
;
469 Status
= RtlAnsiStringToUnicodeString(&KeyName
, &TempString
, FALSE
);
472 Status
= NtSetValueKey(KeyHandle
,
473 &CmSymbolicLinkValueName
,
478 if (!NT_SUCCESS(Status
)) return Status
;
480 /* Get the configuration database key */
481 InitializeObjectAttributes(&ObjectAttributes
,
483 OBJ_CASE_INSENSITIVE
,
486 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
489 /* Check if we don't have one */
490 if (!NT_SUCCESS(Status
))
492 /* Cleanup and exit */
497 /* Now get the current config */
498 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
499 Status
= NtQueryValueKey(ConfigHandle
,
501 KeyValueFullInformation
,
503 sizeof(ValueInfoBuffer
),
506 /* Set pointer to buffer */
507 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
509 /* Check if we failed or got a non DWORD-value */
510 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
)) goto Cleanup
;
512 /* Get the hadware profile */
513 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
515 /* Open the hardware profile key */
516 RtlInitUnicodeString(&KeyName
,
517 L
"\\Registry\\Machine\\System\\CurrentControlSet"
518 L
"\\Hardware Profiles");
519 InitializeObjectAttributes(&ObjectAttributes
,
521 OBJ_CASE_INSENSITIVE
,
524 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
525 if (!NT_SUCCESS(Status
))
527 /* Exit and clean up */
532 /* Build the profile name */
533 sprintf(Buffer
, "%04ld", HwProfile
);
534 RtlInitAnsiString(&TempString
, Buffer
);
536 /* Convert it to Unicode */
537 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
538 KeyName
.Buffer
= UnicodeBuffer
;
539 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
542 ASSERT(Status
== STATUS_SUCCESS
);
544 /* Open the associated key */
545 InitializeObjectAttributes(&ObjectAttributes
,
547 OBJ_CASE_INSENSITIVE
,
550 Status
= NtOpenKey(&ProfileHandle
,
551 KEY_READ
| KEY_WRITE
,
553 if (!NT_SUCCESS (Status
))
555 /* Cleanup and exit */
560 /* Check if we have a loader block extension */
561 LoaderExtension
= LoaderBlock
->Extension
;
564 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE
);
567 /* Create the current hardware profile key */
568 RtlInitUnicodeString(&KeyName
,
569 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
570 L
"Hardware Profiles\\Current");
571 InitializeObjectAttributes(&ObjectAttributes
,
573 OBJ_CASE_INSENSITIVE
,
576 Status
= NtCreateKey(&KeyHandle
,
581 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
583 if (NT_SUCCESS(Status
))
586 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
588 /* Create the profile name */
590 "\\Registry\\Machine\\System\\CurrentControlSet\\"
591 "Hardware Profiles\\%04ld",
593 RtlInitAnsiString(&TempString
, Buffer
);
595 /* Convert it to Unicode */
596 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
597 KeyName
.Buffer
= UnicodeBuffer
;
598 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
601 ASSERT(STATUS_SUCCESS
== Status
);
604 Status
= NtSetValueKey(KeyHandle
,
605 &CmSymbolicLinkValueName
,
613 /* Close every opened handle */
615 if (ConfigHandle
) NtClose(ConfigHandle
);
616 if (ProfileHandle
) NtClose(ProfileHandle
);
617 if (ParentHandle
) NtClose(ParentHandle
);
620 return STATUS_SUCCESS
;
625 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName
,
626 IN HANDLE RootDirectory
,
627 IN PCMHIVE RegistryHive
,
629 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
631 OBJECT_ATTRIBUTES ObjectAttributes
;
633 CM_PARSE_CONTEXT ParseContext
= {0};
635 PCM_KEY_BODY KeyBody
;
638 /* Setup the object attributes */
639 InitializeObjectAttributes(&ObjectAttributes
,
641 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
645 /* Setup the parse context */
646 ParseContext
.CreateLink
= TRUE
;
647 ParseContext
.CreateOperation
= TRUE
;
648 ParseContext
.ChildHive
.KeyHive
= &RegistryHive
->Hive
;
650 /* Check if we have a root keycell or if we need to create it */
654 ParseContext
.ChildHive
.KeyCell
= HCELL_NIL
;
659 ParseContext
.ChildHive
.KeyCell
= RegistryHive
->Hive
.BaseBlock
->RootCell
;
662 /* Create the link node */
663 Status
= ObOpenObjectByName(&ObjectAttributes
,
667 KEY_READ
| KEY_WRITE
,
668 (PVOID
)&ParseContext
,
670 if (!NT_SUCCESS(Status
)) return Status
;
672 /* Mark the hive as clean */
673 RegistryHive
->Hive
.DirtyFlag
= FALSE
;
675 /* ReactOS Hack: Keep alive */
676 Status
= ObReferenceObjectByHandle(KeyHandle
,
682 ASSERT(NT_SUCCESS(Status
));
684 /* Close the extra handle */
686 return STATUS_SUCCESS
;
691 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
694 ANSI_STRING LoadString
;
699 UNICODE_STRING KeyName
;
700 PCMHIVE SystemHive
= NULL
;
701 UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
702 PSECURITY_DESCRIPTOR SecurityDescriptor
;
705 /* Setup the ansi string */
706 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
708 /* Allocate the unicode buffer */
709 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
710 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
714 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
717 /* Setup the unicode string */
718 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, (USHORT
)Length
);
720 /* Add the load options and null-terminate */
721 RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
722 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
723 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
725 /* Get the System Hive base address */
726 HiveBase
= LoaderBlock
->RegistryBase
;
730 ((PHBASE_BLOCK
)HiveBase
)->Length
= LoaderBlock
->RegistryLength
;
731 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
741 if (!NT_SUCCESS(Status
)) return FALSE
;
743 /* Set the hive filename */
744 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
745 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
747 /* We imported, no need to create a new hive */
750 /* Manually set the hive as volatile, if in Live CD mode */
751 if (CmpShareSystemHives
) SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
756 Status
= CmpInitializeHive(&SystemHive
,
766 if (!NT_SUCCESS(Status
)) return FALSE
;
768 /* Set the hive filename */
769 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
770 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
772 /* Tell CmpLinkHiveToMaster to allocate a hive */
776 /* Save the boot type */
777 CmpBootType
= SystemHive
->Hive
.BaseBlock
->BootType
;
779 /* Are we in self-healing mode? */
782 /* Disable self-healing internally and check if boot type wanted it */
786 /* We're disabled, so bugcheck */
787 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
,
790 (ULONG_PTR
)SystemHive
,
795 /* Create the default security descriptor */
796 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
798 /* Attach it to the system key */
799 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM");
800 Status
= CmpLinkHiveToMaster(&KeyName
,
806 /* Free the security descriptor */
807 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
808 if (!NT_SUCCESS(Status
)) return FALSE
;
810 /* Add the hive to the hive list */
811 CmpMachineHiveList
[3].CmHive
= (PCMHIVE
)SystemHive
;
819 CmpCreateObjectTypes(VOID
)
821 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
823 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
829 /* Initialize the Key object type */
830 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
831 RtlInitUnicodeString(&Name
, L
"Key");
832 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
833 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
834 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
835 ObjectTypeInitializer
.PoolType
= PagedPool
;
836 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
837 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
838 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
839 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
840 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
841 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
842 ObjectTypeInitializer
.CloseProcedure
= CmpCloseKeyObject
;
843 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
846 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
851 CmpCreateRootNode(IN PHHIVE Hive
,
853 OUT PHCELL_INDEX Index
)
855 UNICODE_STRING KeyName
;
856 PCM_KEY_NODE KeyCell
;
857 LARGE_INTEGER SystemTime
;
860 /* Initialize the node name and allocate it */
861 RtlInitUnicodeString(&KeyName
, Name
);
862 *Index
= HvAllocateCell(Hive
,
863 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
864 CmpNameSize(Hive
, &KeyName
),
867 if (*Index
== HCELL_NIL
) return FALSE
;
869 /* Set the cell index and get the data */
870 Hive
->BaseBlock
->RootCell
= *Index
;
871 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
872 if (!KeyCell
) return FALSE
;
875 KeyCell
->Signature
= (USHORT
)CM_KEY_NODE_SIGNATURE
;
876 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
877 KeQuerySystemTime(&SystemTime
);
878 KeyCell
->LastWriteTime
= SystemTime
;
879 KeyCell
->Parent
= HCELL_NIL
;
880 KeyCell
->SubKeyCounts
[Stable
] = 0;
881 KeyCell
->SubKeyCounts
[Volatile
] = 0;
882 KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
883 KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
884 KeyCell
->ValueList
.Count
= 0;
885 KeyCell
->ValueList
.List
= HCELL_NIL
;
886 KeyCell
->Security
= HCELL_NIL
;
887 KeyCell
->Class
= HCELL_NIL
;
888 KeyCell
->ClassLength
= 0;
889 KeyCell
->MaxNameLen
= 0;
890 KeyCell
->MaxClassLen
= 0;
891 KeyCell
->MaxValueNameLen
= 0;
892 KeyCell
->MaxValueDataLen
= 0;
894 /* Copy the name (this will also set the length) */
895 KeyCell
->NameLength
= CmpCopyName(Hive
, (PWCHAR
)KeyCell
->Name
, &KeyName
);
897 /* Check if the name was compressed */
898 if (KeyCell
->NameLength
< KeyName
.Length
)
901 KeyCell
->Flags
|= KEY_COMP_NAME
;
905 HvReleaseCell(Hive
, *Index
);
911 CmpCreateRegistryRoot(VOID
)
913 UNICODE_STRING KeyName
;
914 OBJECT_ATTRIBUTES ObjectAttributes
;
915 PCM_KEY_BODY RootKey
;
916 HCELL_INDEX RootIndex
;
918 PCM_KEY_NODE KeyCell
;
919 PSECURITY_DESCRIPTOR SecurityDescriptor
;
920 PCM_KEY_CONTROL_BLOCK Kcb
;
923 /* Setup the root node */
924 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
930 /* Create '\Registry' key. */
931 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
932 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
933 InitializeObjectAttributes(&ObjectAttributes
,
935 OBJ_CASE_INSENSITIVE
,
938 Status
= ObCreateObject(KernelMode
,
947 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
948 if (!NT_SUCCESS(Status
)) return FALSE
;
950 /* Sanity check, and get the key cell */
951 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
952 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
953 if (!KeyCell
) return FALSE
;
956 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
957 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
963 if (!Kcb
) return FALSE
;
965 /* Initialize the object */
966 RootKey
->KeyControlBlock
= Kcb
;
967 RootKey
->Type
= TAG('k', 'y', '0', '2');
968 RootKey
->NotifyBlock
= NULL
;
969 RootKey
->ProcessID
= PsGetCurrentProcessId();
972 EnlistKeyBodyWithKCB(RootKey
, 0);
974 /* Insert the key into the namespace */
975 Status
= ObInsertObject(RootKey
,
980 &CmpRegistryRootHandle
);
981 if (!NT_SUCCESS(Status
)) return FALSE
;
983 /* Reference the key again so that we never lose it */
984 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
990 if (!NT_SUCCESS(Status
)) return FALSE
;
992 /* Completely sucessful */
998 CmpGetRegistryPath(IN PWCHAR ConfigPath
)
1000 OBJECT_ATTRIBUTES ObjectAttributes
;
1003 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1004 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1005 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1006 ULONG BufferSize
, ResultSize
;
1008 /* Check if we are booted in setup */
1009 if (ExpInTextModeSetup
)
1011 /* Setup the object attributes */
1012 InitializeObjectAttributes(&ObjectAttributes
,
1014 OBJ_CASE_INSENSITIVE
,
1018 Status
= ZwOpenKey(&KeyHandle
,
1021 if (!NT_SUCCESS(Status
)) return Status
;
1023 /* Allocate the buffer */
1024 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1025 ValueInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_CM
);
1030 return STATUS_INSUFFICIENT_RESOURCES
;
1033 /* Query the value */
1034 Status
= ZwQueryValueKey(KeyHandle
,
1036 KeyValuePartialInformation
,
1041 if (!NT_SUCCESS(Status
))
1044 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1048 /* Copy the config path and null-terminate it */
1049 RtlCopyMemory(ConfigPath
,
1051 ValueInfo
->DataLength
);
1052 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1053 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1057 /* Just use default path */
1058 wcscpy(ConfigPath
, L
"\\SystemRoot");
1061 /* Add registry path */
1062 wcscat(ConfigPath
, L
"\\System32\\Config\\");
1065 return STATUS_SUCCESS
;
1070 CmpLoadHiveThread(IN PVOID StartContext
)
1072 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1073 UNICODE_STRING TempName
, FileName
, RegName
;
1074 ULONG FileStart
, RegStart
, i
, ErrorResponse
, WorkerCount
, Length
;
1075 ULONG PrimaryDisposition
, SecondaryDisposition
, ClusterSize
;
1077 HANDLE PrimaryHandle
, LogHandle
;
1078 NTSTATUS Status
= STATUS_SUCCESS
;
1079 PVOID ErrorParameters
;
1082 /* Get the hive index, make sure it makes sense */
1083 i
= PtrToUlong(StartContext
);
1084 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1086 /* We were started */
1087 CmpMachineHiveList
[i
].ThreadStarted
= TRUE
;
1089 /* Build the file name and registry name strings */
1090 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1091 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1093 /* Now build the system root path */
1094 CmpGetRegistryPath(ConfigPath
);
1095 RtlInitUnicodeString(&TempName
, ConfigPath
);
1096 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1097 FileStart
= FileName
.Length
;
1099 /* And build the registry root path */
1100 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1101 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1102 RegStart
= RegName
.Length
;
1104 /* Build the base name */
1105 RegName
.Length
= RegStart
;
1106 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1107 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1109 /* Check if this is a child of the root */
1110 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1112 /* Then setup the whole name */
1113 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1114 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1117 /* Now add the rest of the file name */
1118 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1119 FileName
.Length
= FileStart
;
1120 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1121 if (!CmpMachineHiveList
[i
].CmHive
)
1123 /* We need to allocate a new hive structure */
1124 CmpMachineHiveList
[i
].Allocate
= TRUE
;
1126 /* Load the hive file */
1127 Status
= CmpInitHiveFromFile(&FileName
,
1128 CmpMachineHiveList
[i
].HHiveFlags
,
1130 &CmpMachineHiveList
[i
].Allocate
,
1132 if (!(NT_SUCCESS(Status
)) ||
1133 (!(CmHive
->FileHandles
[HFILE_TYPE_LOG
]) && !(CmpMiniNTBoot
))) // HACK
1135 /* We failed or couldn't get a log file, raise a hard error */
1136 ErrorParameters
= &FileName
;
1137 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1140 (PULONG_PTR
)&ErrorParameters
,
1145 /* Set the hive flags and newly allocated hive pointer */
1146 CmHive
->Flags
= CmpMachineHiveList
[i
].CmHiveFlags
;
1147 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1151 /* We already have a hive, is it volatile? */
1152 CmHive
= CmpMachineHiveList
[i
].CmHive
;
1153 if (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
1155 /* It's now, open the hive file and log */
1156 Status
= CmpOpenHiveFiles(&FileName
,
1160 &PrimaryDisposition
,
1161 &SecondaryDisposition
,
1166 if (!(NT_SUCCESS(Status
)) || !(LogHandle
))
1168 /* Couldn't open the hive or its log file, raise a hard error */
1169 ErrorParameters
= &FileName
;
1170 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1173 (PULONG_PTR
)&ErrorParameters
,
1177 /* And bugcheck for posterity's sake */
1178 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 0, i
, Status
);
1181 /* Save the file handles. This should remove our sync hacks */
1182 CmHive
->FileHandles
[HFILE_TYPE_LOG
] = LogHandle
;
1183 CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = PrimaryHandle
;
1185 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1186 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1187 CmHive
->Hive
.HiveFlags
&= ~HIVE_NOLAZYFLUSH
;
1189 /* Get the real size of the hive */
1190 Length
= CmHive
->Hive
.Storage
[Stable
].Length
+ HBLOCK_SIZE
;
1192 /* Check if the cluster size doesn't match */
1193 if (CmHive
->Hive
.Cluster
!= ClusterSize
) ASSERT(FALSE
);
1195 /* Set the file size */
1196 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1198 /* This shouldn't fail */
1202 /* Another thing we don't support is NTLDR-recovery */
1203 if (CmHive
->Hive
.BaseBlock
->BootRecover
) ASSERT(FALSE
);
1205 /* Finally, set our allocated hive to the same hive we've had */
1206 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1207 ASSERT(CmpMachineHiveList
[i
].CmHive
== CmpMachineHiveList
[i
].CmHive2
);
1212 CmpMachineHiveList
[i
].ThreadFinished
= TRUE
;
1214 /* Check if we're the last worker */
1215 WorkerCount
= InterlockedIncrement(&CmpLoadWorkerIncrement
);
1216 if (WorkerCount
== CM_NUMBER_OF_MACHINE_HIVES
)
1218 /* Signal the event */
1219 KeSetEvent(&CmpLoadWorkerEvent
, 0, FALSE
);
1222 /* Kill the thread */
1223 PsTerminateSystemThread(Status
);
1228 CmpInitializeHiveList(IN USHORT Flag
)
1230 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1231 UNICODE_STRING TempName
, FileName
, RegName
;
1234 ULONG FileStart
, RegStart
, i
;
1235 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1238 /* Allow writing for now */
1241 /* Build the file name and registry name strings */
1242 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1243 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1245 /* Now build the system root path */
1246 CmpGetRegistryPath(ConfigPath
);
1247 RtlInitUnicodeString(&TempName
, ConfigPath
);
1248 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1249 FileStart
= FileName
.Length
;
1251 /* And build the registry root path */
1252 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1253 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1254 RegStart
= RegName
.Length
;
1256 /* Setup the event to synchronize workers */
1257 KeInitializeEvent(&CmpLoadWorkerEvent
, SynchronizationEvent
, FALSE
);
1259 /* Enter special boot condition */
1260 CmpSpecialBootCondition
= TRUE
;
1262 /* Create the SD for the root hives */
1263 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1265 /* Loop every hive we care about */
1266 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1268 /* Make sure the list is setup */
1269 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1271 /* Create a thread to handle this hive */
1272 Status
= PsCreateSystemThread(&Thread
,
1279 if (NT_SUCCESS(Status
))
1281 /* We don't care about the handle -- the thread self-terminates */
1286 /* Can't imagine this happening */
1287 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 3, i
, Status
);
1291 /* Make sure we've reached the end of the list */
1292 ASSERT(CmpMachineHiveList
[i
].Name
== NULL
);
1294 /* Wait for hive loading to finish */
1295 KeWaitForSingleObject(&CmpLoadWorkerEvent
,
1301 /* Exit the special boot condition and make sure all workers completed */
1302 CmpSpecialBootCondition
= FALSE
;
1303 ASSERT(CmpLoadWorkerIncrement
== CM_NUMBER_OF_MACHINE_HIVES
);
1305 /* Loop hives again */
1306 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1308 /* Make sure the thread ran and finished */
1309 ASSERT(CmpMachineHiveList
[i
].ThreadFinished
== TRUE
);
1310 ASSERT(CmpMachineHiveList
[i
].ThreadStarted
== TRUE
);
1312 /* Check if this was a new hive */
1313 if (!CmpMachineHiveList
[i
].CmHive
)
1315 /* Make sure we allocated something */
1316 ASSERT(CmpMachineHiveList
[i
].CmHive2
!= NULL
);
1318 /* Build the base name */
1319 RegName
.Length
= RegStart
;
1320 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1321 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1323 /* Check if this is a child of the root */
1324 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1326 /* Then setup the whole name */
1327 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1328 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1331 /* Now link the hive to its master */
1332 Status
= CmpLinkHiveToMaster(&RegName
,
1334 CmpMachineHiveList
[i
].CmHive2
,
1335 CmpMachineHiveList
[i
].Allocate
,
1336 SecurityDescriptor
);
1337 if (Status
!= STATUS_SUCCESS
)
1339 /* Linking needs to work */
1340 KeBugCheckEx(CONFIG_LIST_FAILED
, 11, Status
, i
, (ULONG_PTR
)&RegName
);
1343 /* Check if we had to allocate a new hive */
1344 if (CmpMachineHiveList
[i
].Allocate
)
1346 /* Sync the new hive */
1347 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1351 /* Check if we created a new hive */
1352 if (CmpMachineHiveList
[i
].CmHive2
)
1354 /* TODO: Add to HiveList key */
1358 /* Get rid of the SD */
1359 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1361 /* FIXME: Link SECURITY to SAM */
1363 /* FIXME: Link S-1-5-18 to .Default */
1370 OBJECT_ATTRIBUTES ObjectAttributes
;
1371 UNICODE_STRING KeyName
;
1374 PCMHIVE HardwareHive
;
1375 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1378 /* Check if this is PE-boot */
1379 if (InitIsWinPEMode
)
1381 /* Set registry to PE mode */
1382 CmpMiniNTBoot
= TRUE
;
1383 CmpShareSystemHives
= TRUE
;
1386 /* Initialize the hive list and lock */
1387 InitializeListHead(&CmpHiveListHead
);
1388 ExInitializePushLock((PVOID
)&CmpHiveListHeadLock
);
1389 ExInitializePushLock((PVOID
)&CmpLoadHiveLock
);
1391 /* Initialize registry lock */
1392 ExInitializeResourceLite(&CmpRegistryLock
);
1394 /* Initialize the cache */
1395 CmpInitializeCache();
1397 /* Initialize allocation and delayed dereferencing */
1398 CmpInitCmPrivateAlloc();
1399 CmpInitCmPrivateDelayAlloc();
1400 CmpInitDelayDerefKCBEngine();
1402 /* Initialize callbacks */
1405 /* Initialize self healing */
1406 KeInitializeGuardedMutex(&CmpSelfHealQueueLock
);
1407 InitializeListHead(&CmpSelfHealQueueListHead
);
1409 /* Save the current process and lock the registry */
1410 CmpSystemProcess
= PsGetCurrentProcess();
1412 /* Create the key object types */
1413 Status
= CmpCreateObjectTypes();
1414 if (!NT_SUCCESS(Status
))
1417 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 1, Status
, 0);
1420 /* Build the master hive */
1421 Status
= CmpInitializeHive((PCMHIVE
*)&CmiVolatileHive
,
1431 if (!NT_SUCCESS(Status
))
1434 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 2, Status
, 0);
1437 /* Create the \REGISTRY key node */
1438 if (!CmpCreateRegistryRoot())
1441 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 3, 0, 0);
1444 /* Create the default security descriptor */
1445 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1447 /* Create '\Registry\Machine' key. */
1448 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE");
1449 InitializeObjectAttributes(&ObjectAttributes
,
1451 OBJ_CASE_INSENSITIVE
,
1453 SecurityDescriptor
);
1454 Status
= NtCreateKey(&KeyHandle
,
1455 KEY_READ
| KEY_WRITE
,
1461 if (!NT_SUCCESS(Status
))
1464 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 5, Status
, 0);
1467 /* Close the handle */
1470 /* Create '\Registry\User' key. */
1471 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\USER");
1472 InitializeObjectAttributes(&ObjectAttributes
,
1474 OBJ_CASE_INSENSITIVE
,
1476 SecurityDescriptor
);
1477 Status
= NtCreateKey(&KeyHandle
,
1478 KEY_READ
| KEY_WRITE
,
1484 if (!NT_SUCCESS(Status
))
1487 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 6, Status
, 0);
1490 /* Close the handle */
1493 /* Initialize the system hive */
1494 if (!CmpInitializeSystemHive(KeLoaderBlock
))
1497 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 7, 0, 0);
1500 /* Create the 'CurrentControlSet' link. */
1501 Status
= CmpCreateControlSet(KeLoaderBlock
);
1502 if (!NT_SUCCESS(Status
))
1505 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 8, Status
, 0);
1508 /* Create the hardware hive */
1509 Status
= CmpInitializeHive((PCMHIVE
*)&HardwareHive
,
1519 if (!NT_SUCCESS(Status
))
1522 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 11, Status
, 0);
1525 /* Add the hive to the hive list */
1526 CmpMachineHiveList
[0].CmHive
= (PCMHIVE
)HardwareHive
;
1528 /* Attach it to the machine key */
1529 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE");
1530 Status
= CmpLinkHiveToMaster(&KeyName
,
1532 (PCMHIVE
)HardwareHive
,
1534 SecurityDescriptor
);
1535 if (!NT_SUCCESS(Status
))
1538 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 12, Status
, 0);
1541 /* FIXME: Add to HiveList key */
1543 /* Free the security descriptor */
1544 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1546 /* Fill out the Hardware key with the ARC Data from the Loader */
1547 Status
= CmpInitializeHardwareConfiguration(KeLoaderBlock
);
1548 if (!NT_SUCCESS(Status
))
1551 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 13, Status
, 0);
1554 /* Initialize machine-dependent information into the registry */
1555 Status
= CmpInitializeMachineDependentConfiguration(KeLoaderBlock
);
1556 if (!NT_SUCCESS(Status
))
1559 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 14, Status
, 0);
1562 /* Initialize volatile registry settings */
1563 Status
= CmpSetSystemValues(KeLoaderBlock
);
1564 if (!NT_SUCCESS(Status
))
1567 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 15, Status
, 0);
1570 /* Free the load options */
1571 ExFreePoolWithTag(CmpLoadOptions
.Buffer
, TAG_CM
);
1573 /* If we got here, all went well */
1579 CmpLockRegistryExclusive(VOID
)
1581 /* Enter a critical region and lock the registry */
1582 KeEnterCriticalRegion();
1583 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1586 ASSERT(CmpFlushStarveWriters
== 0);
1587 RtlGetCallersAddress(&CmpRegistryLockCaller
, &CmpRegistryLockCallerCaller
);
1592 CmpLockRegistry(VOID
)
1594 /* Enter a critical region */
1595 KeEnterCriticalRegion();
1597 /* Check if we have to starve writers */
1598 if (CmpFlushStarveWriters
)
1600 /* Starve exlusive waiters */
1601 ExAcquireSharedStarveExclusive(&CmpRegistryLock
, TRUE
);
1605 /* Just grab the lock */
1606 ExAcquireResourceSharedLite(&CmpRegistryLock
, TRUE
);
1612 CmpTestRegistryLock(VOID
)
1615 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1620 CmpTestRegistryLockExclusive(VOID
)
1623 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1628 CmpUnlockRegistry(VOID
)
1631 CMP_ASSERT_REGISTRY_LOCK();
1633 /* Check if we should flush the registry */
1634 if (CmpFlushOnLockRelease
)
1636 /* The registry should be exclusively locked for this */
1637 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1639 /* Flush the registry */
1640 CmpDoFlushAll(TRUE
);
1641 CmpFlushOnLockRelease
= FALSE
;
1644 /* Release the lock and leave the critical region */
1645 ExReleaseResourceLite(&CmpRegistryLock
);
1646 KeLeaveCriticalRegion();
1651 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1
,
1654 ULONG Index1
, Index2
;
1657 CMP_ASSERT_REGISTRY_LOCK();
1659 /* Get hash indexes */
1660 Index1
= GET_HASH_INDEX(ConvKey1
);
1661 Index2
= GET_HASH_INDEX(ConvKey2
);
1663 /* See which one is highest */
1664 if (Index1
< Index2
)
1666 /* Grab them in the proper order */
1667 CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1668 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1672 /* Grab the second one first, then the first */
1673 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1674 if (Index1
!= Index2
) CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1680 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1
,
1683 ULONG Index1
, Index2
;
1686 CMP_ASSERT_REGISTRY_LOCK();
1688 /* Get hash indexes */
1689 Index1
= GET_HASH_INDEX(ConvKey1
);
1690 Index2
= GET_HASH_INDEX(ConvKey2
);
1691 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey2
).Owner
== KeGetCurrentThread()) ||
1692 (CmpTestRegistryLockExclusive()));
1694 /* See which one is highest */
1695 if (Index1
< Index2
)
1697 /* Grab them in the proper order */
1698 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1699 (CmpTestRegistryLockExclusive()));
1700 CmpReleaseKcbLockByKey(ConvKey2
);
1701 CmpReleaseKcbLockByKey(ConvKey1
);
1705 /* Release the first one first, then the second */
1706 if (Index1
!= Index2
)
1708 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1709 (CmpTestRegistryLockExclusive()));
1710 CmpReleaseKcbLockByKey(ConvKey1
);
1712 CmpReleaseKcbLockByKey(ConvKey2
);
1718 CmShutdownSystem(VOID
)
1720 /* Kill the workers and flush all hives */
1721 if (!CmFirstTime
) CmpShutdownWorkers();
1722 CmpDoFlushAll(TRUE
);