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 ******************************************************************/
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 CmpFlushStarveWriters
;
28 BOOLEAN CmpFlushOnLockRelease
;
29 BOOLEAN CmpSpecialBootCondition
;
31 BOOLEAN CmpForceForceFlush
;
32 BOOLEAN CmpWasSetupBoot
;
34 /* FUNCTIONS *****************************************************************/
38 CmpRosGetHardwareHive(OUT PULONG Length
)
40 PLIST_ENTRY ListHead
, NextEntry
;
41 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
= NULL
;
43 /* Loop the memory descriptors */
44 ListHead
= &KeLoaderBlock
->MemoryDescriptorListHead
;
45 NextEntry
= ListHead
->Flink
;
46 while (NextEntry
!= ListHead
)
48 /* Get the current block */
49 MdBlock
= CONTAINING_RECORD(NextEntry
,
50 MEMORY_ALLOCATION_DESCRIPTOR
,
53 /* Check if this is an registry block */
54 if (MdBlock
->MemoryType
== LoaderRegistryData
)
56 /* Check if it's not the SYSTEM hive that we already initialized */
57 if ((MdBlock
->BasePage
) !=
58 (((ULONG_PTR
)KeLoaderBlock
->RegistryBase
&~ KSEG0_BASE
) >> PAGE_SHIFT
))
60 /* Hardware hive break out */
65 /* Go to the next block */
66 NextEntry
= MdBlock
->ListEntry
.Flink
;
69 /* We need a hardware hive */
71 *Length
= MdBlock
->PageCount
<< PAGE_SHIFT
;
72 return (PVOID
)((MdBlock
->BasePage
<< PAGE_SHIFT
) | KSEG0_BASE
);
77 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName
,
83 ULONG HiveDisposition
, LogDisposition
;
84 HANDLE FileHandle
= NULL
, LogHandle
= NULL
;
86 ULONG Operation
, FileType
;
93 /* Open or create the hive files */
94 Status
= CmpOpenHiveFiles(HiveName
,
104 if (!NT_SUCCESS(Status
)) return Status
;
106 /* Check if we have a log handle */
107 FileType
= (LogHandle
) ? HFILE_TYPE_LOG
: HFILE_TYPE_PRIMARY
;
109 /* Check if we created or opened the hive */
110 if (HiveDisposition
== FILE_CREATED
)
112 /* Do a create operation */
113 Operation
= HINIT_CREATE
;
118 /* Open it as a file */
119 Operation
= HINIT_FILE
;
123 /* Check if we're sharing hives */
124 if (CmpShareSystemHives
)
126 /* Then force using the primary hive */
127 FileType
= HFILE_TYPE_PRIMARY
;
130 /* Get rid of the log handle */
136 /* Check if we're too late */
137 if (HvShutdownComplete
)
141 if (LogHandle
) ZwClose(LogHandle
);
142 return STATUS_TOO_LATE
;
145 /* Initialize the hive */
146 Status
= CmpInitializeHive((PCMHIVE
*)&NewHive
,
156 if (!NT_SUCCESS(Status
))
160 if (LogHandle
) ZwClose(LogHandle
);
164 /* Success, return hive */
167 /* ROS: Init root key cell and prepare the hive */
168 if (Operation
== HINIT_CREATE
) CmCreateRootNode(&NewHive
->Hive
, L
"");
169 CmPrepareHive(&NewHive
->Hive
);
171 /* Duplicate the hive name */
172 NewHive
->FileFullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
175 if (NewHive
->FileFullPath
.Buffer
)
177 /* Copy the string */
178 RtlCopyMemory(NewHive
->FileFullPath
.Buffer
,
181 NewHive
->FileFullPath
.Length
= HiveName
->Length
;
182 NewHive
->FileFullPath
.MaximumLength
= HiveName
->MaximumLength
;
186 return STATUS_SUCCESS
;
191 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
193 OBJECT_ATTRIBUTES ObjectAttributes
;
194 UNICODE_STRING KeyName
, ValueName
= {0};
197 ASSERT(LoaderBlock
!= NULL
);
199 /* Setup attributes for loader options */
200 RtlInitUnicodeString(&KeyName
,
201 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
203 InitializeObjectAttributes(&ObjectAttributes
,
205 OBJ_CASE_INSENSITIVE
,
208 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
209 if (!NT_SUCCESS(Status
)) goto Quickie
;
211 /* Key opened, now write to the key */
212 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
213 Status
= NtSetValueKey(KeyHandle
,
217 CmpLoadOptions
.Buffer
,
218 CmpLoadOptions
.Length
);
219 if (!NT_SUCCESS(Status
)) goto Quickie
;
221 /* Setup value name for system boot device */
222 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
223 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->NtBootPathName
);
224 Status
= NtSetValueKey(KeyHandle
,
232 /* Free the buffers */
233 RtlFreeUnicodeString(&ValueName
);
235 /* Close the key and return */
238 /* Return the status */
239 return (ExpInTextModeSetup
? STATUS_SUCCESS
: Status
);
244 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
246 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
247 UNICODE_STRING SelectName
=
248 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
249 UNICODE_STRING KeyName
;
250 OBJECT_ATTRIBUTES ObjectAttributes
;
251 CHAR ValueInfoBuffer
[128];
252 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
254 WCHAR UnicodeBuffer
[128];
255 HANDLE SelectHandle
, KeyHandle
, ConfigHandle
= NULL
, ProfileHandle
= NULL
;
256 HANDLE ParentHandle
= NULL
;
257 ULONG ControlSet
, HwProfile
;
258 ANSI_STRING TempString
;
260 ULONG ResultLength
, Disposition
;
261 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
264 /* Open the select key */
265 InitializeObjectAttributes(&ObjectAttributes
,
267 OBJ_CASE_INSENSITIVE
,
270 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
271 if (!NT_SUCCESS(Status
))
273 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
274 if (!LoaderBlock
->RegistryBase
)
276 /* Use hard-coded setting */
281 /* Fail for real boots */
285 /* Open the current value */
286 RtlInitUnicodeString(&KeyName
, L
"Current");
287 Status
= NtQueryValueKey(SelectHandle
,
289 KeyValueFullInformation
,
291 sizeof(ValueInfoBuffer
),
293 NtClose(SelectHandle
);
294 if (!NT_SUCCESS(Status
)) return Status
;
296 /* Get the actual value pointer, and get the control set ID */
297 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
298 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
300 /* Create the current control set key */
302 RtlInitUnicodeString(&KeyName
,
303 L
"\\Registry\\Machine\\System\\CurrentControlSet");
304 InitializeObjectAttributes(&ObjectAttributes
,
306 OBJ_CASE_INSENSITIVE
,
310 Status
= NtCreateKey(&KeyHandle
,
315 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
317 if (!NT_SUCCESS(Status
)) return Status
;
320 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
322 /* Initialize the symbolic link name */
324 "\\Registry\\Machine\\System\\ControlSet%03ld",
326 RtlInitAnsiString(&TempString
, Buffer
);
328 /* Create a Unicode string out of it */
329 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
330 KeyName
.Buffer
= UnicodeBuffer
;
331 Status
= RtlAnsiStringToUnicodeString(&KeyName
, &TempString
, FALSE
);
334 Status
= NtSetValueKey(KeyHandle
,
335 &CmSymbolicLinkValueName
,
340 if (!NT_SUCCESS(Status
)) return Status
;
342 /* Get the configuration database key */
343 InitializeObjectAttributes(&ObjectAttributes
,
345 OBJ_CASE_INSENSITIVE
,
348 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
351 /* Check if we don't have one */
352 if (!NT_SUCCESS(Status
))
354 /* Cleanup and exit */
359 /* Now get the current config */
360 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
361 Status
= NtQueryValueKey(ConfigHandle
,
363 KeyValueFullInformation
,
365 sizeof(ValueInfoBuffer
),
368 /* Set pointer to buffer */
369 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
371 /* Check if we failed or got a non DWORD-value */
372 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
)) goto Cleanup
;
374 /* Get the hadware profile */
375 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
377 /* Open the hardware profile key */
378 RtlInitUnicodeString(&KeyName
,
379 L
"\\Registry\\Machine\\System\\CurrentControlSet"
380 L
"\\Hardware Profiles");
381 InitializeObjectAttributes(&ObjectAttributes
,
383 OBJ_CASE_INSENSITIVE
,
386 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
387 if (!NT_SUCCESS(Status
))
389 /* Exit and clean up */
394 /* Build the profile name */
395 sprintf(Buffer
, "%04ld", HwProfile
);
396 RtlInitAnsiString(&TempString
, Buffer
);
398 /* Convert it to Unicode */
399 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
400 KeyName
.Buffer
= UnicodeBuffer
;
401 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
404 ASSERT(Status
== STATUS_SUCCESS
);
406 /* Open the associated key */
407 InitializeObjectAttributes(&ObjectAttributes
,
409 OBJ_CASE_INSENSITIVE
,
412 Status
= NtOpenKey(&ProfileHandle
,
413 KEY_READ
| KEY_WRITE
,
415 if (!NT_SUCCESS (Status
))
417 /* Cleanup and exit */
422 /* Check if we have a loader block extension */
423 LoaderExtension
= LoaderBlock
->Extension
;
426 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE
);
429 /* Create the current hardware profile key */
430 RtlInitUnicodeString(&KeyName
,
431 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
432 L
"Hardware Profiles\\Current");
433 InitializeObjectAttributes(&ObjectAttributes
,
435 OBJ_CASE_INSENSITIVE
,
438 Status
= NtCreateKey(&KeyHandle
,
443 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
445 if (NT_SUCCESS(Status
))
448 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
450 /* Create the profile name */
452 "\\Registry\\Machine\\System\\CurrentControlSet\\"
453 "Hardware Profiles\\%04ld",
455 RtlInitAnsiString(&TempString
, Buffer
);
457 /* Convert it to Unicode */
458 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
459 KeyName
.Buffer
= UnicodeBuffer
;
460 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
463 ASSERT(STATUS_SUCCESS
== Status
);
466 Status
= NtSetValueKey(KeyHandle
,
467 &CmSymbolicLinkValueName
,
475 /* Close every opened handle */
477 if (ConfigHandle
) NtClose(ConfigHandle
);
478 if (ProfileHandle
) NtClose(ProfileHandle
);
479 if (ParentHandle
) NtClose(ParentHandle
);
482 return STATUS_SUCCESS
;
487 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName
,
488 IN HANDLE RootDirectory
,
489 IN PCMHIVE RegistryHive
,
491 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
493 OBJECT_ATTRIBUTES ObjectAttributes
;
494 UNICODE_STRING RemainingPath
;
495 PKEY_OBJECT ParentKey
;
498 UNICODE_STRING ObjectName
;
499 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
500 CM_PARSE_CONTEXT ParseContext
= {0};
504 /* Setup the object attributes */
505 InitializeObjectAttributes(&ObjectAttributes
,
507 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
511 /* Setup the parse context */
512 ParseContext
.CreateLink
= TRUE
;
513 ParseContext
.CreateOperation
= TRUE
;
514 ParseContext
.ChildHive
.KeyHive
= &RegistryHive
->Hive
;
516 /* Check if we have a root keycell or if we need to create it */
520 ParseContext
.ChildHive
.KeyCell
= HCELL_NIL
;
525 ParseContext
.ChildHive
.KeyCell
= RegistryHive
->Hive
.BaseBlock
->RootCell
;
528 /* Create the link node */
529 Status
= ObOpenObjectByName(&ObjectAttributes
,
533 KEY_READ
| KEY_WRITE
,
534 (PVOID
)&ParseContext
,
537 /* Capture all the info */
538 Status
= ObpCaptureObjectAttributes(&ObjectAttributes
,
543 if (!NT_SUCCESS(Status
)) return Status
;
546 Status
= CmFindObject(&ObjectCreateInfo
,
554 /* Let go of captured attributes and name */
555 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
556 if (ObjectName
.Buffer
) ObpFreeObjectNameBuffer(&ObjectName
);
558 /* Get out of here if we failed */
559 if (!NT_SUCCESS(Status
)) return Status
;
561 /* Scan for no name */
562 if (!(RemainingPath
.Length
) || (RemainingPath
.Buffer
[0] == UNICODE_NULL
))
565 ObDereferenceObject(ParentKey
);
566 return STATUS_OBJECT_NAME_NOT_FOUND
;
569 /* Scan for leading backslash */
570 while ((RemainingPath
.Length
) &&
571 (*RemainingPath
.Buffer
== OBJ_NAME_PATH_SEPARATOR
))
574 RemainingPath
.Length
-= sizeof(WCHAR
);
575 RemainingPath
.MaximumLength
-= sizeof(WCHAR
);
576 RemainingPath
.Buffer
++;
579 /* Create the link node */
580 Status
= CmpCreateLinkNode(ParentKey
->KeyControlBlock
->KeyHive
,
581 ParentKey
->KeyControlBlock
->KeyCell
,
587 ParentKey
->KeyControlBlock
,
589 if (!NT_SUCCESS(Status
))
592 DPRINT1("CmpLinkHiveToMaster failed: %lx\n", Status
);
593 ObDereferenceObject(ParentKey
);
597 /* Free the create information */
598 ObpFreeAndReleaseCapturedAttributes(OBJECT_TO_OBJECT_HEADER(NewKey
)->ObjectCreateInfo
);
599 OBJECT_TO_OBJECT_HEADER(NewKey
)->ObjectCreateInfo
= NULL
;
601 /* Mark the hive as clean */
602 RegistryHive
->Hive
.DirtyFlag
= FALSE
;
604 /* Update KCB information */
605 NewKey
->KeyControlBlock
->KeyCell
= RegistryHive
->Hive
.BaseBlock
->RootCell
;
606 NewKey
->KeyControlBlock
->KeyHive
= &RegistryHive
->Hive
;
608 /* Build the key name */
609 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
613 /* Reference the new key */
614 ObReferenceObject(NewKey
);
616 /* Link this key to the parent */
617 InsertTailList(&ParentKey
->KeyControlBlock
->KeyBodyListHead
, &NewKey
->KeyBodyEntry
);
618 return STATUS_SUCCESS
;
623 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
626 ANSI_STRING LoadString
;
631 UNICODE_STRING KeyName
;
632 PCMHIVE SystemHive
= NULL
;
633 UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
634 PSECURITY_DESCRIPTOR SecurityDescriptor
;
637 /* Setup the ansi string */
638 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
640 /* Allocate the unicode buffer */
641 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
642 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
646 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
649 /* Setup the unicode string */
650 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, (USHORT
)Length
);
652 /* Add the load options and null-terminate */
653 RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
654 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
655 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
657 /* Get the System Hive base address */
658 HiveBase
= LoaderBlock
->RegistryBase
;
662 ((PHBASE_BLOCK
)HiveBase
)->Length
= LoaderBlock
->RegistryLength
;
663 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
673 if (!NT_SUCCESS(Status
)) return FALSE
;
674 CmPrepareHive(&SystemHive
->Hive
);
676 /* Set the hive filename */
677 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
678 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
680 /* We imported, no need to create a new hive */
683 /* Manually set the hive as volatile, if in Live CD mode */
684 if (CmpShareSystemHives
) SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
689 Status
= CmpInitializeHive(&SystemHive
,
699 if (!NT_SUCCESS(Status
)) return FALSE
;
701 /* Set the hive filename */
702 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
703 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
705 /* Tell CmpLinkHiveToMaster to allocate a hive */
709 /* Save the boot type */
710 if (SystemHive
) CmpBootType
= SystemHive
->Hive
.BaseBlock
->BootType
;
712 /* Are we in self-healing mode? */
715 /* Disable self-healing internally and check if boot type wanted it */
719 /* We're disabled, so bugcheck */
720 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO
,
723 (ULONG_PTR
)SystemHive
,
728 /* Create the default security descriptor */
729 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
731 /* Attach it to the system key */
732 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM");
733 Status
= CmpLinkHiveToMaster(&KeyName
,
739 /* Free the security descriptor */
740 ExFreePool(SecurityDescriptor
);
741 if (!NT_SUCCESS(Status
)) return FALSE
;
743 /* Add the hive to the hive list */
744 CmpMachineHiveList
[3].CmHive
= (PCMHIVE
)SystemHive
;
752 CmpCreateObjectTypes(VOID
)
754 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
756 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
762 /* Initialize the Key object type */
763 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
764 RtlInitUnicodeString(&Name
, L
"Key");
765 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
766 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
767 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
768 ObjectTypeInitializer
.PoolType
= PagedPool
;
769 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
770 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
771 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
772 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
773 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
774 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
775 //ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
776 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
779 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
784 CmpCreateRootNode(IN PHHIVE Hive
,
786 OUT PHCELL_INDEX Index
)
788 UNICODE_STRING KeyName
;
789 PCM_KEY_NODE KeyCell
;
790 LARGE_INTEGER SystemTime
;
793 /* Initialize the node name and allocate it */
794 RtlInitUnicodeString(&KeyName
, Name
);
795 *Index
= HvAllocateCell(Hive
,
796 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
797 CmpNameSize(Hive
, &KeyName
),
800 if (*Index
== HCELL_NIL
) return FALSE
;
802 /* Set the cell index and get the data */
803 Hive
->BaseBlock
->RootCell
= *Index
;
804 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
805 if (!KeyCell
) return FALSE
;
808 KeyCell
->Signature
= (USHORT
)CM_KEY_NODE_SIGNATURE
;
809 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
810 KeQuerySystemTime(&SystemTime
);
811 KeyCell
->LastWriteTime
= SystemTime
;
812 KeyCell
->Parent
= HCELL_NIL
;
813 KeyCell
->SubKeyCounts
[Stable
] = 0;
814 KeyCell
->SubKeyCounts
[Volatile
] = 0;
815 KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
816 KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
817 KeyCell
->ValueList
.Count
= 0;
818 KeyCell
->ValueList
.List
= HCELL_NIL
;
819 KeyCell
->Security
= HCELL_NIL
;
820 KeyCell
->Class
= HCELL_NIL
;
821 KeyCell
->ClassLength
= 0;
822 KeyCell
->MaxNameLen
= 0;
823 KeyCell
->MaxClassLen
= 0;
824 KeyCell
->MaxValueNameLen
= 0;
825 KeyCell
->MaxValueDataLen
= 0;
827 /* Copy the name (this will also set the length) */
828 KeyCell
->NameLength
= CmpCopyName(Hive
, (PWCHAR
)KeyCell
->Name
, &KeyName
);
830 /* Check if the name was compressed */
831 if (KeyCell
->NameLength
< KeyName
.Length
)
834 KeyCell
->Flags
|= KEY_COMP_NAME
;
838 HvReleaseCell(Hive
, *Index
);
844 CmpCreateRegistryRoot(VOID
)
846 UNICODE_STRING KeyName
;
847 OBJECT_ATTRIBUTES ObjectAttributes
;
849 PCM_KEY_BODY RootKey
;
853 HCELL_INDEX RootIndex
;
855 PCM_KEY_NODE KeyCell
;
856 PSECURITY_DESCRIPTOR SecurityDescriptor
;
857 PCM_KEY_CONTROL_BLOCK Kcb
;
860 /* Setup the root node */
861 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
867 /* Create '\Registry' key. */
868 RtlInitUnicodeString(&KeyName
, L
"\\Registry");
869 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
870 InitializeObjectAttributes(&ObjectAttributes
,
872 OBJ_CASE_INSENSITIVE
,
875 Status
= ObCreateObject(KernelMode
,
884 ExFreePool(SecurityDescriptor
);
885 if (!NT_SUCCESS(Status
)) return FALSE
;
887 /* Sanity check, and get the key cell */
888 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
889 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
890 if (!KeyCell
) return FALSE
;
893 RtlInitUnicodeString(&KeyName
, L
"Registry");
894 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
900 if (!Kcb
) return FALSE
;
902 /* Initialize the object */
903 RootKey
->Type
= TAG('k', 'v', '0', '2');
904 RootKey
->KeyControlBlock
= Kcb
;
906 RootKey
->NotifyBlock
= NULL
;
907 RootKey
->ProcessID
= PsGetCurrentProcessId();
909 RtlpCreateUnicodeString(&RootKey
->Name
, L
"Registry", NonPagedPool
);
912 /* Insert the key into the namespace */
913 Status
= ObInsertObject(RootKey
,
918 &CmpRegistryRootHandle
);
919 if (!NT_SUCCESS(Status
)) return FALSE
;
921 /* Reference the key again so that we never lose it */
922 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
928 if (!NT_SUCCESS(Status
)) return FALSE
;
930 /* Completely sucessful */
936 CmpGetRegistryPath(IN PWCHAR ConfigPath
)
938 OBJECT_ATTRIBUTES ObjectAttributes
;
941 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
942 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
943 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
944 ULONG BufferSize
,ResultSize
;
946 /* Check if we are booted in setup */
947 if (ExpInTextModeSetup
)
949 /* Setup the object attributes */
950 InitializeObjectAttributes(&ObjectAttributes
,
952 OBJ_CASE_INSENSITIVE
,
956 Status
= ZwOpenKey(&KeyHandle
,
959 if (!NT_SUCCESS(Status
)) return Status
;
961 /* Allocate the buffer */
962 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
963 ValueInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_CM
);
968 return STATUS_INSUFFICIENT_RESOURCES
;
971 /* Query the value */
972 Status
= ZwQueryValueKey(KeyHandle
,
974 KeyValuePartialInformation
,
979 if (!NT_SUCCESS(Status
))
982 ExFreePool(ValueInfo
);
986 /* Copy the config path and null-terminate it */
987 RtlCopyMemory(ConfigPath
,
989 ValueInfo
->DataLength
);
990 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
991 ExFreePool(ValueInfo
);
995 /* Just use default path */
996 wcscpy(ConfigPath
, L
"\\SystemRoot");
999 /* Add registry path */
1000 wcscat(ConfigPath
, L
"\\System32\\Config\\");
1003 return STATUS_SUCCESS
;
1008 CmpLoadHiveThread(IN PVOID StartContext
)
1010 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1011 UNICODE_STRING TempName
, FileName
, RegName
;
1012 ULONG FileStart
, RegStart
, i
, ErrorResponse
, WorkerCount
, Length
;
1013 ULONG PrimaryDisposition
, SecondaryDisposition
, ClusterSize
;
1015 HANDLE PrimaryHandle
, LogHandle
;
1016 NTSTATUS Status
= STATUS_SUCCESS
;
1017 PVOID ErrorParameters
;
1020 /* Get the hive index, make sure it makes sense */
1021 i
= (ULONG
)StartContext
;
1022 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1023 DPRINT1("[HiveLoad] Parallel Thread: %d\n", i
);
1025 /* We were started */
1026 CmpMachineHiveList
[i
].ThreadStarted
= TRUE
;
1028 /* Build the file name and registry name strings */
1029 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1030 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1032 /* Now build the system root path */
1033 CmpGetRegistryPath(ConfigPath
);
1034 RtlInitUnicodeString(&TempName
, ConfigPath
);
1035 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1036 FileStart
= FileName
.Length
;
1038 /* And build the registry root path */
1039 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1040 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1041 RegStart
= RegName
.Length
;
1043 /* Build the base name */
1044 RegName
.Length
= RegStart
;
1045 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1046 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1048 /* Check if this is a child of the root */
1049 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1051 /* Then setup the whole name */
1052 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1053 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1056 /* Now Add tge rest if the file name */
1057 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1058 FileName
.Length
= FileStart
;
1059 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1060 if (!CmpMachineHiveList
[i
].CmHive
)
1062 /* We need to allocate a new hive structure */
1063 CmpMachineHiveList
[i
].Allocate
= TRUE
;
1065 /* Load the hive file */
1066 DPRINT1("[HiveLoad]: Load from file %wZ\n", &FileName
);
1067 Status
= CmpInitHiveFromFile(&FileName
,
1068 CmpMachineHiveList
[i
].HHiveFlags
,
1070 &CmpMachineHiveList
[i
].Allocate
,
1072 if (!(NT_SUCCESS(Status
)) || !(CmHive
->FileHandles
[HFILE_TYPE_LOG
]))
1074 /* We failed or couldn't get a log file, raise a hard error */
1075 ErrorParameters
= &FileName
;
1076 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1079 (PULONG_PTR
)&ErrorParameters
,
1084 /* Set the hive flags and newly allocated hive pointer */
1085 CmHive
->Flags
= CmpMachineHiveList
[i
].CmHiveFlags
;
1086 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1090 CmHive
= CmpMachineHiveList
[i
].CmHive
;
1091 /* We already have a hive, is it volatile? */
1092 if (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
1094 DPRINT1("[HiveLoad]: Open from file %wZ\n", &FileName
);
1096 /* It's now, open the hive file and log */
1097 Status
= CmpOpenHiveFiles(&FileName
,
1101 &PrimaryDisposition
,
1102 &SecondaryDisposition
,
1107 if (!(NT_SUCCESS(Status
)) || !(LogHandle
))
1109 /* Couldn't open the hive or its log file, raise a hard error */
1110 ErrorParameters
= &FileName
;
1111 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1114 (PULONG_PTR
)&ErrorParameters
,
1118 /* And bugcheck for posterity's sake */
1119 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 0, i
, Status
);
1122 /* Save the file handles. This should remove our sync hacks */
1123 CmHive
->FileHandles
[HFILE_TYPE_LOG
] = LogHandle
;
1124 CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = PrimaryHandle
;
1126 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1127 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1128 CmHive
->Hive
.HiveFlags
&= ~HIVE_NOLAZYFLUSH
;
1130 /* Get the real size of the hive */
1131 Length
= CmHive
->Hive
.Storage
[Stable
].Length
+ HBLOCK_SIZE
;
1133 /* Check if the cluster size doesn't match */
1134 if (CmHive
->Hive
.Cluster
!= ClusterSize
) ASSERT(FALSE
);
1136 /* Set the file size */
1137 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1139 /* This shouldn't fail */
1143 /* Another thing we don't support is NTLDR-recovery */
1144 if (CmHive
->Hive
.BaseBlock
->BootRecover
) ASSERT(FALSE
);
1146 /* Finally, set our allocated hive to the same hive we've had */
1147 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1148 ASSERT(CmpMachineHiveList
[i
].CmHive
== CmpMachineHiveList
[i
].CmHive2
);
1153 CmpMachineHiveList
[i
].ThreadFinished
= TRUE
;
1155 /* Check if we're the last worker */
1156 WorkerCount
= InterlockedIncrement(&CmpLoadWorkerIncrement
);
1157 if (WorkerCount
== CM_NUMBER_OF_MACHINE_HIVES
)
1159 /* Signal the event */
1160 KeSetEvent(&CmpLoadWorkerEvent
, 0, FALSE
);
1163 /* Kill the thread */
1164 PsTerminateSystemThread(Status
);
1169 CmpInitializeHiveList(IN USHORT Flag
)
1171 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1172 UNICODE_STRING TempName
, FileName
, RegName
;
1175 ULONG FileStart
, RegStart
, i
;
1176 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1179 /* Allow writing for now */
1182 /* Build the file name and registry name strings */
1183 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1184 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1186 /* Now build the system root path */
1187 CmpGetRegistryPath(ConfigPath
);
1188 RtlInitUnicodeString(&TempName
, ConfigPath
);
1189 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1190 FileStart
= FileName
.Length
;
1192 /* And build the registry root path */
1193 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1194 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1195 RegStart
= RegName
.Length
;
1197 /* Setup the event to synchronize workers */
1198 KeInitializeEvent(&CmpLoadWorkerEvent
, SynchronizationEvent
, FALSE
);
1200 /* Enter special boot condition */
1201 CmpSpecialBootCondition
= TRUE
;
1203 /* Create the SD for the root hives */
1204 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1206 /* Loop every hive we care about */
1207 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1209 /* Make sure the list is setup */
1210 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1212 /* Create a thread to handle this hive */
1213 Status
= PsCreateSystemThread(&Thread
,
1220 if (NT_SUCCESS(Status
))
1222 /* We don't care about the handle -- the thread self-terminates */
1227 /* Can't imagine this happening */
1228 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 3, i
, Status
);
1232 /* Make sure we've reached the end of the list */
1233 ASSERT(CmpMachineHiveList
[i
].Name
== NULL
);
1235 /* Wait for hive loading to finish */
1236 KeWaitForSingleObject(&CmpLoadWorkerEvent
,
1242 /* Exit the special boot condition and make sure all workers completed */
1243 CmpSpecialBootCondition
= FALSE
;
1244 ASSERT(CmpLoadWorkerIncrement
== CM_NUMBER_OF_MACHINE_HIVES
);
1246 /* Loop hives again */
1247 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1249 /* Make sure the thread ran and finished */
1250 ASSERT(CmpMachineHiveList
[i
].ThreadFinished
== TRUE
);
1251 ASSERT(CmpMachineHiveList
[i
].ThreadStarted
== TRUE
);
1253 /* Check if this was a new hive */
1254 if (!CmpMachineHiveList
[i
].CmHive
)
1256 /* Make sure we allocated something */
1257 ASSERT(CmpMachineHiveList
[i
].CmHive2
!= NULL
);
1259 /* Build the base name */
1260 RegName
.Length
= RegStart
;
1261 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1262 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1264 /* Check if this is a child of the root */
1265 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1267 /* Then setup the whole name */
1268 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1269 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1272 /* Now link the hive to its master */
1273 DPRINT1("[HiveLoad]: Link %wZ\n", &RegName
);
1274 Status
= CmpLinkHiveToMaster(&RegName
,
1276 CmpMachineHiveList
[i
].CmHive2
,
1277 CmpMachineHiveList
[i
].Allocate
,
1278 SecurityDescriptor
);
1279 if (Status
!= STATUS_SUCCESS
)
1281 /* Linking needs to work */
1282 KeBugCheckEx(CONFIG_LIST_FAILED
, 11, Status
, i
, (ULONG_PTR
)&RegName
);
1285 /* Check if we had to allocate a new hive */
1286 if (CmpMachineHiveList
[i
].Allocate
)
1288 /* Sync the new hive */
1289 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1293 /* Check if we created a new hive */
1294 if (CmpMachineHiveList
[i
].CmHive2
)
1296 /* TODO: Add to HiveList key */
1300 /* Get rid of the SD */
1301 ExFreePool(SecurityDescriptor
);
1303 /* FIXME: Link SECURITY to SAM */
1305 /* FIXME: Link S-1-5-18 to .Default */
1312 OBJECT_ATTRIBUTES ObjectAttributes
;
1313 UNICODE_STRING KeyName
;
1316 PCMHIVE HardwareHive
;
1319 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1322 /* Check if this is PE-boot */
1323 if (InitIsWinPEMode
)
1325 /* Set registry to PE mode */
1326 CmpMiniNTBoot
= TRUE
;
1327 CmpShareSystemHives
= TRUE
;
1330 /* Initialize the hive list and lock */
1331 InitializeListHead(&CmpHiveListHead
);
1332 ExInitializePushLock((PVOID
)&CmpHiveListHeadLock
);
1333 ExInitializePushLock((PVOID
)&CmpLoadHiveLock
);
1335 /* Initialize registry lock */
1336 ExInitializeResourceLite(&CmpRegistryLock
);
1338 /* Initialize the cache */
1339 CmpInitializeCache();
1341 /* Initialize allocation and delayed dereferencing */
1342 CmpInitCmPrivateAlloc();
1343 CmpInitCmPrivateDelayAlloc();
1344 CmpInitDelayDerefKCBEngine();
1346 /* Initialize callbacks */
1349 /* Initialize self healing */
1350 KeInitializeGuardedMutex(&CmpSelfHealQueueLock
);
1351 InitializeListHead(&CmpSelfHealQueueListHead
);
1353 /* Save the current process and lock the registry */
1354 CmpSystemProcess
= PsGetCurrentProcess();
1356 /* Create the key object types */
1357 Status
= CmpCreateObjectTypes();
1358 if (!NT_SUCCESS(Status
))
1361 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 1, Status
, 0);
1364 /* Build the master hive */
1365 Status
= CmpInitializeHive((PCMHIVE
*)&CmiVolatileHive
,
1375 if (!NT_SUCCESS(Status
))
1378 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 2, Status
, 0);
1381 /* Create the \REGISTRY key node */
1382 if (!CmpCreateRegistryRoot())
1385 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 3, 0, 0);
1388 /* Create the default security descriptor */
1389 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1391 /* Create '\Registry\Machine' key. */
1392 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE");
1393 InitializeObjectAttributes(&ObjectAttributes
,
1395 OBJ_CASE_INSENSITIVE
,
1397 SecurityDescriptor
);
1398 Status
= NtCreateKey(&KeyHandle
,
1399 KEY_READ
| KEY_WRITE
,
1405 if (!NT_SUCCESS(Status
))
1408 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 5, Status
, 0);
1411 /* Close the handle */
1414 /* Create '\Registry\User' key. */
1415 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\USER");
1416 InitializeObjectAttributes(&ObjectAttributes
,
1418 OBJ_CASE_INSENSITIVE
,
1420 SecurityDescriptor
);
1421 Status
= NtCreateKey(&KeyHandle
,
1422 KEY_READ
| KEY_WRITE
,
1428 if (!NT_SUCCESS(Status
))
1431 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 6, Status
, 0);
1434 /* Close the handle */
1437 /* Initialize the system hive */
1438 if (!CmpInitializeSystemHive(KeLoaderBlock
))
1441 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 7, 0, 0);
1444 /* Create the 'CurrentControlSet' link. */
1445 Status
= CmpCreateControlSet(KeLoaderBlock
);
1446 if (!NT_SUCCESS(Status
))
1449 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 8, Status
, 0);
1452 /* Import the hardware hive (FIXME: We should create it from scratch) */
1453 BaseAddress
= CmpRosGetHardwareHive(&Length
);
1454 ((PHBASE_BLOCK
)BaseAddress
)->Length
= Length
;
1455 Status
= CmpInitializeHive((PCMHIVE
*)&HardwareHive
,
1456 HINIT_MEMORY
, //HINIT_CREATE,
1457 HIVE_VOLATILE
| HIVE_NOLAZYFLUSH
,
1459 BaseAddress
, // NULL,
1465 CmPrepareHive(&HardwareHive
->Hive
);
1466 if (!NT_SUCCESS(Status
))
1469 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 11, Status
, 0);
1472 /* Add the hive to the hive list */
1473 CmpMachineHiveList
[0].CmHive
= (PCMHIVE
)HardwareHive
;
1475 /* Attach it to the machine key */
1476 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE");
1477 Status
= CmpLinkHiveToMaster(&KeyName
,
1479 (PCMHIVE
)HardwareHive
,
1481 SecurityDescriptor
);
1482 if (!NT_SUCCESS(Status
))
1485 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 12, Status
, 0);
1488 /* FIXME: Add to HiveList key */
1490 /* Free the security descriptor */
1491 ExFreePool(SecurityDescriptor
);
1493 /* Fill out the Hardware key with the ARC Data from the Loader */
1494 Status
= CmpInitializeHardwareConfiguration(KeLoaderBlock
);
1495 if (!NT_SUCCESS(Status
))
1498 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 13, Status
, 0);
1501 /* Initialize machine-dependent information into the registry */
1502 Status
= CmpInitializeMachineDependentConfiguration(KeLoaderBlock
);
1503 if (!NT_SUCCESS(Status
))
1506 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 14, Status
, 0);
1509 /* Initialize volatile registry settings */
1510 Status
= CmpSetSystemValues(KeLoaderBlock
);
1511 if (!NT_SUCCESS(Status
))
1514 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 15, Status
, 0);
1517 /* Free the load options */
1518 ExFreePool(CmpLoadOptions
.Buffer
);
1520 /* If we got here, all went well */
1526 CmpLockRegistryExclusive(VOID
)
1528 /* Enter a critical region and lock the registry */
1529 KeEnterCriticalRegion();
1530 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1533 ASSERT(CmpFlushStarveWriters
== 0);
1534 RtlGetCallersAddress(&CmpRegistryLockCaller
, &CmpRegistryLockCallerCaller
);
1539 CmpLockRegistry(VOID
)
1541 /* Enter a critical region */
1542 KeEnterCriticalRegion();
1544 /* Check if we have to starve writers */
1545 if (CmpFlushStarveWriters
)
1547 /* Starve exlusive waiters */
1548 ExAcquireSharedStarveExclusive(&CmpRegistryLock
, TRUE
);
1552 /* Just grab the lock */
1553 ExAcquireResourceSharedLite(&CmpRegistryLock
, TRUE
);
1559 CmpTestRegistryLock(VOID
)
1562 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1567 CmpTestRegistryLockExclusive(VOID
)
1570 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1575 CmpUnlockRegistry(VOID
)
1578 CMP_ASSERT_REGISTRY_LOCK();
1580 /* Check if we should flush the registry */
1581 if (CmpFlushOnLockRelease
)
1583 /* The registry should be exclusively locked for this */
1584 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1586 /* Flush the registry */
1587 CmpDoFlushAll(TRUE
);
1588 CmpFlushOnLockRelease
= FALSE
;
1591 /* Release the lock and leave the critical region */
1592 ExReleaseResourceLite(&CmpRegistryLock
);
1593 KeLeaveCriticalRegion();
1598 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1
,
1601 ULONG Index1
, Index2
;
1604 CMP_ASSERT_REGISTRY_LOCK();
1606 /* Get hash indexes */
1607 Index1
= GET_HASH_INDEX(ConvKey1
);
1608 Index2
= GET_HASH_INDEX(ConvKey2
);
1610 /* See which one is highest */
1611 if (Index1
< Index2
)
1613 /* Grab them in the proper order */
1614 CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1615 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1619 /* Grab the second one first, then the first */
1620 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1621 if (Index1
!= Index2
) CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1627 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1
,
1630 ULONG Index1
, Index2
;
1633 CMP_ASSERT_REGISTRY_LOCK();
1635 /* Get hash indexes */
1636 Index1
= GET_HASH_INDEX(ConvKey1
);
1637 Index2
= GET_HASH_INDEX(ConvKey2
);
1638 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey2
).Owner
== KeGetCurrentThread()) ||
1639 (CmpTestRegistryLockExclusive()));
1641 /* See which one is highest */
1642 if (Index1
< Index2
)
1644 /* Grab them in the proper order */
1645 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1646 (CmpTestRegistryLockExclusive()));
1647 CmpReleaseKcbLockByKey(ConvKey2
);
1648 CmpReleaseKcbLockByKey(ConvKey1
);
1652 /* Release the first one first, then the second */
1653 if (Index1
!= Index2
)
1655 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1656 (CmpTestRegistryLockExclusive()));
1657 CmpReleaseKcbLockByKey(ConvKey1
);
1659 CmpReleaseKcbLockByKey(ConvKey2
);
1665 CmShutdownSystem(VOID
)
1667 /* Kill the workers and fush all hives */
1668 CmpShutdownWorkers();
1669 CmpDoFlushAll(TRUE
);