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 CmpFlushOnLockRelease
;
27 BOOLEAN CmpSpecialBootCondition
;
29 BOOLEAN CmpWasSetupBoot
;
30 ULONG CmpTraceLevel
= 0;
32 extern LONG CmpFlushStarveWriters
;
33 extern BOOLEAN CmFirstTime
;
35 /* FUNCTIONS *****************************************************************/
39 CmpDeleteKeyObject(PVOID DeletedObject
)
41 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)DeletedObject
;
42 PCM_KEY_CONTROL_BLOCK Kcb
;
43 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo
;
44 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
48 /* First off, prepare the handle close information callback */
49 PostOperationInfo
.Object
= KeyBody
;
50 KeyHandleCloseInfo
.Object
= KeyBody
;
51 Status
= CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose
,
53 if (!NT_SUCCESS(Status
))
55 /* If we failed, notify the post routine */
56 PostOperationInfo
.Status
= Status
;
57 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
61 /* Acquire hive lock */
64 /* Make sure this is a valid key body */
65 if (KeyBody
->Type
== '20yk')
68 Kcb
= KeyBody
->KeyControlBlock
;
72 DelistKeyBodyFromKCB(KeyBody
, FALSE
);
74 /* Dereference the KCB */
75 CmpDelayDerefKeyControlBlock(Kcb
);
79 /* Release the registry lock */
82 /* Do the post callback */
83 PostOperationInfo
.Status
= STATUS_SUCCESS
;
84 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
89 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL
,
91 IN ACCESS_MASK GrantedAccess
,
92 IN ULONG ProcessHandleCount
,
93 IN ULONG SystemHandleCount
)
95 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)Object
;
98 /* Don't do anything if we're not the last handle */
99 if (SystemHandleCount
> 1) return;
101 /* Make sure we're a valid key body */
102 if (KeyBody
->Type
== '20yk')
104 /* Don't do anything if we don't have a notify block */
105 if (!KeyBody
->NotifyBlock
) return;
107 /* This shouldn't happen yet */
114 CmpQueryKeyName(IN PVOID ObjectBody
,
116 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
118 OUT PULONG ReturnLength
,
119 IN KPROCESSOR_MODE PreviousMode
)
121 PUNICODE_STRING KeyName
;
122 NTSTATUS Status
= STATUS_SUCCESS
;
123 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)ObjectBody
;
124 PCM_KEY_CONTROL_BLOCK Kcb
= KeyBody
->KeyControlBlock
;
126 /* Acquire hive lock */
129 /* Lock KCB shared */
130 CmpAcquireKcbLockShared(Kcb
);
132 /* Check if it's a deleted block */
135 /* Release the locks */
136 CmpReleaseKcbLock(Kcb
);
139 /* Let the caller know it's deleted */
140 return STATUS_KEY_DELETED
;
144 KeyName
= CmpConstructName(Kcb
);
146 /* Release the locks */
147 CmpReleaseKcbLock(Kcb
);
150 /* Check if we got the name */
151 if (!KeyName
) return STATUS_INSUFFICIENT_RESOURCES
;
153 /* Set the returned length */
154 *ReturnLength
= KeyName
->Length
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
);
156 /* Check if it fits into the provided buffer */
157 if ((Length
< sizeof(OBJECT_NAME_INFORMATION
)) ||
158 (Length
< (*ReturnLength
- sizeof(OBJECT_NAME_INFORMATION
))))
160 /* Free the buffer allocated by CmpConstructName */
163 /* Return buffer length failure */
164 return STATUS_INFO_LENGTH_MISMATCH
;
167 /* Fill in the result */
170 /* Return data to user */
171 ObjectNameInfo
->Name
.Buffer
= (PWCHAR
)(ObjectNameInfo
+ 1);
172 ObjectNameInfo
->Name
.MaximumLength
= KeyName
->Length
;
173 ObjectNameInfo
->Name
.Length
= KeyName
->Length
;
175 /* Copy string content*/
176 RtlCopyMemory(ObjectNameInfo
->Name
.Buffer
,
180 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
183 Status
= _SEH2_GetExceptionCode();
187 /* Free the buffer allocated by CmpConstructName */
196 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName
,
202 ULONG HiveDisposition
, LogDisposition
;
203 HANDLE FileHandle
= NULL
, LogHandle
= NULL
;
205 ULONG Operation
, FileType
;
212 /* Open or create the hive files */
213 Status
= CmpOpenHiveFiles(HiveName
,
223 if (!NT_SUCCESS(Status
)) return Status
;
225 /* Check if we have a log handle */
226 FileType
= (LogHandle
) ? HFILE_TYPE_LOG
: HFILE_TYPE_PRIMARY
;
228 /* Check if we created or opened the hive */
229 if (HiveDisposition
== FILE_CREATED
)
231 /* Do a create operation */
232 Operation
= HINIT_CREATE
;
237 /* Open it as a file */
238 Operation
= HINIT_FILE
;
242 /* Check if we're sharing hives */
243 if (CmpShareSystemHives
)
245 /* Then force using the primary hive */
246 FileType
= HFILE_TYPE_PRIMARY
;
249 /* Get rid of the log handle */
255 /* Check if we're too late */
256 if (HvShutdownComplete
)
260 if (LogHandle
) ZwClose(LogHandle
);
261 return STATUS_TOO_LATE
;
264 /* Initialize the hive */
265 Status
= CmpInitializeHive((PCMHIVE
*)&NewHive
,
275 if (!NT_SUCCESS(Status
))
279 if (LogHandle
) ZwClose(LogHandle
);
283 /* Success, return hive */
286 /* ROS: Init root key cell and prepare the hive */
287 if (Operation
== HINIT_CREATE
) CmCreateRootNode(&NewHive
->Hive
, L
"");
289 /* Duplicate the hive name */
290 NewHive
->FileFullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
293 if (NewHive
->FileFullPath
.Buffer
)
295 /* Copy the string */
296 RtlCopyMemory(NewHive
->FileFullPath
.Buffer
,
299 NewHive
->FileFullPath
.Length
= HiveName
->Length
;
300 NewHive
->FileFullPath
.MaximumLength
= HiveName
->MaximumLength
;
304 return STATUS_SUCCESS
;
309 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
311 OBJECT_ATTRIBUTES ObjectAttributes
;
312 UNICODE_STRING KeyName
, ValueName
= { 0, 0, NULL
};
315 ASSERT(LoaderBlock
!= NULL
);
317 /* Setup attributes for loader options */
318 RtlInitUnicodeString(&KeyName
,
319 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
321 InitializeObjectAttributes(&ObjectAttributes
,
323 OBJ_CASE_INSENSITIVE
,
326 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
327 if (!NT_SUCCESS(Status
)) goto Quickie
;
329 /* Key opened, now write to the key */
330 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
331 Status
= NtSetValueKey(KeyHandle
,
335 CmpLoadOptions
.Buffer
,
336 CmpLoadOptions
.Length
);
337 if (!NT_SUCCESS(Status
)) goto Quickie
;
339 /* Setup value name for system boot device */
340 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
341 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->NtBootPathName
);
342 Status
= NtSetValueKey(KeyHandle
,
350 /* Free the buffers */
351 RtlFreeUnicodeString(&ValueName
);
353 /* Close the key and return */
356 /* Return the status */
357 return (ExpInTextModeSetup
? STATUS_SUCCESS
: Status
);
362 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
364 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
365 UNICODE_STRING SelectName
=
366 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
367 UNICODE_STRING KeyName
;
368 OBJECT_ATTRIBUTES ObjectAttributes
;
369 CHAR ValueInfoBuffer
[128];
370 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
372 WCHAR UnicodeBuffer
[128];
373 HANDLE SelectHandle
, KeyHandle
, ConfigHandle
= NULL
, ProfileHandle
= NULL
;
374 HANDLE ParentHandle
= NULL
;
375 ULONG ControlSet
, HwProfile
;
376 ANSI_STRING TempString
;
378 ULONG ResultLength
, Disposition
;
379 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
382 /* Open the select key */
383 InitializeObjectAttributes(&ObjectAttributes
,
385 OBJ_CASE_INSENSITIVE
,
388 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
389 if (!NT_SUCCESS(Status
))
391 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
392 if (!LoaderBlock
->RegistryBase
)
394 /* Build the ControlSet001 key */
395 RtlInitUnicodeString(&KeyName
,
396 L
"\\Registry\\Machine\\System\\ControlSet001");
397 InitializeObjectAttributes(&ObjectAttributes
,
399 OBJ_CASE_INSENSITIVE
,
402 Status
= NtCreateKey(&KeyHandle
,
409 if (!NT_SUCCESS(Status
)) return Status
;
411 /* Don't need the handle */
414 /* Use hard-coded setting */
419 /* Fail for real boots */
423 /* Open the current value */
424 RtlInitUnicodeString(&KeyName
, L
"Current");
425 Status
= NtQueryValueKey(SelectHandle
,
427 KeyValueFullInformation
,
429 sizeof(ValueInfoBuffer
),
431 NtClose(SelectHandle
);
432 if (!NT_SUCCESS(Status
)) return Status
;
434 /* Get the actual value pointer, and get the control set ID */
435 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
436 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
438 /* Create the current control set key */
440 RtlInitUnicodeString(&KeyName
,
441 L
"\\Registry\\Machine\\System\\CurrentControlSet");
442 InitializeObjectAttributes(&ObjectAttributes
,
444 OBJ_CASE_INSENSITIVE
,
447 Status
= NtCreateKey(&KeyHandle
,
452 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
454 if (!NT_SUCCESS(Status
)) return Status
;
457 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
459 /* Initialize the symbolic link name */
461 "\\Registry\\Machine\\System\\ControlSet%03ld",
463 RtlInitAnsiString(&TempString
, Buffer
);
465 /* Create a Unicode string out of it */
466 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
467 KeyName
.Buffer
= UnicodeBuffer
;
468 Status
= RtlAnsiStringToUnicodeString(&KeyName
, &TempString
, FALSE
);
471 Status
= NtSetValueKey(KeyHandle
,
472 &CmSymbolicLinkValueName
,
477 if (!NT_SUCCESS(Status
)) return Status
;
479 /* Get the configuration database key */
480 InitializeObjectAttributes(&ObjectAttributes
,
482 OBJ_CASE_INSENSITIVE
,
485 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
488 /* Check if we don't have one */
489 if (!NT_SUCCESS(Status
))
491 /* Cleanup and exit */
496 /* Now get the current config */
497 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
498 Status
= NtQueryValueKey(ConfigHandle
,
500 KeyValueFullInformation
,
502 sizeof(ValueInfoBuffer
),
505 /* Set pointer to buffer */
506 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
508 /* Check if we failed or got a non DWORD-value */
509 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
)) goto Cleanup
;
511 /* Get the hadware profile */
512 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
514 /* Open the hardware profile key */
515 RtlInitUnicodeString(&KeyName
,
516 L
"\\Registry\\Machine\\System\\CurrentControlSet"
517 L
"\\Hardware Profiles");
518 InitializeObjectAttributes(&ObjectAttributes
,
520 OBJ_CASE_INSENSITIVE
,
523 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
524 if (!NT_SUCCESS(Status
))
526 /* Exit and clean up */
531 /* Build the profile name */
532 sprintf(Buffer
, "%04ld", HwProfile
);
533 RtlInitAnsiString(&TempString
, Buffer
);
535 /* Convert it to Unicode */
536 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
537 KeyName
.Buffer
= UnicodeBuffer
;
538 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
541 ASSERT(Status
== STATUS_SUCCESS
);
543 /* Open the associated key */
544 InitializeObjectAttributes(&ObjectAttributes
,
546 OBJ_CASE_INSENSITIVE
,
549 Status
= NtOpenKey(&ProfileHandle
,
550 KEY_READ
| KEY_WRITE
,
552 if (!NT_SUCCESS (Status
))
554 /* Cleanup and exit */
559 /* Check if we have a loader block extension */
560 LoaderExtension
= LoaderBlock
->Extension
;
563 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE
);
566 /* Create the current hardware profile key */
567 RtlInitUnicodeString(&KeyName
,
568 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
569 L
"Hardware Profiles\\Current");
570 InitializeObjectAttributes(&ObjectAttributes
,
572 OBJ_CASE_INSENSITIVE
,
575 Status
= NtCreateKey(&KeyHandle
,
580 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
582 if (NT_SUCCESS(Status
))
585 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
587 /* Create the profile name */
589 "\\Registry\\Machine\\System\\CurrentControlSet\\"
590 "Hardware Profiles\\%04ld",
592 RtlInitAnsiString(&TempString
, Buffer
);
594 /* Convert it to Unicode */
595 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
596 KeyName
.Buffer
= UnicodeBuffer
;
597 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
600 ASSERT(STATUS_SUCCESS
== Status
);
603 Status
= NtSetValueKey(KeyHandle
,
604 &CmSymbolicLinkValueName
,
612 /* Close every opened handle */
614 if (ConfigHandle
) NtClose(ConfigHandle
);
615 if (ProfileHandle
) NtClose(ProfileHandle
);
616 if (ParentHandle
) NtClose(ParentHandle
);
619 return STATUS_SUCCESS
;
624 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName
,
625 IN HANDLE RootDirectory
,
626 IN PCMHIVE RegistryHive
,
628 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
630 OBJECT_ATTRIBUTES ObjectAttributes
;
632 CM_PARSE_CONTEXT ParseContext
= {0};
634 PCM_KEY_BODY KeyBody
;
637 /* Setup the object attributes */
638 InitializeObjectAttributes(&ObjectAttributes
,
640 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
644 /* Setup the parse context */
645 ParseContext
.CreateLink
= TRUE
;
646 ParseContext
.CreateOperation
= TRUE
;
647 ParseContext
.ChildHive
.KeyHive
= &RegistryHive
->Hive
;
649 /* Check if we have a root keycell or if we need to create it */
653 ParseContext
.ChildHive
.KeyCell
= HCELL_NIL
;
658 ParseContext
.ChildHive
.KeyCell
= RegistryHive
->Hive
.BaseBlock
->RootCell
;
661 /* Create the link node */
662 Status
= ObOpenObjectByName(&ObjectAttributes
,
666 KEY_READ
| KEY_WRITE
,
667 (PVOID
)&ParseContext
,
669 if (!NT_SUCCESS(Status
)) return Status
;
671 /* Mark the hive as clean */
672 RegistryHive
->Hive
.DirtyFlag
= FALSE
;
674 /* ReactOS Hack: Keep alive */
675 Status
= ObReferenceObjectByHandle(KeyHandle
,
681 ASSERT(NT_SUCCESS(Status
));
683 /* Close the extra handle */
685 return STATUS_SUCCESS
;
690 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
693 ANSI_STRING LoadString
;
698 UNICODE_STRING KeyName
;
699 PCMHIVE SystemHive
= NULL
;
700 UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
701 PSECURITY_DESCRIPTOR SecurityDescriptor
;
704 /* Setup the ansi string */
705 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
707 /* Allocate the unicode buffer */
708 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
709 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
713 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
716 /* Setup the unicode string */
717 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, (USHORT
)Length
);
719 /* Add the load options and null-terminate */
720 RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
721 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
722 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
724 /* Get the System Hive base address */
725 HiveBase
= LoaderBlock
->RegistryBase
;
729 ((PHBASE_BLOCK
)HiveBase
)->Length
= LoaderBlock
->RegistryLength
;
730 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
740 if (!NT_SUCCESS(Status
)) return FALSE
;
742 /* Set the hive filename */
743 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
744 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
746 /* We imported, no need to create a new hive */
749 /* Manually set the hive as volatile, if in Live CD mode */
750 if (CmpShareSystemHives
) SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
755 Status
= CmpInitializeHive(&SystemHive
,
765 if (!NT_SUCCESS(Status
)) return FALSE
;
767 /* Set the hive filename */
768 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
769 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
771 /* Tell CmpLinkHiveToMaster to allocate a hive */
775 /* Save the boot type */
776 CmpBootType
= SystemHive
->Hive
.BaseBlock
->BootType
;
778 /* Are we in self-healing mode? */
781 /* Disable self-healing internally and check if boot type wanted it */
785 /* We're disabled, so bugcheck */
786 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
,
789 (ULONG_PTR
)SystemHive
,
794 /* Create the default security descriptor */
795 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
797 /* Attach it to the system key */
798 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM");
799 Status
= CmpLinkHiveToMaster(&KeyName
,
805 /* Free the security descriptor */
806 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
807 if (!NT_SUCCESS(Status
)) return FALSE
;
809 /* Add the hive to the hive list */
810 CmpMachineHiveList
[3].CmHive
= (PCMHIVE
)SystemHive
;
818 CmpCreateObjectTypes(VOID
)
820 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
822 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
828 /* Initialize the Key object type */
829 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
830 RtlInitUnicodeString(&Name
, L
"Key");
831 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
832 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
833 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
834 ObjectTypeInitializer
.PoolType
= PagedPool
;
835 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
836 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
837 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
838 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
839 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
840 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
841 ObjectTypeInitializer
.CloseProcedure
= CmpCloseKeyObject
;
842 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
845 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
850 CmpCreateRootNode(IN PHHIVE Hive
,
852 OUT PHCELL_INDEX Index
)
854 UNICODE_STRING KeyName
;
855 PCM_KEY_NODE KeyCell
;
856 LARGE_INTEGER SystemTime
;
859 /* Initialize the node name and allocate it */
860 RtlInitUnicodeString(&KeyName
, Name
);
861 *Index
= HvAllocateCell(Hive
,
862 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
863 CmpNameSize(Hive
, &KeyName
),
866 if (*Index
== HCELL_NIL
) return FALSE
;
868 /* Set the cell index and get the data */
869 Hive
->BaseBlock
->RootCell
= *Index
;
870 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
871 if (!KeyCell
) return FALSE
;
874 KeyCell
->Signature
= (USHORT
)CM_KEY_NODE_SIGNATURE
;
875 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
876 KeQuerySystemTime(&SystemTime
);
877 KeyCell
->LastWriteTime
= SystemTime
;
878 KeyCell
->Parent
= HCELL_NIL
;
879 KeyCell
->SubKeyCounts
[Stable
] = 0;
880 KeyCell
->SubKeyCounts
[Volatile
] = 0;
881 KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
882 KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
883 KeyCell
->ValueList
.Count
= 0;
884 KeyCell
->ValueList
.List
= HCELL_NIL
;
885 KeyCell
->Security
= HCELL_NIL
;
886 KeyCell
->Class
= HCELL_NIL
;
887 KeyCell
->ClassLength
= 0;
888 KeyCell
->MaxNameLen
= 0;
889 KeyCell
->MaxClassLen
= 0;
890 KeyCell
->MaxValueNameLen
= 0;
891 KeyCell
->MaxValueDataLen
= 0;
893 /* Copy the name (this will also set the length) */
894 KeyCell
->NameLength
= CmpCopyName(Hive
, (PWCHAR
)KeyCell
->Name
, &KeyName
);
896 /* Check if the name was compressed */
897 if (KeyCell
->NameLength
< KeyName
.Length
)
900 KeyCell
->Flags
|= KEY_COMP_NAME
;
904 HvReleaseCell(Hive
, *Index
);
910 CmpCreateRegistryRoot(VOID
)
912 UNICODE_STRING KeyName
;
913 OBJECT_ATTRIBUTES ObjectAttributes
;
914 PCM_KEY_BODY RootKey
;
915 HCELL_INDEX RootIndex
;
917 PCM_KEY_NODE KeyCell
;
918 PSECURITY_DESCRIPTOR SecurityDescriptor
;
919 PCM_KEY_CONTROL_BLOCK Kcb
;
922 /* Setup the root node */
923 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
929 /* Create '\Registry' key. */
930 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
931 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
932 InitializeObjectAttributes(&ObjectAttributes
,
934 OBJ_CASE_INSENSITIVE
,
937 Status
= ObCreateObject(KernelMode
,
946 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
947 if (!NT_SUCCESS(Status
)) return FALSE
;
949 /* Sanity check, and get the key cell */
950 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
951 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
952 if (!KeyCell
) return FALSE
;
955 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
956 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
962 if (!Kcb
) return FALSE
;
964 /* Initialize the object */
965 RootKey
->KeyControlBlock
= Kcb
;
966 RootKey
->Type
= '20yk';
967 RootKey
->NotifyBlock
= NULL
;
968 RootKey
->ProcessID
= PsGetCurrentProcessId();
971 EnlistKeyBodyWithKCB(RootKey
, 0);
973 /* Insert the key into the namespace */
974 Status
= ObInsertObject(RootKey
,
979 &CmpRegistryRootHandle
);
980 if (!NT_SUCCESS(Status
)) return FALSE
;
982 /* Reference the key again so that we never lose it */
983 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
989 if (!NT_SUCCESS(Status
)) return FALSE
;
991 /* Completely sucessful */
997 CmpGetRegistryPath(IN PWCHAR ConfigPath
)
999 OBJECT_ATTRIBUTES ObjectAttributes
;
1002 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1003 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1004 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1005 ULONG BufferSize
, ResultSize
;
1007 /* Check if we are booted in setup */
1008 if (ExpInTextModeSetup
)
1010 /* Setup the object attributes */
1011 InitializeObjectAttributes(&ObjectAttributes
,
1013 OBJ_CASE_INSENSITIVE
,
1017 Status
= ZwOpenKey(&KeyHandle
,
1020 if (!NT_SUCCESS(Status
)) return Status
;
1022 /* Allocate the buffer */
1023 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1024 ValueInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_CM
);
1029 return STATUS_INSUFFICIENT_RESOURCES
;
1032 /* Query the value */
1033 Status
= ZwQueryValueKey(KeyHandle
,
1035 KeyValuePartialInformation
,
1040 if (!NT_SUCCESS(Status
))
1043 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1047 /* Copy the config path and null-terminate it */
1048 RtlCopyMemory(ConfigPath
,
1050 ValueInfo
->DataLength
);
1051 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1052 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1056 /* Just use default path */
1057 wcscpy(ConfigPath
, L
"\\SystemRoot");
1060 /* Add registry path */
1061 wcscat(ConfigPath
, L
"\\System32\\Config\\");
1064 return STATUS_SUCCESS
;
1069 CmpLoadHiveThread(IN PVOID StartContext
)
1071 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1072 UNICODE_STRING TempName
, FileName
, RegName
;
1073 ULONG FileStart
, RegStart
, i
, ErrorResponse
, WorkerCount
, Length
;
1074 ULONG PrimaryDisposition
, SecondaryDisposition
, ClusterSize
;
1076 HANDLE PrimaryHandle
, LogHandle
;
1077 NTSTATUS Status
= STATUS_SUCCESS
;
1078 PVOID ErrorParameters
;
1081 /* Get the hive index, make sure it makes sense */
1082 i
= PtrToUlong(StartContext
);
1083 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1085 /* We were started */
1086 CmpMachineHiveList
[i
].ThreadStarted
= TRUE
;
1088 /* Build the file name and registry name strings */
1089 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1090 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1092 /* Now build the system root path */
1093 CmpGetRegistryPath(ConfigPath
);
1094 RtlInitUnicodeString(&TempName
, ConfigPath
);
1095 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1096 FileStart
= FileName
.Length
;
1098 /* And build the registry root path */
1099 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1100 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1101 RegStart
= RegName
.Length
;
1103 /* Build the base name */
1104 RegName
.Length
= RegStart
;
1105 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1106 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1108 /* Check if this is a child of the root */
1109 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1111 /* Then setup the whole name */
1112 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1113 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1116 /* Now add the rest of the file name */
1117 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1118 FileName
.Length
= FileStart
;
1119 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1120 if (!CmpMachineHiveList
[i
].CmHive
)
1122 /* We need to allocate a new hive structure */
1123 CmpMachineHiveList
[i
].Allocate
= TRUE
;
1125 /* Load the hive file */
1126 Status
= CmpInitHiveFromFile(&FileName
,
1127 CmpMachineHiveList
[i
].HHiveFlags
,
1129 &CmpMachineHiveList
[i
].Allocate
,
1131 if (!(NT_SUCCESS(Status
)) ||
1132 (!(CmHive
->FileHandles
[HFILE_TYPE_LOG
]) && !(CmpMiniNTBoot
))) // HACK
1134 /* We failed or couldn't get a log file, raise a hard error */
1135 ErrorParameters
= &FileName
;
1136 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1139 (PULONG_PTR
)&ErrorParameters
,
1144 /* Set the hive flags and newly allocated hive pointer */
1145 CmHive
->Flags
= CmpMachineHiveList
[i
].CmHiveFlags
;
1146 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1150 /* We already have a hive, is it volatile? */
1151 CmHive
= CmpMachineHiveList
[i
].CmHive
;
1152 if (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
1154 /* It's now, open the hive file and log */
1155 Status
= CmpOpenHiveFiles(&FileName
,
1159 &PrimaryDisposition
,
1160 &SecondaryDisposition
,
1165 if (!(NT_SUCCESS(Status
)) || !(LogHandle
))
1167 /* Couldn't open the hive or its log file, raise a hard error */
1168 ErrorParameters
= &FileName
;
1169 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1172 (PULONG_PTR
)&ErrorParameters
,
1176 /* And bugcheck for posterity's sake */
1177 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 0, i
, Status
);
1180 /* Save the file handles. This should remove our sync hacks */
1181 CmHive
->FileHandles
[HFILE_TYPE_LOG
] = LogHandle
;
1182 CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = PrimaryHandle
;
1184 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1185 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1186 CmHive
->Hive
.HiveFlags
&= ~HIVE_NOLAZYFLUSH
;
1188 /* Get the real size of the hive */
1189 Length
= CmHive
->Hive
.Storage
[Stable
].Length
+ HBLOCK_SIZE
;
1191 /* Check if the cluster size doesn't match */
1192 if (CmHive
->Hive
.Cluster
!= ClusterSize
) ASSERT(FALSE
);
1194 /* Set the file size */
1195 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1197 /* This shouldn't fail */
1201 /* Another thing we don't support is NTLDR-recovery */
1202 if (CmHive
->Hive
.BaseBlock
->BootRecover
) ASSERT(FALSE
);
1204 /* Finally, set our allocated hive to the same hive we've had */
1205 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1206 ASSERT(CmpMachineHiveList
[i
].CmHive
== CmpMachineHiveList
[i
].CmHive2
);
1211 CmpMachineHiveList
[i
].ThreadFinished
= TRUE
;
1213 /* Check if we're the last worker */
1214 WorkerCount
= InterlockedIncrement(&CmpLoadWorkerIncrement
);
1215 if (WorkerCount
== CM_NUMBER_OF_MACHINE_HIVES
)
1217 /* Signal the event */
1218 KeSetEvent(&CmpLoadWorkerEvent
, 0, FALSE
);
1221 /* Kill the thread */
1222 PsTerminateSystemThread(Status
);
1227 CmpInitializeHiveList(IN USHORT Flag
)
1229 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1230 UNICODE_STRING TempName
, FileName
, RegName
;
1233 ULONG FileStart
, RegStart
, i
;
1234 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1237 /* Allow writing for now */
1240 /* Build the file name and registry name strings */
1241 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1242 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1244 /* Now build the system root path */
1245 CmpGetRegistryPath(ConfigPath
);
1246 RtlInitUnicodeString(&TempName
, ConfigPath
);
1247 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1248 FileStart
= FileName
.Length
;
1250 /* And build the registry root path */
1251 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1252 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1253 RegStart
= RegName
.Length
;
1255 /* Setup the event to synchronize workers */
1256 KeInitializeEvent(&CmpLoadWorkerEvent
, SynchronizationEvent
, FALSE
);
1258 /* Enter special boot condition */
1259 CmpSpecialBootCondition
= TRUE
;
1261 /* Create the SD for the root hives */
1262 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1264 /* Loop every hive we care about */
1265 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1267 /* Make sure the list is setup */
1268 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1270 /* Create a thread to handle this hive */
1271 Status
= PsCreateSystemThread(&Thread
,
1278 if (NT_SUCCESS(Status
))
1280 /* We don't care about the handle -- the thread self-terminates */
1285 /* Can't imagine this happening */
1286 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 3, i
, Status
);
1290 /* Make sure we've reached the end of the list */
1291 ASSERT(CmpMachineHiveList
[i
].Name
== NULL
);
1293 /* Wait for hive loading to finish */
1294 KeWaitForSingleObject(&CmpLoadWorkerEvent
,
1300 /* Exit the special boot condition and make sure all workers completed */
1301 CmpSpecialBootCondition
= FALSE
;
1302 ASSERT(CmpLoadWorkerIncrement
== CM_NUMBER_OF_MACHINE_HIVES
);
1304 /* Loop hives again */
1305 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1307 /* Make sure the thread ran and finished */
1308 ASSERT(CmpMachineHiveList
[i
].ThreadFinished
== TRUE
);
1309 ASSERT(CmpMachineHiveList
[i
].ThreadStarted
== TRUE
);
1311 /* Check if this was a new hive */
1312 if (!CmpMachineHiveList
[i
].CmHive
)
1314 /* Make sure we allocated something */
1315 ASSERT(CmpMachineHiveList
[i
].CmHive2
!= NULL
);
1317 /* Build the base name */
1318 RegName
.Length
= RegStart
;
1319 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1320 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1322 /* Check if this is a child of the root */
1323 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1325 /* Then setup the whole name */
1326 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1327 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1330 /* Now link the hive to its master */
1331 Status
= CmpLinkHiveToMaster(&RegName
,
1333 CmpMachineHiveList
[i
].CmHive2
,
1334 CmpMachineHiveList
[i
].Allocate
,
1335 SecurityDescriptor
);
1336 if (Status
!= STATUS_SUCCESS
)
1338 /* Linking needs to work */
1339 KeBugCheckEx(CONFIG_LIST_FAILED
, 11, Status
, i
, (ULONG_PTR
)&RegName
);
1342 /* Check if we had to allocate a new hive */
1343 if (CmpMachineHiveList
[i
].Allocate
)
1345 /* Sync the new hive */
1346 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1350 /* Check if we created a new hive */
1351 if (CmpMachineHiveList
[i
].CmHive2
)
1353 /* TODO: Add to HiveList key */
1357 /* Get rid of the SD */
1358 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1360 /* FIXME: Link SECURITY to SAM */
1362 /* FIXME: Link S-1-5-18 to .Default */
1369 OBJECT_ATTRIBUTES ObjectAttributes
;
1370 UNICODE_STRING KeyName
;
1373 PCMHIVE HardwareHive
;
1374 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1377 /* Check if this is PE-boot */
1378 if (InitIsWinPEMode
)
1380 /* Set registry to PE mode */
1381 CmpMiniNTBoot
= TRUE
;
1382 CmpShareSystemHives
= TRUE
;
1385 /* Initialize the hive list and lock */
1386 InitializeListHead(&CmpHiveListHead
);
1387 ExInitializePushLock((PVOID
)&CmpHiveListHeadLock
);
1388 ExInitializePushLock((PVOID
)&CmpLoadHiveLock
);
1390 /* Initialize registry lock */
1391 ExInitializeResourceLite(&CmpRegistryLock
);
1393 /* Initialize the cache */
1394 CmpInitializeCache();
1396 /* Initialize allocation and delayed dereferencing */
1397 CmpInitCmPrivateAlloc();
1398 CmpInitCmPrivateDelayAlloc();
1399 CmpInitDelayDerefKCBEngine();
1401 /* Initialize callbacks */
1404 /* Initialize self healing */
1405 KeInitializeGuardedMutex(&CmpSelfHealQueueLock
);
1406 InitializeListHead(&CmpSelfHealQueueListHead
);
1408 /* Save the current process and lock the registry */
1409 CmpSystemProcess
= PsGetCurrentProcess();
1411 /* Create the key object types */
1412 Status
= CmpCreateObjectTypes();
1413 if (!NT_SUCCESS(Status
))
1416 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 1, Status
, 0);
1419 /* Build the master hive */
1420 Status
= CmpInitializeHive((PCMHIVE
*)&CmiVolatileHive
,
1430 if (!NT_SUCCESS(Status
))
1433 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 2, Status
, 0);
1436 /* Create the \REGISTRY key node */
1437 if (!CmpCreateRegistryRoot())
1440 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 3, 0, 0);
1443 /* Create the default security descriptor */
1444 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1446 /* Create '\Registry\Machine' key. */
1447 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE");
1448 InitializeObjectAttributes(&ObjectAttributes
,
1450 OBJ_CASE_INSENSITIVE
,
1452 SecurityDescriptor
);
1453 Status
= NtCreateKey(&KeyHandle
,
1454 KEY_READ
| KEY_WRITE
,
1460 if (!NT_SUCCESS(Status
))
1463 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 5, Status
, 0);
1466 /* Close the handle */
1469 /* Create '\Registry\User' key. */
1470 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\USER");
1471 InitializeObjectAttributes(&ObjectAttributes
,
1473 OBJ_CASE_INSENSITIVE
,
1475 SecurityDescriptor
);
1476 Status
= NtCreateKey(&KeyHandle
,
1477 KEY_READ
| KEY_WRITE
,
1483 if (!NT_SUCCESS(Status
))
1486 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 6, Status
, 0);
1489 /* Close the handle */
1492 /* Initialize the system hive */
1493 if (!CmpInitializeSystemHive(KeLoaderBlock
))
1496 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 7, 0, 0);
1499 /* Create the 'CurrentControlSet' link. */
1500 Status
= CmpCreateControlSet(KeLoaderBlock
);
1501 if (!NT_SUCCESS(Status
))
1504 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 8, Status
, 0);
1507 /* Create the hardware hive */
1508 Status
= CmpInitializeHive((PCMHIVE
*)&HardwareHive
,
1518 if (!NT_SUCCESS(Status
))
1521 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 11, Status
, 0);
1524 /* Add the hive to the hive list */
1525 CmpMachineHiveList
[0].CmHive
= (PCMHIVE
)HardwareHive
;
1527 /* Attach it to the machine key */
1528 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE");
1529 Status
= CmpLinkHiveToMaster(&KeyName
,
1531 (PCMHIVE
)HardwareHive
,
1533 SecurityDescriptor
);
1534 if (!NT_SUCCESS(Status
))
1537 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 12, Status
, 0);
1540 /* FIXME: Add to HiveList key */
1542 /* Free the security descriptor */
1543 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1545 /* Fill out the Hardware key with the ARC Data from the Loader */
1546 Status
= CmpInitializeHardwareConfiguration(KeLoaderBlock
);
1547 if (!NT_SUCCESS(Status
))
1550 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 13, Status
, 0);
1553 /* Initialize machine-dependent information into the registry */
1554 Status
= CmpInitializeMachineDependentConfiguration(KeLoaderBlock
);
1555 if (!NT_SUCCESS(Status
))
1558 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 14, Status
, 0);
1561 /* Initialize volatile registry settings */
1562 Status
= CmpSetSystemValues(KeLoaderBlock
);
1563 if (!NT_SUCCESS(Status
))
1566 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 15, Status
, 0);
1569 /* Free the load options */
1570 ExFreePoolWithTag(CmpLoadOptions
.Buffer
, TAG_CM
);
1572 /* If we got here, all went well */
1578 CmpLockRegistryExclusive(VOID
)
1580 /* Enter a critical region and lock the registry */
1581 KeEnterCriticalRegion();
1582 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1585 ASSERT(CmpFlushStarveWriters
== 0);
1586 RtlGetCallersAddress(&CmpRegistryLockCaller
, &CmpRegistryLockCallerCaller
);
1591 CmpLockRegistry(VOID
)
1593 /* Enter a critical region */
1594 KeEnterCriticalRegion();
1596 /* Check if we have to starve writers */
1597 if (CmpFlushStarveWriters
)
1599 /* Starve exlusive waiters */
1600 ExAcquireSharedStarveExclusive(&CmpRegistryLock
, TRUE
);
1604 /* Just grab the lock */
1605 ExAcquireResourceSharedLite(&CmpRegistryLock
, TRUE
);
1611 CmpTestRegistryLock(VOID
)
1614 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1619 CmpTestRegistryLockExclusive(VOID
)
1622 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1627 CmpUnlockRegistry(VOID
)
1630 CMP_ASSERT_REGISTRY_LOCK();
1632 /* Check if we should flush the registry */
1633 if (CmpFlushOnLockRelease
)
1635 /* The registry should be exclusively locked for this */
1636 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1638 /* Flush the registry */
1639 CmpDoFlushAll(TRUE
);
1640 CmpFlushOnLockRelease
= FALSE
;
1643 /* Release the lock and leave the critical region */
1644 ExReleaseResourceLite(&CmpRegistryLock
);
1645 KeLeaveCriticalRegion();
1650 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1
,
1653 ULONG Index1
, Index2
;
1656 CMP_ASSERT_REGISTRY_LOCK();
1658 /* Get hash indexes */
1659 Index1
= GET_HASH_INDEX(ConvKey1
);
1660 Index2
= GET_HASH_INDEX(ConvKey2
);
1662 /* See which one is highest */
1663 if (Index1
< Index2
)
1665 /* Grab them in the proper order */
1666 CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1667 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1671 /* Grab the second one first, then the first */
1672 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1673 if (Index1
!= Index2
) CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1679 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1
,
1682 ULONG Index1
, Index2
;
1685 CMP_ASSERT_REGISTRY_LOCK();
1687 /* Get hash indexes */
1688 Index1
= GET_HASH_INDEX(ConvKey1
);
1689 Index2
= GET_HASH_INDEX(ConvKey2
);
1690 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey2
).Owner
== KeGetCurrentThread()) ||
1691 (CmpTestRegistryLockExclusive()));
1693 /* See which one is highest */
1694 if (Index1
< Index2
)
1696 /* Grab them in the proper order */
1697 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1698 (CmpTestRegistryLockExclusive()));
1699 CmpReleaseKcbLockByKey(ConvKey2
);
1700 CmpReleaseKcbLockByKey(ConvKey1
);
1704 /* Release the first one first, then the second */
1705 if (Index1
!= Index2
)
1707 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1708 (CmpTestRegistryLockExclusive()));
1709 CmpReleaseKcbLockByKey(ConvKey1
);
1711 CmpReleaseKcbLockByKey(ConvKey2
);
1717 CmShutdownSystem(VOID
)
1719 /* Kill the workers and flush all hives */
1720 if (!CmFirstTime
) CmpShutdownWorkers();
1721 CmpDoFlushAll(TRUE
);