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 KGUARDED_MUTEX CmpSelfHealQueueLock
;
17 LIST_ENTRY CmpSelfHealQueueListHead
;
18 KEVENT CmpLoadWorkerEvent
;
19 LONG CmpLoadWorkerIncrement
;
20 PEPROCESS CmpSystemProcess
;
21 BOOLEAN HvShutdownComplete
;
22 PVOID CmpRegistryLockCallerCaller
, CmpRegistryLockCaller
;
23 BOOLEAN CmpFlushStarveWriters
;
24 BOOLEAN CmpFlushOnLockRelease
;
25 BOOLEAN CmpSpecialBootCondition
;
27 BOOLEAN CmpForceForceFlush
;
28 BOOLEAN CmpWasSetupBoot
;
30 /* FUNCTIONS *****************************************************************/
34 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName
,
40 ULONG HiveDisposition
, LogDisposition
;
41 HANDLE FileHandle
= NULL
, LogHandle
= NULL
;
43 ULONG Operation
, FileType
;
50 /* Open or create the hive files */
51 Status
= CmpOpenHiveFiles(HiveName
,
61 if (!NT_SUCCESS(Status
)) return Status
;
63 /* Check if we have a log handle */
64 FileType
= (LogHandle
) ? HFILE_TYPE_LOG
: HFILE_TYPE_PRIMARY
;
66 /* Check if we created or opened the hive */
67 if (HiveDisposition
== FILE_CREATED
)
69 /* Do a create operation */
70 Operation
= HINIT_CREATE
;
75 /* Open it as a file */
76 Operation
= HINIT_FILE
;
80 /* Check if we're sharing hives */
81 if (CmpShareSystemHives
)
83 /* Then force using the primary hive */
84 FileType
= HFILE_TYPE_PRIMARY
;
87 /* Get rid of the log handle */
93 /* Check if we're too late */
94 if (HvShutdownComplete
)
98 if (LogHandle
) ZwClose(LogHandle
);
99 return STATUS_TOO_LATE
;
102 /* Initialize the hive */
103 Status
= CmpInitializeHive((PCMHIVE
*)&NewHive
,
113 if (!NT_SUCCESS(Status
))
117 if (LogHandle
) ZwClose(LogHandle
);
121 /* Success, return hive */
124 /* ROS: Init root key cell and prepare the hive */
125 if (Operation
== HINIT_CREATE
) CmCreateRootNode(&NewHive
->Hive
, L
"");
126 CmPrepareHive(&NewHive
->Hive
);
128 /* Duplicate the hive name */
129 NewHive
->FileFullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
132 if (NewHive
->FileFullPath
.Buffer
)
134 /* Copy the string */
135 RtlCopyMemory(NewHive
->FileFullPath
.Buffer
,
138 NewHive
->FileFullPath
.Length
= HiveName
->Length
;
139 NewHive
->FileFullPath
.MaximumLength
= HiveName
->MaximumLength
;
142 /* ROS: Close the hive files */
144 if (LogHandle
) ZwClose(LogHandle
);
147 return STATUS_SUCCESS
;
152 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
154 OBJECT_ATTRIBUTES ObjectAttributes
;
155 UNICODE_STRING KeyName
, ValueName
;
158 ASSERT(LoaderBlock
!= NULL
);
159 if (ExpInTextModeSetup
) return STATUS_SUCCESS
;
161 /* Setup attributes for loader options */
162 RtlInitUnicodeString(&KeyName
,
163 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
165 InitializeObjectAttributes(&ObjectAttributes
,
167 OBJ_CASE_INSENSITIVE
,
170 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
171 if (!NT_SUCCESS(Status
)) goto Quickie
;
173 /* Key opened, now write to the key */
174 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
175 Status
= NtSetValueKey(KeyHandle
,
179 CmpLoadOptions
.Buffer
,
180 CmpLoadOptions
.Length
);
181 if (!NT_SUCCESS(Status
)) goto Quickie
;
183 /* Setup value name for system boot device */
184 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
185 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->NtBootPathName
);
186 Status
= NtSetValueKey(KeyHandle
,
194 /* Free the buffers */
195 RtlFreeUnicodeString(&ValueName
);
197 /* Close the key and return */
200 /* Return the status */
206 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
208 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
209 UNICODE_STRING SelectName
=
210 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
211 UNICODE_STRING KeyName
;
212 OBJECT_ATTRIBUTES ObjectAttributes
;
213 CHAR ValueInfoBuffer
[128];
214 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
216 WCHAR UnicodeBuffer
[128];
217 HANDLE SelectHandle
, KeyHandle
, ConfigHandle
= NULL
, ProfileHandle
= NULL
;
218 HANDLE ParentHandle
= NULL
;
219 ULONG ControlSet
, HwProfile
;
220 ANSI_STRING TempString
;
222 ULONG ResultLength
, Disposition
;
223 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
225 if (ExpInTextModeSetup
) return STATUS_SUCCESS
;
227 /* Open the select key */
228 InitializeObjectAttributes(&ObjectAttributes
,
230 OBJ_CASE_INSENSITIVE
,
233 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
234 if (!NT_SUCCESS(Status
)) return(Status
);
236 /* Open the current value */
237 RtlInitUnicodeString(&KeyName
, L
"Current");
238 Status
= NtQueryValueKey(SelectHandle
,
240 KeyValueFullInformation
,
242 sizeof(ValueInfoBuffer
),
244 NtClose(SelectHandle
);
245 if (!NT_SUCCESS(Status
)) return Status
;
247 /* Get the actual value pointer, and get the control set ID */
248 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
249 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
251 /* Create the current control set key */
252 RtlInitUnicodeString(&KeyName
,
253 L
"\\Registry\\Machine\\System\\CurrentControlSet");
254 InitializeObjectAttributes(&ObjectAttributes
,
256 OBJ_CASE_INSENSITIVE
,
260 Status
= NtCreateKey(&KeyHandle
,
265 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
267 if (!NT_SUCCESS(Status
)) return Status
;
270 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
272 /* Initialize the symbolic link name */
274 "\\Registry\\Machine\\System\\ControlSet%03ld",
276 RtlInitAnsiString(&TempString
, Buffer
);
278 /* Create a Unicode string out of it */
279 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
280 KeyName
.Buffer
= UnicodeBuffer
;
281 Status
= RtlAnsiStringToUnicodeString(&KeyName
, &TempString
, FALSE
);
284 Status
= NtSetValueKey(KeyHandle
,
285 &CmSymbolicLinkValueName
,
290 if (!NT_SUCCESS(Status
)) return Status
;
292 /* Get the configuration database key */
293 InitializeObjectAttributes(&ObjectAttributes
,
295 OBJ_CASE_INSENSITIVE
,
298 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
301 /* Check if we don't have one */
302 if (!NT_SUCCESS(Status
))
304 /* Cleanup and exit */
309 /* Now get the current config */
310 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
311 Status
= NtQueryValueKey(ConfigHandle
,
313 KeyValueFullInformation
,
315 sizeof(ValueInfoBuffer
),
318 /* Set pointer to buffer */
319 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
321 /* Check if we failed or got a non DWORD-value */
322 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
)) goto Cleanup
;
324 /* Get the hadware profile */
325 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
327 /* Open the hardware profile key */
328 RtlInitUnicodeString(&KeyName
,
329 L
"\\Registry\\Machine\\System\\CurrentControlSet"
330 L
"\\Hardware Profiles");
331 InitializeObjectAttributes(&ObjectAttributes
,
333 OBJ_CASE_INSENSITIVE
,
336 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
337 if (!NT_SUCCESS(Status
))
339 /* Exit and clean up */
344 /* Build the profile name */
345 sprintf(Buffer
, "%04ld", HwProfile
);
346 RtlInitAnsiString(&TempString
, Buffer
);
348 /* Convert it to Unicode */
349 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
350 KeyName
.Buffer
= UnicodeBuffer
;
351 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
354 ASSERT(Status
== STATUS_SUCCESS
);
356 /* Open the associated key */
357 InitializeObjectAttributes(&ObjectAttributes
,
359 OBJ_CASE_INSENSITIVE
,
362 Status
= NtOpenKey(&ProfileHandle
,
363 KEY_READ
| KEY_WRITE
,
365 if (!NT_SUCCESS (Status
))
367 /* Cleanup and exit */
372 /* Check if we have a loader block extension */
373 LoaderExtension
= LoaderBlock
->Extension
;
376 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE
);
379 /* Create the current hardware profile key */
380 RtlInitUnicodeString(&KeyName
,
381 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
382 L
"Hardware Profiles\\Current");
383 InitializeObjectAttributes(&ObjectAttributes
,
385 OBJ_CASE_INSENSITIVE
,
388 Status
= NtCreateKey(&KeyHandle
,
393 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
395 if (NT_SUCCESS(Status
))
398 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
400 /* Create the profile name */
402 "\\Registry\\Machine\\System\\CurrentControlSet\\"
403 "Hardware Profiles\\%04ld",
405 RtlInitAnsiString(&TempString
, Buffer
);
407 /* Convert it to Unicode */
408 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
409 KeyName
.Buffer
= UnicodeBuffer
;
410 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
413 ASSERT(STATUS_SUCCESS
== Status
);
416 Status
= NtSetValueKey(KeyHandle
,
417 &CmSymbolicLinkValueName
,
425 /* Close every opened handle */
427 if (ConfigHandle
) NtClose(ConfigHandle
);
428 if (ProfileHandle
) NtClose(ProfileHandle
);
429 if (ParentHandle
) NtClose(ParentHandle
);
432 return STATUS_SUCCESS
;
437 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
440 ANSI_STRING LoadString
;
445 UNICODE_STRING KeyName
;
446 PCMHIVE SystemHive
= NULL
;
447 UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
448 PSECURITY_DESCRIPTOR SecurityDescriptor
;
451 /* Setup the ansi string */
452 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
454 /* Allocate the unicode buffer */
455 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
456 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
460 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
463 /* Setup the unicode string */
464 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, (USHORT
)Length
);
466 /* Add the load options and null-terminate */
467 RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
468 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
469 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
471 /* Get the System Hive base address */
472 HiveBase
= LoaderBlock
->RegistryBase
;
476 ((PHBASE_BLOCK
)HiveBase
)->Length
= LoaderBlock
->RegistryLength
;
477 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
479 0, //HIVE_NOLAZYFLUSH,
487 if (!NT_SUCCESS(Status
)) return FALSE
;
488 CmPrepareHive(&SystemHive
->Hive
);
490 /* Set the hive filename */
491 RtlCreateUnicodeString(&SystemHive
->FileFullPath
, SYSTEM_REG_FILE
);
493 /* We imported, no need to create a new hive */
496 /* Manually set the hive as volatile, if in Live CD mode */
497 if (CmpShareSystemHives
) SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
503 Status
= CmpInitializeHive(&SystemHive
,
505 0, //HIVE_NOLAZYFLUSH,
513 if (!NT_SUCCESS(Status
)) return FALSE
;
515 /* Set the hive filename */
516 RtlCreateUnicodeString(&SystemHive
->FileFullPath
, SYSTEM_REG_FILE
);
518 /* Tell CmpLinkHiveToMaster to allocate a hive */
522 /* Save the boot type */
523 if (SystemHive
) CmpBootType
= SystemHive
->Hive
.BaseBlock
->BootType
;
525 /* Are we in self-healing mode? */
528 /* Disable self-healing internally and check if boot type wanted it */
532 /* We're disabled, so bugcheck */
533 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO
,
536 (ULONG_PTR
)SystemHive
,
541 /* Create the default security descriptor */
542 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
544 /* Attach it to the system key */
545 RtlInitUnicodeString(&KeyName
, REG_SYSTEM_KEY_NAME
);
546 Status
= CmpLinkHiveToMaster(&KeyName
,
552 /* Free the security descriptor */
553 ExFreePool(SecurityDescriptor
);
554 if (!NT_SUCCESS(Status
)) return FALSE
;
556 /* Add the hive to the hive list */
557 CmpMachineHiveList
[3].CmHive
= (PCMHIVE
)SystemHive
;
565 CmpCreateObjectTypes(VOID
)
567 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
569 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
575 /* Initialize the Key object type */
576 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
577 RtlInitUnicodeString(&Name
, L
"Key");
578 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
579 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
580 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
581 ObjectTypeInitializer
.PoolType
= PagedPool
;
582 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
583 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
584 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
585 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
586 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
587 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
588 //ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
589 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
592 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
597 CmpCreateRootNode(IN PHHIVE Hive
,
599 OUT PHCELL_INDEX Index
)
601 UNICODE_STRING KeyName
;
602 PCM_KEY_NODE KeyCell
;
603 LARGE_INTEGER SystemTime
;
606 /* Initialize the node name and allocate it */
607 RtlInitUnicodeString(&KeyName
, Name
);
608 *Index
= HvAllocateCell(Hive
,
609 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
610 CmpNameSize(Hive
, &KeyName
),
613 if (*Index
== HCELL_NIL
) return FALSE
;
615 /* Set the cell index and get the data */
616 Hive
->BaseBlock
->RootCell
= *Index
;
617 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
618 if (!KeyCell
) return FALSE
;
621 KeyCell
->Signature
= (USHORT
)CM_KEY_NODE_SIGNATURE
;
622 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
623 KeQuerySystemTime(&SystemTime
);
624 KeyCell
->LastWriteTime
= SystemTime
;
625 KeyCell
->Parent
= HCELL_NIL
;
626 KeyCell
->SubKeyCounts
[Stable
] = 0;
627 KeyCell
->SubKeyCounts
[Volatile
] = 0;
628 KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
629 KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
630 KeyCell
->ValueList
.Count
= 0;
631 KeyCell
->ValueList
.List
= HCELL_NIL
;
632 KeyCell
->Security
= HCELL_NIL
;
633 KeyCell
->Class
= HCELL_NIL
;
634 KeyCell
->ClassLength
= 0;
635 KeyCell
->MaxNameLen
= 0;
636 KeyCell
->MaxClassLen
= 0;
637 KeyCell
->MaxValueNameLen
= 0;
638 KeyCell
->MaxValueDataLen
= 0;
640 /* Copy the name (this will also set the length) */
641 KeyCell
->NameLength
= CmpCopyName(Hive
, (PWCHAR
)KeyCell
->Name
, &KeyName
);
643 /* Check if the name was compressed */
644 if (KeyCell
->NameLength
< KeyName
.Length
)
647 KeyCell
->Flags
|= KEY_COMP_NAME
;
651 HvReleaseCell(Hive
, *Index
);
657 CmpCreateRegistryRoot(VOID
)
659 UNICODE_STRING KeyName
;
660 OBJECT_ATTRIBUTES ObjectAttributes
;
662 PCM_KEY_BODY RootKey
;
666 HCELL_INDEX RootIndex
;
668 PCM_KEY_NODE KeyCell
;
669 PSECURITY_DESCRIPTOR SecurityDescriptor
;
670 PCM_KEY_CONTROL_BLOCK Kcb
;
673 /* Setup the root node */
674 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
680 /* Create '\Registry' key. */
681 RtlInitUnicodeString(&KeyName
, L
"\\Registry");
682 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
683 InitializeObjectAttributes(&ObjectAttributes
,
685 OBJ_CASE_INSENSITIVE
,
688 Status
= ObCreateObject(KernelMode
,
697 ExFreePool(SecurityDescriptor
);
698 if (!NT_SUCCESS(Status
)) return FALSE
;
700 /* Sanity check, and get the key cell */
701 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
702 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
703 if (!KeyCell
) return FALSE
;
706 RtlInitUnicodeString(&KeyName
, L
"Registry");
707 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
713 if (!Kcb
) return FALSE
;
715 /* Initialize the object */
716 RootKey
->Type
= TAG('k', 'v', '0', '2');
717 RootKey
->KeyControlBlock
= Kcb
;
719 RootKey
->NotifyBlock
= NULL
;
720 RootKey
->ProcessID
= PsGetCurrentProcessId();
722 RtlpCreateUnicodeString(&RootKey
->Name
, L
"Registry", NonPagedPool
);
723 RootKey
->SubKeyCounts
= 0;
724 RootKey
->SubKeys
= NULL
;
725 RootKey
->SizeOfSubKeys
= 0;
728 /* Insert it into the object list head */
729 EnlistKeyBodyWithKeyObject(RootKey
, 0);
731 /* Insert the key into the namespace */
732 Status
= ObInsertObject(RootKey
,
737 &CmpRegistryRootHandle
);
738 if (!NT_SUCCESS(Status
)) return FALSE
;
740 /* Reference the key again so that we never lose it */
741 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
747 if (!NT_SUCCESS(Status
)) return FALSE
;
749 /* Completely sucessful */
755 CmpLoadHiveThread(IN PVOID StartContext
)
757 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
];
758 UNICODE_STRING TempName
, FileName
, RegName
;
759 ULONG FileStart
, RegStart
, i
, ErrorResponse
, ClusterSize
, WorkerCount
;
760 ULONG PrimaryDisposition
, SecondaryDisposition
, Length
;
762 HANDLE PrimaryHandle
, LogHandle
;
763 NTSTATUS Status
= STATUS_SUCCESS
;
764 PVOID ErrorParameters
;
767 /* Get the hive index, make sure it makes sense */
768 i
= (ULONG
)StartContext
;
769 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
770 DPRINT1("[HiveLoad] Parallel Thread: %d\n", i
);
772 /* We were started */
773 CmpMachineHiveList
[i
].ThreadStarted
= TRUE
;
775 /* Build the file name and registry name strings */
776 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
777 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
779 /* Now build the system root path */
780 RtlInitUnicodeString(&TempName
, L
"\\SystemRoot\\System32\\Config\\");
781 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
782 FileStart
= FileName
.Length
;
784 /* And build the registry root path */
785 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
786 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
787 RegStart
= RegName
.Length
;
789 /* Build the base name */
790 RegName
.Length
= RegStart
;
791 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
792 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
794 /* Check if this is a child of the root */
795 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
797 /* Then setup the whole name */
798 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
799 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
802 /* Now Add tge rest if the file name */
803 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
804 FileName
.Length
= FileStart
;
805 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
806 if (!CmpMachineHiveList
[i
].CmHive
)
808 /* We need to allocate a ne whive structure */
809 CmpMachineHiveList
[i
].Allocate
= TRUE
;
811 /* Load the hive file */
812 DPRINT1("[HiveLoad]: Load from file %wZ\n", &FileName
);
813 CmpMachineHiveList
[i
].CmHive2
= (PVOID
)0xBAADBEEF;
815 Status
= CmpInitHiveFromFile(&FileName
,
816 CmpMachineHiveList
[i
].HHiveFlags
,
818 &CmpMachineHiveList
[i
].Allocate
,
820 if (!(NT_SUCCESS(Status
)) || !(CmHive
->FileHandles
[HFILE_TYPE_LOG
]))
822 /* We failed or couldn't get a log file, raise a hard error */
823 ErrorParameters
= &FileName
;
824 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
827 (PULONG_PTR
)&ErrorParameters
,
832 /* Set the hive flags and newly allocated hive pointer */
833 CmHive
->Flags
= CmpMachineHiveList
[i
].CmHiveFlags
;
834 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
838 /* We already have a hive, is it volatile? */
839 CmHive
= CmpMachineHiveList
[i
].CmHive
;
840 if (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
842 DPRINT1("[HiveLoad]: Open from file %wZ\n", &FileName
);
843 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
846 /* It's now, open the hive file and log */
847 Status
= CmpOpenHiveFiles(&FileName
,
852 &SecondaryDisposition
,
857 if (!(NT_SUCCESS(Status
)) || !(LogHandle
))
859 /* Couldn't open the hive or its log file, raise a hard error */
860 ErrorParameters
= &FileName
;
861 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
864 (PULONG_PTR
)&ErrorParameters
,
868 /* And bugcheck for posterity's sake */
869 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 0, i
, Status
);
872 /* Save the file handles. This should remove our sync hacks */
873 CmHive
->FileHandles
[HFILE_TYPE_LOG
] = LogHandle
;
874 CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = PrimaryHandle
;
876 /* Allow lazy flushing since the handles are there -- remove sync hacks */
877 ASSERT(CmHive
->Hive
.HiveFlags
& HIVE_NOLAZYFLUSH
);
878 CmHive
->Hive
.HiveFlags
&= ~HIVE_NOLAZYFLUSH
;
880 /* Get the real size of the hive */
881 Length
= CmHive
->Hive
.Storage
[Stable
].Length
+ HBLOCK_SIZE
;
883 /* Check if the cluster size doesn't match */
884 if (CmHive
->Hive
.Cluster
!= ClusterSize
) ASSERT(FALSE
);
886 /* Set the file size */
887 if (!CmpFileSetSize((PHHIVE
)CmHive
, HFILE_TYPE_PRIMARY
, Length
, Length
))
889 /* This shouldn't fail */
893 /* Another thing we don't support is NTLDR-recovery */
894 if (CmHive
->Hive
.BaseBlock
->BootRecover
) ASSERT(FALSE
);
896 /* Finally, set our allocated hive to the same hive we've had */
897 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
898 ASSERT(CmpMachineHiveList
[i
].CmHive
== CmpMachineHiveList
[i
].CmHive2
);
904 CmpMachineHiveList
[i
].ThreadFinished
= TRUE
;
906 /* Check if we're the last worker */
907 WorkerCount
= InterlockedIncrement(&CmpLoadWorkerIncrement
);
908 if (WorkerCount
== CM_NUMBER_OF_MACHINE_HIVES
)
911 /* Signal the event */
912 KeSetEvent(&CmpLoadWorkerEvent
, 0, FALSE
);
915 /* Kill the thread */
916 PsTerminateSystemThread(Status
);
921 CmpInitializeHiveList(IN USHORT Flag
)
923 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
];
924 UNICODE_STRING TempName
, FileName
, RegName
;
927 ULONG FileStart
, RegStart
, i
;
928 PSECURITY_DESCRIPTOR SecurityDescriptor
;
931 /* Allow writing for now */
934 /* Build the file name and registry name strings */
935 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
936 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
938 /* Now build the system root path */
939 RtlInitUnicodeString(&TempName
, L
"\\SystemRoot\\System32\\Config\\");
940 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
941 FileStart
= FileName
.Length
;
943 /* And build the registry root path */
944 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
945 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
946 RegStart
= RegName
.Length
;
948 /* Setup the event to synchronize workers */
949 KeInitializeEvent(&CmpLoadWorkerEvent
, SynchronizationEvent
, FALSE
);
951 /* Enter special boot condition */
952 CmpSpecialBootCondition
= TRUE
;
954 /* Create the SD for the root hives */
955 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
957 /* Loop every hive we care about */
958 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
960 /* Make sure the list is setup */
961 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
963 /* Create a thread to handle this hive */
964 Status
= PsCreateSystemThread(&Thread
,
971 if (NT_SUCCESS(Status
))
973 /* We don't care about the handle -- the thread self-terminates */
978 /* Can't imagine this happening */
979 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 3, i
, Status
);
983 /* Make sure we've reached the end of the list */
984 ASSERT(CmpMachineHiveList
[i
].Name
== NULL
);
986 /* Wait for hive loading to finish */
987 KeWaitForSingleObject(&CmpLoadWorkerEvent
,
993 /* Exit the special boot condition and make sure all workers completed */
994 CmpSpecialBootCondition
= FALSE
;
995 ASSERT(CmpLoadWorkerIncrement
== CM_NUMBER_OF_MACHINE_HIVES
);
997 /* Loop hives again */
998 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1000 /* Make sure the thread ran and finished */
1001 ASSERT(CmpMachineHiveList
[i
].ThreadFinished
== TRUE
);
1002 ASSERT(CmpMachineHiveList
[i
].ThreadStarted
== TRUE
);
1004 /* Check if this was a new hive */
1005 if (!CmpMachineHiveList
[i
].CmHive
)
1007 /* Make sure we allocated something */
1008 ASSERT(CmpMachineHiveList
[i
].CmHive2
!= NULL
);
1010 /* Build the base name */
1011 RegName
.Length
= RegStart
;
1012 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1013 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1015 /* Check if this is a child of the root */
1016 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1018 /* Then setup the whole name */
1019 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1020 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1023 /* Now link the hive to its master */
1024 DPRINT1("[HiveLoad]: Link %wZ\n", &RegName
);
1026 Status
= CmpLinkHiveToMaster(&RegName
,
1028 CmpMachineHiveList
[i
].CmHive2
,
1029 CmpMachineHiveList
[i
].Allocate
,
1030 SecurityDescriptor
);
1031 if (Status
!= STATUS_SUCCESS
)
1033 /* Linking needs to work */
1034 KeBugCheckEx(CONFIG_LIST_FAILED
, 11, Status
, i
, (ULONG_PTR
)&RegName
);
1037 /* Check if we had to allocate a new hive */
1038 if (CmpMachineHiveList
[i
].Allocate
)
1040 /* Sync the new hive */
1041 HvSyncHive((PHHIVE
)(CmpMachineHiveList
[i
].CmHive2
));
1046 /* Check if we created a new hive */
1047 if (CmpMachineHiveList
[i
].CmHive2
)
1049 /* TODO: Add to HiveList key */
1053 /* Get rid of the SD */
1054 ExFreePool(SecurityDescriptor
);
1056 /* FIXME: Link SECURITY to SAM */
1058 /* FIXME: Link S-1-5-18 to .Default */
1065 OBJECT_ATTRIBUTES ObjectAttributes
;
1066 UNICODE_STRING KeyName
;
1069 PCMHIVE HardwareHive
;
1072 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1075 /* Check if this is PE-boot */
1076 if (InitIsWinPEMode
)
1078 /* Set registry to PE mode */
1079 CmpMiniNTBoot
= TRUE
;
1080 CmpShareSystemHives
= TRUE
;
1083 /* Initialize the hive list and lock */
1084 InitializeListHead(&CmpHiveListHead
);
1085 ExInitializePushLock((PVOID
)&CmpHiveListHeadLock
);
1086 ExInitializePushLock((PVOID
)&CmpLoadHiveLock
);
1088 /* Initialize registry lock */
1089 ExInitializeResourceLite(&CmpRegistryLock
);
1091 /* Initialize the cache */
1092 CmpInitializeCache();
1094 /* Initialize allocation and delayed dereferencing */
1095 CmpInitCmPrivateAlloc();
1096 CmpInitCmPrivateDelayAlloc();
1097 CmpInitDelayDerefKCBEngine();
1099 /* Initialize callbacks */
1102 /* Initialize self healing */
1103 KeInitializeGuardedMutex(&CmpSelfHealQueueLock
);
1104 InitializeListHead(&CmpSelfHealQueueListHead
);
1106 /* Save the current process and lock the registry */
1107 CmpSystemProcess
= PsGetCurrentProcess();
1110 /* OLD CM: Initialize the key object list */
1111 InitializeListHead(&CmiKeyObjectListHead
);
1112 InitializeListHead(&CmiConnectedHiveList
);
1115 /* Create the key object types */
1116 Status
= CmpCreateObjectTypes();
1117 if (!NT_SUCCESS(Status
))
1120 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 1, Status
, 0);
1123 /* Build the master hive */
1124 Status
= CmpInitializeHive((PCMHIVE
*)&CmiVolatileHive
,
1134 if (!NT_SUCCESS(Status
))
1137 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 2, Status
, 0);
1140 /* Create the \REGISTRY key node */
1141 if (!CmpCreateRegistryRoot())
1144 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 3, 0, 0);
1147 /* Create the default security descriptor */
1148 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1150 /* Create '\Registry\Machine' key. */
1151 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE");
1152 InitializeObjectAttributes(&ObjectAttributes
,
1154 OBJ_CASE_INSENSITIVE
,
1156 SecurityDescriptor
);
1157 Status
= NtCreateKey(&KeyHandle
,
1158 KEY_READ
| KEY_WRITE
,
1164 if (!NT_SUCCESS(Status
))
1167 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 5, Status
, 0);
1170 /* Close the handle */
1173 /* Create '\Registry\User' key. */
1174 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\USER");
1175 InitializeObjectAttributes(&ObjectAttributes
,
1177 OBJ_CASE_INSENSITIVE
,
1179 SecurityDescriptor
);
1180 Status
= NtCreateKey(&KeyHandle
,
1181 KEY_READ
| KEY_WRITE
,
1187 if (!NT_SUCCESS(Status
))
1190 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 6, Status
, 0);
1193 /* Close the handle */
1196 /* Initialize the system hive */
1197 if (!CmpInitializeSystemHive(KeLoaderBlock
))
1200 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 7, 0, 0);
1203 /* Create the 'CurrentControlSet' link. */
1204 Status
= CmpCreateControlSet(KeLoaderBlock
);
1205 if (!NT_SUCCESS(Status
))
1208 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 8, Status
, 0);
1211 /* Import the hardware hive (FIXME: We should create it from scratch) */
1212 BaseAddress
= CmpRosGetHardwareHive(&Length
);
1213 ((PHBASE_BLOCK
)BaseAddress
)->Length
= Length
;
1214 Status
= CmpInitializeHive((PCMHIVE
*)&HardwareHive
,
1215 HINIT_MEMORY
, //HINIT_CREATE,
1218 BaseAddress
, // NULL,
1224 CmPrepareHive(&HardwareHive
->Hive
);
1225 if (!NT_SUCCESS(Status
))
1228 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 11, Status
, 0);
1231 /* Attach it to the machine key */
1232 RtlInitUnicodeString(&KeyName
, REG_HARDWARE_KEY_NAME
);
1233 Status
= CmpLinkHiveToMaster(&KeyName
,
1235 (PCMHIVE
)HardwareHive
,
1237 SecurityDescriptor
);
1238 if (!NT_SUCCESS(Status
))
1241 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 12, Status
, 0);
1244 /* Fill out the Hardware key with the ARC Data from the Loader */
1245 Status
= CmpInitializeHardwareConfiguration(KeLoaderBlock
);
1246 if (!NT_SUCCESS(Status
))
1249 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 13, Status
, 0);
1252 /* Initialize machine-dependent information into the registry */
1253 Status
= CmpInitializeMachineDependentConfiguration(KeLoaderBlock
);
1254 if (!NT_SUCCESS(Status
))
1257 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 14, Status
, 0);
1260 /* Initialize volatile registry settings */
1261 Status
= CmpSetSystemValues(KeLoaderBlock
);
1262 if (!NT_SUCCESS(Status
))
1265 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED
, 1, 15, Status
, 0);
1268 /* Free the load options */
1269 ExFreePool(CmpLoadOptions
.Buffer
);
1271 /* If we got here, all went well */
1277 CmpLockRegistryExclusive(VOID
)
1279 /* Enter a critical region and lock the registry */
1280 KeEnterCriticalRegion();
1281 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1284 ASSERT(CmpFlushStarveWriters
== 0);
1285 RtlGetCallersAddress(&CmpRegistryLockCaller
, &CmpRegistryLockCallerCaller
);
1290 CmpLockRegistry(VOID
)
1292 /* Enter a critical region */
1293 KeEnterCriticalRegion();
1295 /* Check if we have to starve writers */
1296 if (CmpFlushStarveWriters
)
1298 /* Starve exlusive waiters */
1299 ExAcquireSharedStarveExclusive(&CmpRegistryLock
, TRUE
);
1303 /* Just grab the lock */
1304 ExAcquireResourceSharedLite(&CmpRegistryLock
, TRUE
);
1310 CmpTestRegistryLock(VOID
)
1313 return (BOOLEAN
)ExIsResourceAcquiredSharedLite(&CmpRegistryLock
);
1318 CmpTestRegistryLockExclusive(VOID
)
1321 return ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock
);
1326 CmpUnlockRegistry(VOID
)
1329 CMP_ASSERT_REGISTRY_LOCK();
1331 /* Check if we should flush the registry */
1332 if (CmpFlushOnLockRelease
)
1334 /* The registry should be exclusively locked for this */
1335 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1337 /* Flush the registry */
1338 CmpDoFlushAll(TRUE
);
1339 CmpFlushOnLockRelease
= FALSE
;
1342 /* Release the lock and leave the critical region */
1343 ExReleaseResourceLite(&CmpRegistryLock
);
1344 KeLeaveCriticalRegion();
1349 CmShutdownSystem(VOID
)
1351 /* Kill the workers and fush all hives */
1352 CmpShutdownWorkers();
1353 CmpDoFlushAll(TRUE
);