2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/config/cmsysini.c
5 * PURPOSE: Configuration Manager - System Initialization Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES *******************************************************************/
16 POBJECT_TYPE CmpKeyObjectType
;
17 PCMHIVE CmiVolatileHive
;
18 LIST_ENTRY CmpHiveListHead
;
19 ERESOURCE CmpRegistryLock
;
20 KGUARDED_MUTEX CmpSelfHealQueueLock
;
21 LIST_ENTRY CmpSelfHealQueueListHead
;
22 KEVENT CmpLoadWorkerEvent
;
23 LONG CmpLoadWorkerIncrement
;
24 PEPROCESS CmpSystemProcess
;
25 BOOLEAN HvShutdownComplete
;
26 PVOID CmpRegistryLockCallerCaller
, CmpRegistryLockCaller
;
27 BOOLEAN CmpFlushOnLockRelease
;
28 BOOLEAN CmpSpecialBootCondition
;
30 BOOLEAN CmpWasSetupBoot
;
31 BOOLEAN CmpProfileLoaded
;
32 ULONG CmpTraceLevel
= 0;
34 extern LONG CmpFlushStarveWriters
;
35 extern BOOLEAN CmFirstTime
;
37 /* FUNCTIONS ******************************************************************/
41 CmpDeleteKeyObject(PVOID DeletedObject
)
43 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)DeletedObject
;
44 PCM_KEY_CONTROL_BLOCK Kcb
;
45 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo
;
46 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
50 /* First off, prepare the handle close information callback */
51 PostOperationInfo
.Object
= KeyBody
;
52 KeyHandleCloseInfo
.Object
= KeyBody
;
53 Status
= CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose
,
55 if (!NT_SUCCESS(Status
))
57 /* If we failed, notify the post routine */
58 PostOperationInfo
.Status
= Status
;
59 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
63 /* Acquire hive lock */
66 /* Make sure this is a valid key body */
67 if (KeyBody
->Type
== '20yk')
70 Kcb
= KeyBody
->KeyControlBlock
;
74 DelistKeyBodyFromKCB(KeyBody
, FALSE
);
76 /* Dereference the KCB */
77 CmpDelayDerefKeyControlBlock(Kcb
);
81 /* Release the registry lock */
84 /* Do the post callback */
85 PostOperationInfo
.Status
= STATUS_SUCCESS
;
86 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
91 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL
,
93 IN ACCESS_MASK GrantedAccess
,
94 IN ULONG ProcessHandleCount
,
95 IN ULONG SystemHandleCount
)
97 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)Object
;
100 /* Don't do anything if we're not the last handle */
101 if (SystemHandleCount
> 1) return;
103 /* Make sure we're a valid key body */
104 if (KeyBody
->Type
== '20yk')
106 /* Don't do anything if we don't have a notify block */
107 if (!KeyBody
->NotifyBlock
) return;
109 /* This shouldn't happen yet */
116 CmpQueryKeyName(IN PVOID ObjectBody
,
118 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
120 OUT PULONG ReturnLength
,
121 IN KPROCESSOR_MODE PreviousMode
)
123 PUNICODE_STRING KeyName
;
125 NTSTATUS Status
= STATUS_SUCCESS
;
126 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)ObjectBody
;
127 PCM_KEY_CONTROL_BLOCK Kcb
= KeyBody
->KeyControlBlock
;
129 /* Acquire hive lock */
132 /* Lock KCB shared */
133 CmpAcquireKcbLockShared(Kcb
);
135 /* Check if it's a deleted block */
138 /* Release the locks */
139 CmpReleaseKcbLock(Kcb
);
142 /* Let the caller know it's deleted */
143 return STATUS_KEY_DELETED
;
147 KeyName
= CmpConstructName(Kcb
);
149 /* Release the locks */
150 CmpReleaseKcbLock(Kcb
);
153 /* Check if we got the name */
154 if (!KeyName
) return STATUS_INSUFFICIENT_RESOURCES
;
156 /* Set the returned length */
157 *ReturnLength
= KeyName
->Length
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
);
159 /* Calculate amount of bytes to copy into the buffer */
160 BytesToCopy
= KeyName
->Length
+ sizeof(WCHAR
);
162 /* Check if the provided buffer is too small to fit even anything */
163 if ((Length
<= sizeof(OBJECT_NAME_INFORMATION
)) ||
164 ((Length
< (*ReturnLength
)) && (BytesToCopy
< sizeof(WCHAR
))))
166 /* Free the buffer allocated by CmpConstructName */
169 /* Return buffer length failure without writing anything there because nothing fits */
170 return STATUS_INFO_LENGTH_MISMATCH
;
173 /* Check if the provided buffer can be partially written */
174 if (Length
< (*ReturnLength
))
176 /* Yes, indicate so in the return status */
177 Status
= STATUS_INFO_LENGTH_MISMATCH
;
179 /* Calculate amount of bytes which the provided buffer could handle */
180 BytesToCopy
= Length
- sizeof(OBJECT_NAME_INFORMATION
);
183 /* Remove the null termination character from the size */
184 BytesToCopy
-= sizeof(WCHAR
);
186 /* Fill in the result */
189 /* Return data to user */
190 ObjectNameInfo
->Name
.Buffer
= (PWCHAR
)(ObjectNameInfo
+ 1);
191 ObjectNameInfo
->Name
.MaximumLength
= KeyName
->Length
;
192 ObjectNameInfo
->Name
.Length
= KeyName
->Length
;
194 /* Copy string content*/
195 RtlCopyMemory(ObjectNameInfo
->Name
.Buffer
,
199 /* Null terminate it */
200 ObjectNameInfo
->Name
.Buffer
[BytesToCopy
/ sizeof(WCHAR
)] = 0;
202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
205 Status
= _SEH2_GetExceptionCode();
209 /* Free the buffer allocated by CmpConstructName */
218 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName
,
224 ULONG HiveDisposition
, LogDisposition
;
225 HANDLE FileHandle
= NULL
, LogHandle
= NULL
;
227 ULONG Operation
, FileType
;
234 /* Open or create the hive files */
235 Status
= CmpOpenHiveFiles(HiveName
,
245 if (!NT_SUCCESS(Status
)) return Status
;
247 /* Check if we have a log handle */
248 FileType
= (LogHandle
) ? HFILE_TYPE_LOG
: HFILE_TYPE_PRIMARY
;
250 /* Check if we created or opened the hive */
251 if (HiveDisposition
== FILE_CREATED
)
253 /* Do a create operation */
254 Operation
= HINIT_CREATE
;
259 /* Open it as a file */
260 Operation
= HINIT_FILE
;
264 /* Check if we're sharing hives */
265 if (CmpShareSystemHives
)
267 /* Then force using the primary hive */
268 FileType
= HFILE_TYPE_PRIMARY
;
271 /* Get rid of the log handle */
277 /* Check if we're too late */
278 if (HvShutdownComplete
)
282 if (LogHandle
) ZwClose(LogHandle
);
283 return STATUS_TOO_LATE
;
286 /* Initialize the hive */
287 Status
= CmpInitializeHive((PCMHIVE
*)&NewHive
,
297 if (!NT_SUCCESS(Status
))
301 if (LogHandle
) ZwClose(LogHandle
);
305 /* Success, return hive */
308 /* ROS: Init root key cell and prepare the hive */
309 if (Operation
== HINIT_CREATE
) CmCreateRootNode(&NewHive
->Hive
, L
"");
311 /* Duplicate the hive name */
312 NewHive
->FileFullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
315 if (NewHive
->FileFullPath
.Buffer
)
317 /* Copy the string */
318 RtlCopyMemory(NewHive
->FileFullPath
.Buffer
,
321 NewHive
->FileFullPath
.Length
= HiveName
->Length
;
322 NewHive
->FileFullPath
.MaximumLength
= HiveName
->MaximumLength
;
326 return STATUS_SUCCESS
;
332 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
334 OBJECT_ATTRIBUTES ObjectAttributes
;
335 UNICODE_STRING KeyName
, ValueName
= { 0, 0, NULL
};
336 HANDLE KeyHandle
= NULL
;
338 ASSERT(LoaderBlock
!= NULL
);
340 /* Setup attributes for loader options */
341 RtlInitUnicodeString(&KeyName
,
342 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
344 InitializeObjectAttributes(&ObjectAttributes
,
346 OBJ_CASE_INSENSITIVE
,
349 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
350 if (!NT_SUCCESS(Status
)) goto Quickie
;
352 /* Key opened, now write to the key */
353 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
354 Status
= NtSetValueKey(KeyHandle
,
358 CmpLoadOptions
.Buffer
,
359 CmpLoadOptions
.Length
);
360 if (!NT_SUCCESS(Status
)) goto Quickie
;
362 /* Setup value name for system boot device */
363 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
364 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->NtBootPathName
);
365 Status
= NtSetValueKey(KeyHandle
,
373 /* Free the buffers */
374 RtlFreeUnicodeString(&ValueName
);
376 /* Close the key and return */
377 if (KeyHandle
) NtClose(KeyHandle
);
379 /* Return the status */
380 return (ExpInTextModeSetup
? STATUS_SUCCESS
: Status
);
386 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
388 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
389 UNICODE_STRING SelectName
=
390 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
391 UNICODE_STRING KeyName
;
392 OBJECT_ATTRIBUTES ObjectAttributes
;
393 CHAR ValueInfoBuffer
[128];
394 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
396 WCHAR UnicodeBuffer
[128];
397 HANDLE SelectHandle
, KeyHandle
, ConfigHandle
= NULL
, ProfileHandle
= NULL
;
398 HANDLE ParentHandle
= NULL
;
399 ULONG ControlSet
, HwProfile
;
400 ANSI_STRING TempString
;
402 ULONG ResultLength
, Disposition
;
403 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
406 /* Open the select key */
407 InitializeObjectAttributes(&ObjectAttributes
,
409 OBJ_CASE_INSENSITIVE
,
412 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
413 if (!NT_SUCCESS(Status
))
415 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
416 if (!LoaderBlock
->RegistryBase
)
418 /* Build the ControlSet001 key */
419 RtlInitUnicodeString(&KeyName
,
420 L
"\\Registry\\Machine\\System\\ControlSet001");
421 InitializeObjectAttributes(&ObjectAttributes
,
423 OBJ_CASE_INSENSITIVE
,
426 Status
= NtCreateKey(&KeyHandle
,
433 if (!NT_SUCCESS(Status
)) return Status
;
435 /* Don't need the handle */
438 /* Use hard-coded setting */
443 /* Fail for real boots */
447 /* Open the current value */
448 RtlInitUnicodeString(&KeyName
, L
"Current");
449 Status
= NtQueryValueKey(SelectHandle
,
451 KeyValueFullInformation
,
453 sizeof(ValueInfoBuffer
),
455 NtClose(SelectHandle
);
456 if (!NT_SUCCESS(Status
)) return Status
;
458 /* Get the actual value pointer, and get the control set ID */
459 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
460 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
462 /* Create the current control set key */
464 RtlInitUnicodeString(&KeyName
,
465 L
"\\Registry\\Machine\\System\\CurrentControlSet");
466 InitializeObjectAttributes(&ObjectAttributes
,
468 OBJ_CASE_INSENSITIVE
,
471 Status
= NtCreateKey(&KeyHandle
,
476 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
478 if (!NT_SUCCESS(Status
)) return Status
;
481 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
483 /* Initialize the symbolic link name */
485 "\\Registry\\Machine\\System\\ControlSet%03ld",
487 RtlInitAnsiString(&TempString
, Buffer
);
489 /* Create a Unicode string out of it */
490 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
491 KeyName
.Buffer
= UnicodeBuffer
;
492 Status
= RtlAnsiStringToUnicodeString(&KeyName
, &TempString
, FALSE
);
495 Status
= NtSetValueKey(KeyHandle
,
496 &CmSymbolicLinkValueName
,
501 if (!NT_SUCCESS(Status
)) return Status
;
503 /* Get the configuration database key */
504 InitializeObjectAttributes(&ObjectAttributes
,
506 OBJ_CASE_INSENSITIVE
,
509 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
512 /* Check if we don't have one */
513 if (!NT_SUCCESS(Status
))
515 /* Cleanup and exit */
520 /* Now get the current config */
521 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
522 Status
= NtQueryValueKey(ConfigHandle
,
524 KeyValueFullInformation
,
526 sizeof(ValueInfoBuffer
),
529 /* Set pointer to buffer */
530 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
532 /* Check if we failed or got a non DWORD-value */
533 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
)) goto Cleanup
;
535 /* Get the hadware profile */
536 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
538 /* Open the hardware profile key */
539 RtlInitUnicodeString(&KeyName
,
540 L
"\\Registry\\Machine\\System\\CurrentControlSet"
541 L
"\\Hardware Profiles");
542 InitializeObjectAttributes(&ObjectAttributes
,
544 OBJ_CASE_INSENSITIVE
,
547 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
548 if (!NT_SUCCESS(Status
))
550 /* Exit and clean up */
555 /* Build the profile name */
556 sprintf(Buffer
, "%04ld", HwProfile
);
557 RtlInitAnsiString(&TempString
, Buffer
);
559 /* Convert it to Unicode */
560 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
561 KeyName
.Buffer
= UnicodeBuffer
;
562 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
565 ASSERT(Status
== STATUS_SUCCESS
);
567 /* Open the associated key */
568 InitializeObjectAttributes(&ObjectAttributes
,
570 OBJ_CASE_INSENSITIVE
,
573 Status
= NtOpenKey(&ProfileHandle
,
574 KEY_READ
| KEY_WRITE
,
576 if (!NT_SUCCESS (Status
))
578 /* Cleanup and exit */
583 /* Check if we have a loader block extension */
584 LoaderExtension
= LoaderBlock
->Extension
;
587 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE
);
590 /* Create the current hardware profile key */
591 RtlInitUnicodeString(&KeyName
,
592 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
593 L
"Hardware Profiles\\Current");
594 InitializeObjectAttributes(&ObjectAttributes
,
596 OBJ_CASE_INSENSITIVE
,
599 Status
= NtCreateKey(&KeyHandle
,
604 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
606 if (NT_SUCCESS(Status
))
609 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
611 /* Create the profile name */
613 "\\Registry\\Machine\\System\\CurrentControlSet\\"
614 "Hardware Profiles\\%04ld",
616 RtlInitAnsiString(&TempString
, Buffer
);
618 /* Convert it to Unicode */
619 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
620 KeyName
.Buffer
= UnicodeBuffer
;
621 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
624 ASSERT(STATUS_SUCCESS
== Status
);
627 Status
= NtSetValueKey(KeyHandle
,
628 &CmSymbolicLinkValueName
,
636 /* Close every opened handle */
638 if (ConfigHandle
) NtClose(ConfigHandle
);
639 if (ProfileHandle
) NtClose(ProfileHandle
);
640 if (ParentHandle
) NtClose(ParentHandle
);
643 return STATUS_SUCCESS
;
648 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName
,
649 IN HANDLE RootDirectory
,
650 IN PCMHIVE RegistryHive
,
652 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
654 OBJECT_ATTRIBUTES ObjectAttributes
;
656 CM_PARSE_CONTEXT ParseContext
= {0};
658 PCM_KEY_BODY KeyBody
;
661 /* Setup the object attributes */
662 InitializeObjectAttributes(&ObjectAttributes
,
664 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
668 /* Setup the parse context */
669 ParseContext
.CreateLink
= TRUE
;
670 ParseContext
.CreateOperation
= TRUE
;
671 ParseContext
.ChildHive
.KeyHive
= &RegistryHive
->Hive
;
673 /* Check if we have a root keycell or if we need to create it */
677 ParseContext
.ChildHive
.KeyCell
= HCELL_NIL
;
682 ParseContext
.ChildHive
.KeyCell
= RegistryHive
->Hive
.BaseBlock
->RootCell
;
685 /* Create the link node */
686 Status
= ObOpenObjectByName(&ObjectAttributes
,
690 KEY_READ
| KEY_WRITE
,
691 (PVOID
)&ParseContext
,
693 if (!NT_SUCCESS(Status
)) return Status
;
695 /* Mark the hive as clean */
696 RegistryHive
->Hive
.DirtyFlag
= FALSE
;
698 /* ReactOS Hack: Keep alive */
699 Status
= ObReferenceObjectByHandle(KeyHandle
,
705 ASSERT(NT_SUCCESS(Status
));
707 /* Close the extra handle */
709 return STATUS_SUCCESS
;
715 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
718 ANSI_STRING LoadString
;
723 UNICODE_STRING KeyName
;
724 PCMHIVE SystemHive
= NULL
;
725 UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
726 PSECURITY_DESCRIPTOR SecurityDescriptor
;
729 /* Setup the ansi string */
730 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
732 /* Allocate the unicode buffer */
733 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
734 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
738 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
741 /* Setup the unicode string */
742 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, (USHORT
)Length
);
744 /* Add the load options and null-terminate */
745 RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
746 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
747 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
749 /* Get the System Hive base address */
750 HiveBase
= LoaderBlock
->RegistryBase
;
754 ((PHBASE_BLOCK
)HiveBase
)->Length
= LoaderBlock
->RegistryLength
;
755 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
765 if (!NT_SUCCESS(Status
)) return FALSE
;
767 /* Set the hive filename */
768 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
769 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
771 /* We imported, no need to create a new hive */
774 /* Manually set the hive as volatile, if in Live CD mode */
775 if (CmpShareSystemHives
) SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
780 Status
= CmpInitializeHive(&SystemHive
,
790 if (!NT_SUCCESS(Status
)) return FALSE
;
792 /* Set the hive filename */
793 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
794 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
796 /* Tell CmpLinkHiveToMaster to allocate a hive */
800 /* Save the boot type */
801 CmpBootType
= SystemHive
->Hive
.BaseBlock
->BootType
;
803 /* Are we in self-healing mode? */
806 /* Disable self-healing internally and check if boot type wanted it */
810 /* We're disabled, so bugcheck */
811 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
,
814 (ULONG_PTR
)SystemHive
,
819 /* Create the default security descriptor */
820 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
822 /* Attach it to the system key */
823 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM");
824 Status
= CmpLinkHiveToMaster(&KeyName
,
830 /* Free the security descriptor */
831 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
832 if (!NT_SUCCESS(Status
)) return FALSE
;
834 /* Add the hive to the hive list */
835 CmpMachineHiveList
[3].CmHive
= (PCMHIVE
)SystemHive
;
844 CmpCreateObjectTypes(VOID
)
846 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
848 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
854 /* Initialize the Key object type */
855 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
856 RtlInitUnicodeString(&Name
, L
"Key");
857 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
858 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
859 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
860 ObjectTypeInitializer
.PoolType
= PagedPool
;
861 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
862 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
863 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
864 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
865 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
866 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
867 ObjectTypeInitializer
.CloseProcedure
= CmpCloseKeyObject
;
868 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
869 ObjectTypeInitializer
.InvalidAttributes
= OBJ_EXCLUSIVE
| OBJ_PERMANENT
;
872 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
878 CmpCreateRootNode(IN PHHIVE Hive
,
880 OUT PHCELL_INDEX Index
)
882 UNICODE_STRING KeyName
;
883 PCM_KEY_NODE KeyCell
;
884 LARGE_INTEGER SystemTime
;
887 /* Initialize the node name and allocate it */
888 RtlInitUnicodeString(&KeyName
, Name
);
889 *Index
= HvAllocateCell(Hive
,
890 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
891 CmpNameSize(Hive
, &KeyName
),
894 if (*Index
== HCELL_NIL
) return FALSE
;
896 /* Set the cell index and get the data */
897 Hive
->BaseBlock
->RootCell
= *Index
;
898 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
899 if (!KeyCell
) return FALSE
;
902 KeyCell
->Signature
= (USHORT
)CM_KEY_NODE_SIGNATURE
;
903 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
904 KeQuerySystemTime(&SystemTime
);
905 KeyCell
->LastWriteTime
= SystemTime
;
906 KeyCell
->Parent
= HCELL_NIL
;
907 KeyCell
->SubKeyCounts
[Stable
] = 0;
908 KeyCell
->SubKeyCounts
[Volatile
] = 0;
909 KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
910 KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
911 KeyCell
->ValueList
.Count
= 0;
912 KeyCell
->ValueList
.List
= HCELL_NIL
;
913 KeyCell
->Security
= HCELL_NIL
;
914 KeyCell
->Class
= HCELL_NIL
;
915 KeyCell
->ClassLength
= 0;
916 KeyCell
->MaxNameLen
= 0;
917 KeyCell
->MaxClassLen
= 0;
918 KeyCell
->MaxValueNameLen
= 0;
919 KeyCell
->MaxValueDataLen
= 0;
921 /* Copy the name (this will also set the length) */
922 KeyCell
->NameLength
= CmpCopyName(Hive
, (PWCHAR
)KeyCell
->Name
, &KeyName
);
924 /* Check if the name was compressed */
925 if (KeyCell
->NameLength
< KeyName
.Length
)
928 KeyCell
->Flags
|= KEY_COMP_NAME
;
932 HvReleaseCell(Hive
, *Index
);
939 CmpCreateRegistryRoot(VOID
)
941 UNICODE_STRING KeyName
;
942 OBJECT_ATTRIBUTES ObjectAttributes
;
943 PCM_KEY_BODY RootKey
;
944 HCELL_INDEX RootIndex
;
946 PCM_KEY_NODE KeyCell
;
947 PSECURITY_DESCRIPTOR SecurityDescriptor
;
948 PCM_KEY_CONTROL_BLOCK Kcb
;
951 /* Setup the root node */
952 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
958 /* Create '\Registry' key. */
959 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
960 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
961 InitializeObjectAttributes(&ObjectAttributes
,
963 OBJ_CASE_INSENSITIVE
,
966 Status
= ObCreateObject(KernelMode
,
975 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
976 if (!NT_SUCCESS(Status
)) return FALSE
;
978 /* Sanity check, and get the key cell */
979 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
980 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
981 if (!KeyCell
) return FALSE
;
984 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
985 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
991 if (!Kcb
) return FALSE
;
993 /* Initialize the object */
994 RootKey
->KeyControlBlock
= Kcb
;
995 RootKey
->Type
= '20yk';
996 RootKey
->NotifyBlock
= NULL
;
997 RootKey
->ProcessID
= PsGetCurrentProcessId();
1000 EnlistKeyBodyWithKCB(RootKey
, 0);
1002 /* Insert the key into the namespace */
1003 Status
= ObInsertObject(RootKey
,
1008 &CmpRegistryRootHandle
);
1009 if (!NT_SUCCESS(Status
)) return FALSE
;
1011 /* Reference the key again so that we never lose it */
1012 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
1018 if (!NT_SUCCESS(Status
)) return FALSE
;
1020 /* Completely sucessful */
1026 CmpGetRegistryPath(IN PWCHAR ConfigPath
)
1028 OBJECT_ATTRIBUTES ObjectAttributes
;
1031 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1032 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1033 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1034 ULONG BufferSize
, ResultSize
;
1036 /* Check if we are booted in setup */
1037 if (ExpInTextModeSetup
)
1039 /* Setup the object attributes */
1040 InitializeObjectAttributes(&ObjectAttributes
,
1042 OBJ_CASE_INSENSITIVE
,
1046 Status
= ZwOpenKey(&KeyHandle
,
1049 if (!NT_SUCCESS(Status
)) return Status
;
1051 /* Allocate the buffer */
1052 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1053 ValueInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_CM
);
1058 return STATUS_INSUFFICIENT_RESOURCES
;
1061 /* Query the value */
1062 Status
= ZwQueryValueKey(KeyHandle
,
1064 KeyValuePartialInformation
,
1069 if (!NT_SUCCESS(Status
))
1072 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1076 /* Copy the config path and null-terminate it */
1077 RtlCopyMemory(ConfigPath
,
1079 ValueInfo
->DataLength
);
1080 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1081 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1085 /* Just use default path */
1086 wcscpy(ConfigPath
, L
"\\SystemRoot");
1089 /* Add registry path */
1090 wcscat(ConfigPath
, L
"\\System32\\Config\\");
1093 return STATUS_SUCCESS
;
1098 CmpLoadHiveThread(IN PVOID StartContext
)
1100 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1101 UNICODE_STRING TempName
, FileName
, RegName
;
1102 ULONG i
, ErrorResponse
, WorkerCount
, Length
;
1105 ULONG PrimaryDisposition
, SecondaryDisposition
, ClusterSize
;
1107 HANDLE PrimaryHandle
= NULL
, LogHandle
= NULL
;
1108 NTSTATUS Status
= STATUS_SUCCESS
;
1109 PVOID ErrorParameters
;
1112 /* Get the hive index, make sure it makes sense */
1113 i
= PtrToUlong(StartContext
);
1114 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1116 /* We were started */
1117 CmpMachineHiveList
[i
].ThreadStarted
= TRUE
;
1119 /* Build the file name and registry name strings */
1120 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1121 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1123 /* Now build the system root path */
1124 CmpGetRegistryPath(ConfigPath
);
1125 RtlInitUnicodeString(&TempName
, ConfigPath
);
1126 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1127 FileStart
= FileName
.Length
;
1129 /* And build the registry root path */
1130 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1131 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1132 //RegStart = RegName.Length;
1134 /* Build the base name */
1135 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1136 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1138 /* Check if this is a child of the root */
1139 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1141 /* Then setup the whole name */
1142 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1143 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1146 /* Now add the rest of the file name */
1147 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1148 FileName
.Length
= FileStart
;
1149 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1150 if (!CmpMachineHiveList
[i
].CmHive
)
1152 /* We need to allocate a new hive structure */
1153 CmpMachineHiveList
[i
].Allocate
= TRUE
;
1155 /* Load the hive file */
1156 Status
= CmpInitHiveFromFile(&FileName
,
1157 CmpMachineHiveList
[i
].HHiveFlags
,
1159 &CmpMachineHiveList
[i
].Allocate
,
1161 if (!(NT_SUCCESS(Status
)) ||
1162 (!(CmHive
->FileHandles
[HFILE_TYPE_LOG
]) && !(CmpMiniNTBoot
))) // HACK
1164 /* We failed or couldn't get a log file, raise a hard error */
1165 ErrorParameters
= &FileName
;
1166 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1169 (PULONG_PTR
)&ErrorParameters
,
1174 /* Set the hive flags and newly allocated hive pointer */
1175 CmHive
->Flags
= CmpMachineHiveList
[i
].CmHiveFlags
;
1176 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1180 /* We already have a hive, is it volatile? */
1181 CmHive
= CmpMachineHiveList
[i
].CmHive
;
1182 if (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
1184 /* It's now, open the hive file and log */
1185 Status
= CmpOpenHiveFiles(&FileName
,
1189 &PrimaryDisposition
,
1190 &SecondaryDisposition
,
1195 if (!(NT_SUCCESS(Status
)) || !(LogHandle
))
1197 /* Couldn't open the hive or its log file, raise a hard error */
1198 ErrorParameters
= &FileName
;
1199 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1202 (PULONG_PTR
)&ErrorParameters
,
1206 /* And bugcheck for posterity's sake */
1207 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 0, i
, Status
);
1210 /* Save the file handles. This should remove our sync hacks */
1211 CmHive
->FileHandles
[HFILE_TYPE_LOG
] = LogHandle
;
1212 CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = PrimaryHandle
;
1214 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1215 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1216 CmHive
->Hive
.HiveFlags
&= ~HIVE_NOLAZYFLUSH
;
1218 /* Get the real size of the hive */
1219 Length
= CmHive
->Hive
.Storage
[Stable
].Length
+ HBLOCK_SIZE
;
1221 /* Check if the cluster size doesn't match */
1222 if (CmHive
->Hive
.Cluster
!= ClusterSize
) ASSERT(FALSE
);
1224 /* Set the file size */
1225 DPRINT("FIXME: Should set file size: %lx\n", Length
);
1226 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1228 /* This shouldn't fail */
1232 /* Another thing we don't support is NTLDR-recovery */
1233 if (CmHive
->Hive
.BaseBlock
->BootRecover
) ASSERT(FALSE
);
1235 /* Finally, set our allocated hive to the same hive we've had */
1236 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1237 ASSERT(CmpMachineHiveList
[i
].CmHive
== CmpMachineHiveList
[i
].CmHive2
);
1242 CmpMachineHiveList
[i
].ThreadFinished
= TRUE
;
1244 /* Check if we're the last worker */
1245 WorkerCount
= InterlockedIncrement(&CmpLoadWorkerIncrement
);
1246 if (WorkerCount
== CM_NUMBER_OF_MACHINE_HIVES
)
1248 /* Signal the event */
1249 KeSetEvent(&CmpLoadWorkerEvent
, 0, FALSE
);
1252 /* Kill the thread */
1253 PsTerminateSystemThread(Status
);
1258 CmpInitializeHiveList(IN USHORT Flag
)
1260 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1261 UNICODE_STRING TempName
, FileName
, RegName
;
1266 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1269 /* Allow writing for now */
1272 /* Build the file name and registry name strings */
1273 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1274 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1276 /* Now build the system root path */
1277 CmpGetRegistryPath(ConfigPath
);
1278 RtlInitUnicodeString(&TempName
, ConfigPath
);
1279 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1281 /* And build the registry root path */
1282 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1283 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1284 RegStart
= RegName
.Length
;
1286 /* Setup the event to synchronize workers */
1287 KeInitializeEvent(&CmpLoadWorkerEvent
, SynchronizationEvent
, FALSE
);
1289 /* Enter special boot condition */
1290 CmpSpecialBootCondition
= TRUE
;
1292 /* Create the SD for the root hives */
1293 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1295 /* Loop every hive we care about */
1296 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1298 /* Make sure the list is setup */
1299 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1301 /* Create a thread to handle this hive */
1302 Status
= PsCreateSystemThread(&Thread
,
1309 if (NT_SUCCESS(Status
))
1311 /* We don't care about the handle -- the thread self-terminates */
1316 /* Can't imagine this happening */
1317 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 3, i
, Status
);
1321 /* Make sure we've reached the end of the list */
1322 ASSERT(CmpMachineHiveList
[i
].Name
== NULL
);
1324 /* Wait for hive loading to finish */
1325 KeWaitForSingleObject(&CmpLoadWorkerEvent
,
1331 /* Exit the special boot condition and make sure all workers completed */
1332 CmpSpecialBootCondition
= FALSE
;
1333 ASSERT(CmpLoadWorkerIncrement
== CM_NUMBER_OF_MACHINE_HIVES
);
1335 /* Loop hives again */
1336 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1338 /* Make sure the thread ran and finished */
1339 ASSERT(CmpMachineHiveList
[i
].ThreadFinished
== TRUE
);
1340 ASSERT(CmpMachineHiveList
[i
].ThreadStarted
== TRUE
);
1342 /* Check if this was a new hive */
1343 if (!CmpMachineHiveList
[i
].CmHive
)
1345 /* Make sure we allocated something */
1346 ASSERT(CmpMachineHiveList
[i
].CmHive2
!= NULL
);
1348 /* Build the base name */
1349 RegName
.Length
= RegStart
;
1350 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1351 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1353 /* Check if this is a child of the root */
1354 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1356 /* Then setup the whole name */
1357 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1358 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1361 /* Now link the hive to its master */
1362 Status
= CmpLinkHiveToMaster(&RegName
,
1364 CmpMachineHiveList
[i
].CmHive2
,
1365 CmpMachineHiveList
[i
].Allocate
,
1366 SecurityDescriptor
);
1367 if (Status
!= STATUS_SUCCESS
)
1369 /* Linking needs to work */
1370 KeBugCheckEx(CONFIG_LIST_FAILED
, 11, Status
, i
, (ULONG_PTR
)&RegName
);
1373 /* Check if we had to allocate a new hive */
1374 if (CmpMachineHiveList
[i
].Allocate
)
1376 /* Sync the new hive */
1377 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1381 /* Check if we created a new hive */
1382 if (CmpMachineHiveList
[i
].CmHive2
)
1384 /* Add to HiveList key */
1385 CmpAddToHiveFileList(CmpMachineHiveList
[i
].CmHive2
);
1389 /* Get rid of the SD */
1390 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1392 /* FIXME: Link SECURITY to SAM */
1394 /* FIXME: Link S-1-5-18 to .Default */
1402 OBJECT_ATTRIBUTES ObjectAttributes
;
1403 UNICODE_STRING KeyName
;
1406 PCMHIVE HardwareHive
;
1407 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1410 /* Check if this is PE-boot */
1411 if (InitIsWinPEMode
)
1413 /* Set registry to PE mode */
1414 CmpMiniNTBoot
= TRUE
;
1415 CmpShareSystemHives
= TRUE
;
1418 /* Initialize the hive list and lock */
1419 InitializeListHead(&CmpHiveListHead
);
1420 ExInitializePushLock(&CmpHiveListHeadLock
);
1421 ExInitializePushLock(&CmpLoadHiveLock
);
1423 /* Initialize registry lock */
1424 ExInitializeResourceLite(&CmpRegistryLock
);
1426 /* Initialize the cache */
1427 CmpInitializeCache();
1429 /* Initialize allocation and delayed dereferencing */
1430 CmpInitCmPrivateAlloc();
1431 CmpInitCmPrivateDelayAlloc();
1432 CmpInitDelayDerefKCBEngine();
1434 /* Initialize callbacks */
1437 /* Initialize self healing */
1438 KeInitializeGuardedMutex(&CmpSelfHealQueueLock
);
1439 InitializeListHead(&CmpSelfHealQueueListHead
);
1441 /* Save the current process and lock the registry */
1442 CmpSystemProcess
= PsGetCurrentProcess();
1444 /* Create the key object types */
1445 Status
= CmpCreateObjectTypes();
1446 if (!NT_SUCCESS(Status
))
1449 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 1, Status
, 0);
1452 /* Build the master hive */
1453 Status
= CmpInitializeHive((PCMHIVE
*)&CmiVolatileHive
,
1463 if (!NT_SUCCESS(Status
))
1466 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 2, Status
, 0);
1469 /* Create the \REGISTRY key node */
1470 if (!CmpCreateRegistryRoot())
1473 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 3, 0, 0);
1476 /* Create the default security descriptor */
1477 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1479 /* Create '\Registry\Machine' key. */
1480 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE");
1481 InitializeObjectAttributes(&ObjectAttributes
,
1483 OBJ_CASE_INSENSITIVE
,
1485 SecurityDescriptor
);
1486 Status
= NtCreateKey(&KeyHandle
,
1487 KEY_READ
| KEY_WRITE
,
1493 if (!NT_SUCCESS(Status
))
1496 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 5, Status
, 0);
1499 /* Close the handle */
1502 /* Create '\Registry\User' key. */
1503 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\USER");
1504 InitializeObjectAttributes(&ObjectAttributes
,
1506 OBJ_CASE_INSENSITIVE
,
1508 SecurityDescriptor
);
1509 Status
= NtCreateKey(&KeyHandle
,
1510 KEY_READ
| KEY_WRITE
,
1516 if (!NT_SUCCESS(Status
))
1519 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 6, Status
, 0);
1522 /* Close the handle */
1525 /* Initialize the system hive */
1526 if (!CmpInitializeSystemHive(KeLoaderBlock
))
1529 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 7, 0, 0);
1532 /* Create the 'CurrentControlSet' link. */
1533 Status
= CmpCreateControlSet(KeLoaderBlock
);
1534 if (!NT_SUCCESS(Status
))
1537 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 8, Status
, 0);
1540 /* Create the hardware hive */
1541 Status
= CmpInitializeHive((PCMHIVE
*)&HardwareHive
,
1551 if (!NT_SUCCESS(Status
))
1554 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 11, Status
, 0);
1557 /* Add the hive to the hive list */
1558 CmpMachineHiveList
[0].CmHive
= (PCMHIVE
)HardwareHive
;
1560 /* Attach it to the machine key */
1561 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE");
1562 Status
= CmpLinkHiveToMaster(&KeyName
,
1564 (PCMHIVE
)HardwareHive
,
1566 SecurityDescriptor
);
1567 if (!NT_SUCCESS(Status
))
1570 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 12, Status
, 0);
1573 /* Add to HiveList key */
1574 CmpAddToHiveFileList(HardwareHive
);
1576 /* Free the security descriptor */
1577 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1579 /* Fill out the Hardware key with the ARC Data from the Loader */
1580 Status
= CmpInitializeHardwareConfiguration(KeLoaderBlock
);
1581 if (!NT_SUCCESS(Status
))
1584 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 13, Status
, 0);
1587 /* Initialize machine-dependent information into the registry */
1588 Status
= CmpInitializeMachineDependentConfiguration(KeLoaderBlock
);
1589 if (!NT_SUCCESS(Status
))
1592 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 14, Status
, 0);
1595 /* Initialize volatile registry settings */
1596 Status
= CmpSetSystemValues(KeLoaderBlock
);
1597 if (!NT_SUCCESS(Status
))
1600 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 15, Status
, 0);
1603 /* Free the load options */
1604 ExFreePoolWithTag(CmpLoadOptions
.Buffer
, TAG_CM
);
1606 /* If we got here, all went well */
1613 CmpFreeDriverList(IN PHHIVE Hive
,
1614 IN PLIST_ENTRY DriverList
)
1616 PLIST_ENTRY NextEntry
, OldEntry
;
1617 PBOOT_DRIVER_NODE DriverNode
;
1620 /* Parse the current list */
1621 NextEntry
= DriverList
->Flink
;
1622 while (NextEntry
!= DriverList
)
1624 /* Get the driver node */
1625 DriverNode
= CONTAINING_RECORD(NextEntry
, BOOT_DRIVER_NODE
, ListEntry
.Link
);
1627 /* Get the next entry now, since we're going to free it later */
1628 OldEntry
= NextEntry
;
1629 NextEntry
= NextEntry
->Flink
;
1631 /* Was there a name? */
1632 if (DriverNode
->Name
.Buffer
)
1635 CmpFree(DriverNode
->Name
.Buffer
, DriverNode
->Name
.Length
);
1638 /* Was there a registry path? */
1639 if (DriverNode
->ListEntry
.RegistryPath
.Buffer
)
1642 CmpFree(DriverNode
->ListEntry
.RegistryPath
.Buffer
,
1643 DriverNode
->ListEntry
.RegistryPath
.MaximumLength
);
1646 /* Was there a file path? */
1647 if (DriverNode
->ListEntry
.FilePath
.Buffer
)
1650 CmpFree(DriverNode
->ListEntry
.FilePath
.Buffer
,
1651 DriverNode
->ListEntry
.FilePath
.MaximumLength
);
1654 /* Now free the node, and move on */
1655 CmpFree(OldEntry
, sizeof(BOOT_DRIVER_NODE
));
1662 CmGetSystemDriverList(VOID
)
1664 LIST_ENTRY DriverList
;
1665 OBJECT_ATTRIBUTES ObjectAttributes
;
1667 PCM_KEY_BODY KeyBody
;
1669 HCELL_INDEX RootCell
, ControlCell
;
1671 UNICODE_STRING KeyName
;
1672 PLIST_ENTRY NextEntry
;
1674 PUNICODE_STRING
* ServicePath
= NULL
;
1675 BOOLEAN Success
, AutoSelect
;
1676 PBOOT_DRIVER_LIST_ENTRY DriverEntry
;
1679 /* Initialize the driver list */
1680 InitializeListHead(&DriverList
);
1682 /* Open the system hive key */
1683 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System");
1684 InitializeObjectAttributes(&ObjectAttributes
,
1686 OBJ_CASE_INSENSITIVE
,
1689 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
1690 if (!NT_SUCCESS(Status
)) return NULL
;
1692 /* Reference the key object to get the root hive/cell to access directly */
1693 Status
= ObReferenceObjectByHandle(KeyHandle
,
1699 if (!NT_SUCCESS(Status
))
1706 /* Do all this under the registry lock */
1707 CmpLockRegistryExclusive();
1709 /* Get the hive and key cell */
1710 Hive
= KeyBody
->KeyControlBlock
->KeyHive
;
1711 RootCell
= KeyBody
->KeyControlBlock
->KeyCell
;
1713 /* Open the current control set key */
1714 RtlInitUnicodeString(&KeyName
, L
"Current");
1715 ControlCell
= CmpFindControlSet(Hive
, RootCell
, &KeyName
, &AutoSelect
);
1716 if (ControlCell
== HCELL_NIL
) goto EndPath
;
1718 /* Find all system drivers */
1719 Success
= CmpFindDrivers(Hive
, ControlCell
, SystemLoad
, NULL
, &DriverList
);
1720 if (!Success
) goto EndPath
;
1722 /* Sort by group/tag */
1723 if (!CmpSortDriverList(Hive
, ControlCell
, &DriverList
)) goto EndPath
;
1725 /* Remove circular dependencies (cycles) and sort */
1726 if (!CmpResolveDriverDependencies(&DriverList
)) goto EndPath
;
1728 /* Loop the list to count drivers */
1729 for (i
= 0, NextEntry
= DriverList
.Flink
;
1730 NextEntry
!= &DriverList
;
1731 i
++, NextEntry
= NextEntry
->Flink
);
1733 /* Allocate the array */
1734 ServicePath
= ExAllocatePool(NonPagedPool
, (i
+ 1) * sizeof(PUNICODE_STRING
));
1735 if (!ServicePath
) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 2, 1, 0, 0);
1737 /* Loop the driver list */
1738 for (i
= 0, NextEntry
= DriverList
.Flink
;
1739 NextEntry
!= &DriverList
;
1740 i
++, NextEntry
= NextEntry
->Flink
)
1743 DriverEntry
= CONTAINING_RECORD(NextEntry
, BOOT_DRIVER_LIST_ENTRY
, Link
);
1745 /* Allocate the path for the caller and duplicate the registry path */
1746 ServicePath
[i
] = ExAllocatePool(NonPagedPool
, sizeof(UNICODE_STRING
));
1747 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1748 &DriverEntry
->RegistryPath
,
1752 /* Terminate the list */
1753 ServicePath
[i
] = NULL
;
1756 /* Free the driver list if we had one */
1757 if (!IsListEmpty(&DriverList
)) CmpFreeDriverList(Hive
, &DriverList
);
1759 /* Unlock the registry */
1760 CmpUnlockRegistry();
1762 /* Close the key handle and dereference the object, then return the path */
1763 ObDereferenceObject(KeyBody
);
1770 CmpLockRegistryExclusive(VOID
)
1772 /* Enter a critical region and lock the registry */
1773 KeEnterCriticalRegion();
1774 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1777 ASSERT(CmpFlushStarveWriters
== 0);
1778 RtlGetCallersAddress(&CmpRegistryLockCaller
, &CmpRegistryLockCallerCaller
);
1783 CmpLockRegistry(VOID
)
1785 /* Enter a critical region */
1786 KeEnterCriticalRegion();
1788 /* Check if we have to starve writers */
1789 if (CmpFlushStarveWriters
)
1791 /* Starve exlusive waiters */
1792 ExAcquireSharedStarveExclusive(&CmpRegistryLock
, TRUE
);
1796 /* Just grab the lock */
1797 ExAcquireResourceSharedLite(&CmpRegistryLock
, TRUE
);
1803 CmpTestRegistryLock(VOID
)
1806 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1811 CmpTestRegistryLockExclusive(VOID
)
1814 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1819 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive
)
1821 /* Lock the flusher. We should already be in a critical section */
1822 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1823 ASSERT((ExIsResourceAcquiredShared(Hive
->FlusherLock
) == 0) &&
1824 (ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) == 0));
1825 ExAcquireResourceExclusiveLite(Hive
->FlusherLock
, TRUE
);
1830 CmpLockHiveFlusherShared(IN PCMHIVE Hive
)
1832 /* Lock the flusher. We should already be in a critical section */
1833 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1834 ASSERT((ExIsResourceAcquiredShared(Hive
->FlusherLock
) == 0) &&
1835 (ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) == 0));
1836 ExAcquireResourceSharedLite(Hive
->FlusherLock
, TRUE
);
1841 CmpUnlockHiveFlusher(IN PCMHIVE Hive
)
1844 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1845 CMP_ASSERT_FLUSH_LOCK(Hive
);
1847 /* Release the lock */
1848 ExReleaseResourceLite(Hive
->FlusherLock
);
1853 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive
)
1856 return !ExIsResourceAcquiredSharedLite(Hive
->FlusherLock
) ? FALSE
: TRUE
;
1861 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive
)
1864 return !ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) ? FALSE
: TRUE
;
1869 CmpUnlockRegistry(VOID
)
1872 CMP_ASSERT_REGISTRY_LOCK();
1874 /* Check if we should flush the registry */
1875 if (CmpFlushOnLockRelease
)
1877 /* The registry should be exclusively locked for this */
1878 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1880 /* Flush the registry */
1881 CmpDoFlushAll(TRUE
);
1882 CmpFlushOnLockRelease
= FALSE
;
1885 /* Release the lock and leave the critical region */
1886 ExReleaseResourceLite(&CmpRegistryLock
);
1887 KeLeaveCriticalRegion();
1892 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1
,
1895 ULONG Index1
, Index2
;
1898 CMP_ASSERT_REGISTRY_LOCK();
1900 /* Get hash indexes */
1901 Index1
= GET_HASH_INDEX(ConvKey1
);
1902 Index2
= GET_HASH_INDEX(ConvKey2
);
1904 /* See which one is highest */
1905 if (Index1
< Index2
)
1907 /* Grab them in the proper order */
1908 CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1909 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1913 /* Grab the second one first, then the first */
1914 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1915 if (Index1
!= Index2
) CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1921 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1
,
1924 ULONG Index1
, Index2
;
1927 CMP_ASSERT_REGISTRY_LOCK();
1929 /* Get hash indexes */
1930 Index1
= GET_HASH_INDEX(ConvKey1
);
1931 Index2
= GET_HASH_INDEX(ConvKey2
);
1932 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey2
).Owner
== KeGetCurrentThread()) ||
1933 (CmpTestRegistryLockExclusive()));
1935 /* See which one is highest */
1936 if (Index1
< Index2
)
1938 /* Grab them in the proper order */
1939 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1940 (CmpTestRegistryLockExclusive()));
1941 CmpReleaseKcbLockByKey(ConvKey2
);
1942 CmpReleaseKcbLockByKey(ConvKey1
);
1946 /* Release the first one first, then the second */
1947 if (Index1
!= Index2
)
1949 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1950 (CmpTestRegistryLockExclusive()));
1951 CmpReleaseKcbLockByKey(ConvKey1
);
1953 CmpReleaseKcbLockByKey(ConvKey2
);
1959 CmShutdownSystem(VOID
)
1961 /* Kill the workers */
1962 if (!CmFirstTime
) CmpShutdownWorkers();
1964 /* Flush all hives */
1965 CmpLockRegistryExclusive();
1966 CmpDoFlushAll(TRUE
);
1967 CmpUnlockRegistry();
1972 CmpSetVersionData(VOID
)
1974 OBJECT_ATTRIBUTES ObjectAttributes
;
1975 UNICODE_STRING KeyName
;
1976 UNICODE_STRING ValueName
;
1977 UNICODE_STRING ValueData
;
1978 HANDLE SoftwareKeyHandle
= NULL
;
1979 HANDLE MicrosoftKeyHandle
= NULL
;
1980 HANDLE WindowsNtKeyHandle
= NULL
;
1981 HANDLE CurrentVersionKeyHandle
= NULL
;
1985 /* Open the 'CurrentVersion' key */
1986 RtlInitUnicodeString(&KeyName
,
1987 L
"\\REGISTRY\\MACHINE\\SOFTWARE");
1989 InitializeObjectAttributes(&ObjectAttributes
,
1991 OBJ_CASE_INSENSITIVE
,
1995 Status
= NtCreateKey(&SoftwareKeyHandle
,
2002 if (!NT_SUCCESS(Status
))
2004 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2008 /* Open the 'CurrentVersion' key */
2009 RtlInitUnicodeString(&KeyName
,
2012 InitializeObjectAttributes(&ObjectAttributes
,
2014 OBJ_CASE_INSENSITIVE
,
2018 Status
= NtCreateKey(&MicrosoftKeyHandle
,
2025 if (!NT_SUCCESS(Status
))
2027 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2031 /* Open the 'CurrentVersion' key */
2032 RtlInitUnicodeString(&KeyName
,
2035 InitializeObjectAttributes(&ObjectAttributes
,
2037 OBJ_CASE_INSENSITIVE
,
2041 Status
= NtCreateKey(&WindowsNtKeyHandle
,
2048 if (!NT_SUCCESS(Status
))
2050 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2054 /* Open the 'CurrentVersion' key */
2055 RtlInitUnicodeString(&KeyName
,
2058 InitializeObjectAttributes(&ObjectAttributes
,
2060 OBJ_CASE_INSENSITIVE
,
2064 Status
= NtCreateKey(&CurrentVersionKeyHandle
,
2065 KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
2071 if (!NT_SUCCESS(Status
))
2073 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2077 /* Set the 'CurrentType' value */
2078 RtlInitUnicodeString(&ValueName
,
2082 wcscpy(Buffer
, L
"Multiprocessor");
2084 wcscpy(Buffer
, L
"Uniprocessor");
2087 wcscat(Buffer
, L
" ");
2090 wcscat(Buffer
, L
"Checked");
2092 wcscat(Buffer
, L
"Free");
2095 RtlInitUnicodeString(&ValueData
,
2098 NtSetValueKey(CurrentVersionKeyHandle
,
2103 ValueData
.Length
+ sizeof(WCHAR
));
2106 /* Close the keys */
2107 if (CurrentVersionKeyHandle
!= NULL
)
2108 NtClose(CurrentVersionKeyHandle
);
2110 if (WindowsNtKeyHandle
!= NULL
)
2111 NtClose(WindowsNtKeyHandle
);
2113 if (MicrosoftKeyHandle
!= NULL
)
2114 NtClose(MicrosoftKeyHandle
);
2116 if (SoftwareKeyHandle
!= NULL
)
2117 NtClose(SoftwareKeyHandle
);