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
;
124 NTSTATUS Status
= STATUS_SUCCESS
;
125 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)ObjectBody
;
126 PCM_KEY_CONTROL_BLOCK Kcb
= KeyBody
->KeyControlBlock
;
128 /* Acquire hive lock */
131 /* Lock KCB shared */
132 CmpAcquireKcbLockShared(Kcb
);
134 /* Check if it's a deleted block */
137 /* Release the locks */
138 CmpReleaseKcbLock(Kcb
);
141 /* Let the caller know it's deleted */
142 return STATUS_KEY_DELETED
;
146 KeyName
= CmpConstructName(Kcb
);
148 /* Release the locks */
149 CmpReleaseKcbLock(Kcb
);
152 /* Check if we got the name */
153 if (!KeyName
) return STATUS_INSUFFICIENT_RESOURCES
;
155 /* Set the returned length */
156 *ReturnLength
= KeyName
->Length
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
);
158 /* Check if it fits into the provided buffer */
159 if ((Length
< sizeof(OBJECT_NAME_INFORMATION
)) ||
160 (Length
< (*ReturnLength
- sizeof(OBJECT_NAME_INFORMATION
))))
162 /* Free the buffer allocated by CmpConstructName */
165 /* Return buffer length failure */
166 return STATUS_INFO_LENGTH_MISMATCH
;
169 /* Fill in the result */
172 /* Return data to user */
173 ObjectNameInfo
->Name
.Buffer
= (PWCHAR
)(ObjectNameInfo
+ 1);
174 ObjectNameInfo
->Name
.MaximumLength
= KeyName
->Length
;
175 ObjectNameInfo
->Name
.Length
= KeyName
->Length
;
177 /* Copy string content*/
178 RtlCopyMemory(ObjectNameInfo
->Name
.Buffer
,
182 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
185 Status
= _SEH2_GetExceptionCode();
189 /* Free the buffer allocated by CmpConstructName */
198 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName
,
204 ULONG HiveDisposition
, LogDisposition
;
205 HANDLE FileHandle
= NULL
, LogHandle
= NULL
;
207 ULONG Operation
, FileType
;
214 /* Open or create the hive files */
215 Status
= CmpOpenHiveFiles(HiveName
,
225 if (!NT_SUCCESS(Status
)) return Status
;
227 /* Check if we have a log handle */
228 FileType
= (LogHandle
) ? HFILE_TYPE_LOG
: HFILE_TYPE_PRIMARY
;
230 /* Check if we created or opened the hive */
231 if (HiveDisposition
== FILE_CREATED
)
233 /* Do a create operation */
234 Operation
= HINIT_CREATE
;
239 /* Open it as a file */
240 Operation
= HINIT_FILE
;
244 /* Check if we're sharing hives */
245 if (CmpShareSystemHives
)
247 /* Then force using the primary hive */
248 FileType
= HFILE_TYPE_PRIMARY
;
251 /* Get rid of the log handle */
257 /* Check if we're too late */
258 if (HvShutdownComplete
)
262 if (LogHandle
) ZwClose(LogHandle
);
263 return STATUS_TOO_LATE
;
266 /* Initialize the hive */
267 Status
= CmpInitializeHive((PCMHIVE
*)&NewHive
,
277 if (!NT_SUCCESS(Status
))
281 if (LogHandle
) ZwClose(LogHandle
);
285 /* Success, return hive */
288 /* ROS: Init root key cell and prepare the hive */
289 if (Operation
== HINIT_CREATE
) CmCreateRootNode(&NewHive
->Hive
, L
"");
291 /* Duplicate the hive name */
292 NewHive
->FileFullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
295 if (NewHive
->FileFullPath
.Buffer
)
297 /* Copy the string */
298 RtlCopyMemory(NewHive
->FileFullPath
.Buffer
,
301 NewHive
->FileFullPath
.Length
= HiveName
->Length
;
302 NewHive
->FileFullPath
.MaximumLength
= HiveName
->MaximumLength
;
306 return STATUS_SUCCESS
;
312 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
314 OBJECT_ATTRIBUTES ObjectAttributes
;
315 UNICODE_STRING KeyName
, ValueName
= { 0, 0, NULL
};
318 ASSERT(LoaderBlock
!= NULL
);
320 /* Setup attributes for loader options */
321 RtlInitUnicodeString(&KeyName
,
322 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
324 InitializeObjectAttributes(&ObjectAttributes
,
326 OBJ_CASE_INSENSITIVE
,
329 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
330 if (!NT_SUCCESS(Status
)) goto Quickie
;
332 /* Key opened, now write to the key */
333 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
334 Status
= NtSetValueKey(KeyHandle
,
338 CmpLoadOptions
.Buffer
,
339 CmpLoadOptions
.Length
);
340 if (!NT_SUCCESS(Status
)) goto Quickie
;
342 /* Setup value name for system boot device */
343 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
344 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->NtBootPathName
);
345 Status
= NtSetValueKey(KeyHandle
,
353 /* Free the buffers */
354 RtlFreeUnicodeString(&ValueName
);
356 /* Close the key and return */
359 /* Return the status */
360 return (ExpInTextModeSetup
? STATUS_SUCCESS
: Status
);
366 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
368 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
369 UNICODE_STRING SelectName
=
370 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
371 UNICODE_STRING KeyName
;
372 OBJECT_ATTRIBUTES ObjectAttributes
;
373 CHAR ValueInfoBuffer
[128];
374 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
376 WCHAR UnicodeBuffer
[128];
377 HANDLE SelectHandle
, KeyHandle
, ConfigHandle
= NULL
, ProfileHandle
= NULL
;
378 HANDLE ParentHandle
= NULL
;
379 ULONG ControlSet
, HwProfile
;
380 ANSI_STRING TempString
;
382 ULONG ResultLength
, Disposition
;
383 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
386 /* Open the select key */
387 InitializeObjectAttributes(&ObjectAttributes
,
389 OBJ_CASE_INSENSITIVE
,
392 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
393 if (!NT_SUCCESS(Status
))
395 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
396 if (!LoaderBlock
->RegistryBase
)
398 /* Build the ControlSet001 key */
399 RtlInitUnicodeString(&KeyName
,
400 L
"\\Registry\\Machine\\System\\ControlSet001");
401 InitializeObjectAttributes(&ObjectAttributes
,
403 OBJ_CASE_INSENSITIVE
,
406 Status
= NtCreateKey(&KeyHandle
,
413 if (!NT_SUCCESS(Status
)) return Status
;
415 /* Don't need the handle */
418 /* Use hard-coded setting */
423 /* Fail for real boots */
427 /* Open the current value */
428 RtlInitUnicodeString(&KeyName
, L
"Current");
429 Status
= NtQueryValueKey(SelectHandle
,
431 KeyValueFullInformation
,
433 sizeof(ValueInfoBuffer
),
435 NtClose(SelectHandle
);
436 if (!NT_SUCCESS(Status
)) return Status
;
438 /* Get the actual value pointer, and get the control set ID */
439 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
440 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
442 /* Create the current control set key */
444 RtlInitUnicodeString(&KeyName
,
445 L
"\\Registry\\Machine\\System\\CurrentControlSet");
446 InitializeObjectAttributes(&ObjectAttributes
,
448 OBJ_CASE_INSENSITIVE
,
451 Status
= NtCreateKey(&KeyHandle
,
456 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
458 if (!NT_SUCCESS(Status
)) return Status
;
461 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
463 /* Initialize the symbolic link name */
465 "\\Registry\\Machine\\System\\ControlSet%03ld",
467 RtlInitAnsiString(&TempString
, Buffer
);
469 /* Create a Unicode string out of it */
470 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
471 KeyName
.Buffer
= UnicodeBuffer
;
472 Status
= RtlAnsiStringToUnicodeString(&KeyName
, &TempString
, FALSE
);
475 Status
= NtSetValueKey(KeyHandle
,
476 &CmSymbolicLinkValueName
,
481 if (!NT_SUCCESS(Status
)) return Status
;
483 /* Get the configuration database key */
484 InitializeObjectAttributes(&ObjectAttributes
,
486 OBJ_CASE_INSENSITIVE
,
489 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
492 /* Check if we don't have one */
493 if (!NT_SUCCESS(Status
))
495 /* Cleanup and exit */
500 /* Now get the current config */
501 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
502 Status
= NtQueryValueKey(ConfigHandle
,
504 KeyValueFullInformation
,
506 sizeof(ValueInfoBuffer
),
509 /* Set pointer to buffer */
510 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
512 /* Check if we failed or got a non DWORD-value */
513 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
)) goto Cleanup
;
515 /* Get the hadware profile */
516 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
518 /* Open the hardware profile key */
519 RtlInitUnicodeString(&KeyName
,
520 L
"\\Registry\\Machine\\System\\CurrentControlSet"
521 L
"\\Hardware Profiles");
522 InitializeObjectAttributes(&ObjectAttributes
,
524 OBJ_CASE_INSENSITIVE
,
527 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
528 if (!NT_SUCCESS(Status
))
530 /* Exit and clean up */
535 /* Build the profile name */
536 sprintf(Buffer
, "%04ld", HwProfile
);
537 RtlInitAnsiString(&TempString
, Buffer
);
539 /* Convert it to Unicode */
540 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
541 KeyName
.Buffer
= UnicodeBuffer
;
542 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
545 ASSERT(Status
== STATUS_SUCCESS
);
547 /* Open the associated key */
548 InitializeObjectAttributes(&ObjectAttributes
,
550 OBJ_CASE_INSENSITIVE
,
553 Status
= NtOpenKey(&ProfileHandle
,
554 KEY_READ
| KEY_WRITE
,
556 if (!NT_SUCCESS (Status
))
558 /* Cleanup and exit */
563 /* Check if we have a loader block extension */
564 LoaderExtension
= LoaderBlock
->Extension
;
567 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE
);
570 /* Create the current hardware profile key */
571 RtlInitUnicodeString(&KeyName
,
572 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
573 L
"Hardware Profiles\\Current");
574 InitializeObjectAttributes(&ObjectAttributes
,
576 OBJ_CASE_INSENSITIVE
,
579 Status
= NtCreateKey(&KeyHandle
,
584 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
586 if (NT_SUCCESS(Status
))
589 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
591 /* Create the profile name */
593 "\\Registry\\Machine\\System\\CurrentControlSet\\"
594 "Hardware Profiles\\%04ld",
596 RtlInitAnsiString(&TempString
, Buffer
);
598 /* Convert it to Unicode */
599 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
600 KeyName
.Buffer
= UnicodeBuffer
;
601 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
604 ASSERT(STATUS_SUCCESS
== Status
);
607 Status
= NtSetValueKey(KeyHandle
,
608 &CmSymbolicLinkValueName
,
616 /* Close every opened handle */
618 if (ConfigHandle
) NtClose(ConfigHandle
);
619 if (ProfileHandle
) NtClose(ProfileHandle
);
620 if (ParentHandle
) NtClose(ParentHandle
);
623 return STATUS_SUCCESS
;
628 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName
,
629 IN HANDLE RootDirectory
,
630 IN PCMHIVE RegistryHive
,
632 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
634 OBJECT_ATTRIBUTES ObjectAttributes
;
636 CM_PARSE_CONTEXT ParseContext
= {0};
638 PCM_KEY_BODY KeyBody
;
641 /* Setup the object attributes */
642 InitializeObjectAttributes(&ObjectAttributes
,
644 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
648 /* Setup the parse context */
649 ParseContext
.CreateLink
= TRUE
;
650 ParseContext
.CreateOperation
= TRUE
;
651 ParseContext
.ChildHive
.KeyHive
= &RegistryHive
->Hive
;
653 /* Check if we have a root keycell or if we need to create it */
657 ParseContext
.ChildHive
.KeyCell
= HCELL_NIL
;
662 ParseContext
.ChildHive
.KeyCell
= RegistryHive
->Hive
.BaseBlock
->RootCell
;
665 /* Create the link node */
666 Status
= ObOpenObjectByName(&ObjectAttributes
,
670 KEY_READ
| KEY_WRITE
,
671 (PVOID
)&ParseContext
,
673 if (!NT_SUCCESS(Status
)) return Status
;
675 /* Mark the hive as clean */
676 RegistryHive
->Hive
.DirtyFlag
= FALSE
;
678 /* ReactOS Hack: Keep alive */
679 Status
= ObReferenceObjectByHandle(KeyHandle
,
685 ASSERT(NT_SUCCESS(Status
));
687 /* Close the extra handle */
689 return STATUS_SUCCESS
;
695 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
698 ANSI_STRING LoadString
;
703 UNICODE_STRING KeyName
;
704 PCMHIVE SystemHive
= NULL
;
705 UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
706 PSECURITY_DESCRIPTOR SecurityDescriptor
;
709 /* Setup the ansi string */
710 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
712 /* Allocate the unicode buffer */
713 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
714 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
718 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
721 /* Setup the unicode string */
722 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, (USHORT
)Length
);
724 /* Add the load options and null-terminate */
725 RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
726 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
727 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
729 /* Get the System Hive base address */
730 HiveBase
= LoaderBlock
->RegistryBase
;
734 ((PHBASE_BLOCK
)HiveBase
)->Length
= LoaderBlock
->RegistryLength
;
735 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
745 if (!NT_SUCCESS(Status
)) return FALSE
;
747 /* Set the hive filename */
748 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
749 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
751 /* We imported, no need to create a new hive */
754 /* Manually set the hive as volatile, if in Live CD mode */
755 if (CmpShareSystemHives
) SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
760 Status
= CmpInitializeHive(&SystemHive
,
770 if (!NT_SUCCESS(Status
)) return FALSE
;
772 /* Set the hive filename */
773 RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
774 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
776 /* Tell CmpLinkHiveToMaster to allocate a hive */
780 /* Save the boot type */
781 CmpBootType
= SystemHive
->Hive
.BaseBlock
->BootType
;
783 /* Are we in self-healing mode? */
786 /* Disable self-healing internally and check if boot type wanted it */
790 /* We're disabled, so bugcheck */
791 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
,
794 (ULONG_PTR
)SystemHive
,
799 /* Create the default security descriptor */
800 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
802 /* Attach it to the system key */
803 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM");
804 Status
= CmpLinkHiveToMaster(&KeyName
,
810 /* Free the security descriptor */
811 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
812 if (!NT_SUCCESS(Status
)) return FALSE
;
814 /* Add the hive to the hive list */
815 CmpMachineHiveList
[3].CmHive
= (PCMHIVE
)SystemHive
;
824 CmpCreateObjectTypes(VOID
)
826 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
828 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
834 /* Initialize the Key object type */
835 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
836 RtlInitUnicodeString(&Name
, L
"Key");
837 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
838 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
839 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
840 ObjectTypeInitializer
.PoolType
= PagedPool
;
841 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
842 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
843 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
844 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
845 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
846 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
847 ObjectTypeInitializer
.CloseProcedure
= CmpCloseKeyObject
;
848 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
851 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
857 CmpCreateRootNode(IN PHHIVE Hive
,
859 OUT PHCELL_INDEX Index
)
861 UNICODE_STRING KeyName
;
862 PCM_KEY_NODE KeyCell
;
863 LARGE_INTEGER SystemTime
;
866 /* Initialize the node name and allocate it */
867 RtlInitUnicodeString(&KeyName
, Name
);
868 *Index
= HvAllocateCell(Hive
,
869 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
870 CmpNameSize(Hive
, &KeyName
),
873 if (*Index
== HCELL_NIL
) return FALSE
;
875 /* Set the cell index and get the data */
876 Hive
->BaseBlock
->RootCell
= *Index
;
877 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
878 if (!KeyCell
) return FALSE
;
881 KeyCell
->Signature
= (USHORT
)CM_KEY_NODE_SIGNATURE
;
882 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
883 KeQuerySystemTime(&SystemTime
);
884 KeyCell
->LastWriteTime
= SystemTime
;
885 KeyCell
->Parent
= HCELL_NIL
;
886 KeyCell
->SubKeyCounts
[Stable
] = 0;
887 KeyCell
->SubKeyCounts
[Volatile
] = 0;
888 KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
889 KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
890 KeyCell
->ValueList
.Count
= 0;
891 KeyCell
->ValueList
.List
= HCELL_NIL
;
892 KeyCell
->Security
= HCELL_NIL
;
893 KeyCell
->Class
= HCELL_NIL
;
894 KeyCell
->ClassLength
= 0;
895 KeyCell
->MaxNameLen
= 0;
896 KeyCell
->MaxClassLen
= 0;
897 KeyCell
->MaxValueNameLen
= 0;
898 KeyCell
->MaxValueDataLen
= 0;
900 /* Copy the name (this will also set the length) */
901 KeyCell
->NameLength
= CmpCopyName(Hive
, (PWCHAR
)KeyCell
->Name
, &KeyName
);
903 /* Check if the name was compressed */
904 if (KeyCell
->NameLength
< KeyName
.Length
)
907 KeyCell
->Flags
|= KEY_COMP_NAME
;
911 HvReleaseCell(Hive
, *Index
);
918 CmpCreateRegistryRoot(VOID
)
920 UNICODE_STRING KeyName
;
921 OBJECT_ATTRIBUTES ObjectAttributes
;
922 PCM_KEY_BODY RootKey
;
923 HCELL_INDEX RootIndex
;
925 PCM_KEY_NODE KeyCell
;
926 PSECURITY_DESCRIPTOR SecurityDescriptor
;
927 PCM_KEY_CONTROL_BLOCK Kcb
;
930 /* Setup the root node */
931 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
937 /* Create '\Registry' key. */
938 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
939 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
940 InitializeObjectAttributes(&ObjectAttributes
,
942 OBJ_CASE_INSENSITIVE
,
945 Status
= ObCreateObject(KernelMode
,
954 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
955 if (!NT_SUCCESS(Status
)) return FALSE
;
957 /* Sanity check, and get the key cell */
958 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
959 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
960 if (!KeyCell
) return FALSE
;
963 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
964 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
970 if (!Kcb
) return FALSE
;
972 /* Initialize the object */
973 RootKey
->KeyControlBlock
= Kcb
;
974 RootKey
->Type
= '20yk';
975 RootKey
->NotifyBlock
= NULL
;
976 RootKey
->ProcessID
= PsGetCurrentProcessId();
979 EnlistKeyBodyWithKCB(RootKey
, 0);
981 /* Insert the key into the namespace */
982 Status
= ObInsertObject(RootKey
,
987 &CmpRegistryRootHandle
);
988 if (!NT_SUCCESS(Status
)) return FALSE
;
990 /* Reference the key again so that we never lose it */
991 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
997 if (!NT_SUCCESS(Status
)) return FALSE
;
999 /* Completely sucessful */
1005 CmpGetRegistryPath(IN PWCHAR ConfigPath
)
1007 OBJECT_ATTRIBUTES ObjectAttributes
;
1010 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1011 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1012 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1013 ULONG BufferSize
, ResultSize
;
1015 /* Check if we are booted in setup */
1016 if (ExpInTextModeSetup
)
1018 /* Setup the object attributes */
1019 InitializeObjectAttributes(&ObjectAttributes
,
1021 OBJ_CASE_INSENSITIVE
,
1025 Status
= ZwOpenKey(&KeyHandle
,
1028 if (!NT_SUCCESS(Status
)) return Status
;
1030 /* Allocate the buffer */
1031 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1032 ValueInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_CM
);
1037 return STATUS_INSUFFICIENT_RESOURCES
;
1040 /* Query the value */
1041 Status
= ZwQueryValueKey(KeyHandle
,
1043 KeyValuePartialInformation
,
1048 if (!NT_SUCCESS(Status
))
1051 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1055 /* Copy the config path and null-terminate it */
1056 RtlCopyMemory(ConfigPath
,
1058 ValueInfo
->DataLength
);
1059 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1060 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1064 /* Just use default path */
1065 wcscpy(ConfigPath
, L
"\\SystemRoot");
1068 /* Add registry path */
1069 wcscat(ConfigPath
, L
"\\System32\\Config\\");
1072 return STATUS_SUCCESS
;
1077 CmpLoadHiveThread(IN PVOID StartContext
)
1079 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1080 UNICODE_STRING TempName
, FileName
, RegName
;
1081 ULONG FileStart
, i
, ErrorResponse
, WorkerCount
, Length
;
1083 ULONG PrimaryDisposition
, SecondaryDisposition
, ClusterSize
;
1085 HANDLE PrimaryHandle
, LogHandle
;
1086 NTSTATUS Status
= STATUS_SUCCESS
;
1087 PVOID ErrorParameters
;
1090 /* Get the hive index, make sure it makes sense */
1091 i
= PtrToUlong(StartContext
);
1092 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1094 /* We were started */
1095 CmpMachineHiveList
[i
].ThreadStarted
= TRUE
;
1097 /* Build the file name and registry name strings */
1098 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1099 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1101 /* Now build the system root path */
1102 CmpGetRegistryPath(ConfigPath
);
1103 RtlInitUnicodeString(&TempName
, ConfigPath
);
1104 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1105 FileStart
= FileName
.Length
;
1107 /* And build the registry root path */
1108 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1109 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1110 //RegStart = RegName.Length;
1112 /* Build the base name */
1113 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1114 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1116 /* Check if this is a child of the root */
1117 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1119 /* Then setup the whole name */
1120 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1121 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1124 /* Now add the rest of the file name */
1125 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1126 FileName
.Length
= FileStart
;
1127 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1128 if (!CmpMachineHiveList
[i
].CmHive
)
1130 /* We need to allocate a new hive structure */
1131 CmpMachineHiveList
[i
].Allocate
= TRUE
;
1133 /* Load the hive file */
1134 Status
= CmpInitHiveFromFile(&FileName
,
1135 CmpMachineHiveList
[i
].HHiveFlags
,
1137 &CmpMachineHiveList
[i
].Allocate
,
1139 if (!(NT_SUCCESS(Status
)) ||
1140 (!(CmHive
->FileHandles
[HFILE_TYPE_LOG
]) && !(CmpMiniNTBoot
))) // HACK
1142 /* We failed or couldn't get a log file, raise a hard error */
1143 ErrorParameters
= &FileName
;
1144 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1147 (PULONG_PTR
)&ErrorParameters
,
1152 /* Set the hive flags and newly allocated hive pointer */
1153 CmHive
->Flags
= CmpMachineHiveList
[i
].CmHiveFlags
;
1154 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1158 /* We already have a hive, is it volatile? */
1159 CmHive
= CmpMachineHiveList
[i
].CmHive
;
1160 if (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
1162 /* It's now, open the hive file and log */
1163 Status
= CmpOpenHiveFiles(&FileName
,
1167 &PrimaryDisposition
,
1168 &SecondaryDisposition
,
1173 if (!(NT_SUCCESS(Status
)) || !(LogHandle
))
1175 /* Couldn't open the hive or its log file, raise a hard error */
1176 ErrorParameters
= &FileName
;
1177 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1180 (PULONG_PTR
)&ErrorParameters
,
1184 /* And bugcheck for posterity's sake */
1185 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 0, i
, Status
);
1188 /* Save the file handles. This should remove our sync hacks */
1189 CmHive
->FileHandles
[HFILE_TYPE_LOG
] = LogHandle
;
1190 CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = PrimaryHandle
;
1192 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1193 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1194 CmHive
->Hive
.HiveFlags
&= ~HIVE_NOLAZYFLUSH
;
1196 /* Get the real size of the hive */
1197 Length
= CmHive
->Hive
.Storage
[Stable
].Length
+ HBLOCK_SIZE
;
1199 /* Check if the cluster size doesn't match */
1200 if (CmHive
->Hive
.Cluster
!= ClusterSize
) ASSERT(FALSE
);
1202 /* Set the file size */
1203 DPRINT("FIXME: Should set file size: %lx\n", Length
);
1204 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1206 /* This shouldn't fail */
1210 /* Another thing we don't support is NTLDR-recovery */
1211 if (CmHive
->Hive
.BaseBlock
->BootRecover
) ASSERT(FALSE
);
1213 /* Finally, set our allocated hive to the same hive we've had */
1214 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1215 ASSERT(CmpMachineHiveList
[i
].CmHive
== CmpMachineHiveList
[i
].CmHive2
);
1220 CmpMachineHiveList
[i
].ThreadFinished
= TRUE
;
1222 /* Check if we're the last worker */
1223 WorkerCount
= InterlockedIncrement(&CmpLoadWorkerIncrement
);
1224 if (WorkerCount
== CM_NUMBER_OF_MACHINE_HIVES
)
1226 /* Signal the event */
1227 KeSetEvent(&CmpLoadWorkerEvent
, 0, FALSE
);
1230 /* Kill the thread */
1231 PsTerminateSystemThread(Status
);
1236 CmpInitializeHiveList(IN USHORT Flag
)
1238 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1239 UNICODE_STRING TempName
, FileName
, RegName
;
1243 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1246 /* Allow writing for now */
1249 /* Build the file name and registry name strings */
1250 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, MAX_PATH
);
1251 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, MAX_PATH
);
1253 /* Now build the system root path */
1254 CmpGetRegistryPath(ConfigPath
);
1255 RtlInitUnicodeString(&TempName
, ConfigPath
);
1256 RtlAppendStringToString((PSTRING
)&FileName
, (PSTRING
)&TempName
);
1258 /* And build the registry root path */
1259 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1260 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1261 RegStart
= RegName
.Length
;
1263 /* Setup the event to synchronize workers */
1264 KeInitializeEvent(&CmpLoadWorkerEvent
, SynchronizationEvent
, FALSE
);
1266 /* Enter special boot condition */
1267 CmpSpecialBootCondition
= TRUE
;
1269 /* Create the SD for the root hives */
1270 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1272 /* Loop every hive we care about */
1273 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1275 /* Make sure the list is setup */
1276 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1278 /* Create a thread to handle this hive */
1279 Status
= PsCreateSystemThread(&Thread
,
1286 if (NT_SUCCESS(Status
))
1288 /* We don't care about the handle -- the thread self-terminates */
1293 /* Can't imagine this happening */
1294 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 3, i
, Status
);
1298 /* Make sure we've reached the end of the list */
1299 ASSERT(CmpMachineHiveList
[i
].Name
== NULL
);
1301 /* Wait for hive loading to finish */
1302 KeWaitForSingleObject(&CmpLoadWorkerEvent
,
1308 /* Exit the special boot condition and make sure all workers completed */
1309 CmpSpecialBootCondition
= FALSE
;
1310 ASSERT(CmpLoadWorkerIncrement
== CM_NUMBER_OF_MACHINE_HIVES
);
1312 /* Loop hives again */
1313 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1315 /* Make sure the thread ran and finished */
1316 ASSERT(CmpMachineHiveList
[i
].ThreadFinished
== TRUE
);
1317 ASSERT(CmpMachineHiveList
[i
].ThreadStarted
== TRUE
);
1319 /* Check if this was a new hive */
1320 if (!CmpMachineHiveList
[i
].CmHive
)
1322 /* Make sure we allocated something */
1323 ASSERT(CmpMachineHiveList
[i
].CmHive2
!= NULL
);
1325 /* Build the base name */
1326 RegName
.Length
= RegStart
;
1327 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1328 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1330 /* Check if this is a child of the root */
1331 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == '\\')
1333 /* Then setup the whole name */
1334 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1335 RtlAppendStringToString((PSTRING
)&RegName
, (PSTRING
)&TempName
);
1338 /* Now link the hive to its master */
1339 Status
= CmpLinkHiveToMaster(&RegName
,
1341 CmpMachineHiveList
[i
].CmHive2
,
1342 CmpMachineHiveList
[i
].Allocate
,
1343 SecurityDescriptor
);
1344 if (Status
!= STATUS_SUCCESS
)
1346 /* Linking needs to work */
1347 KeBugCheckEx(CONFIG_LIST_FAILED
, 11, Status
, i
, (ULONG_PTR
)&RegName
);
1350 /* Check if we had to allocate a new hive */
1351 if (CmpMachineHiveList
[i
].Allocate
)
1353 /* Sync the new hive */
1354 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1358 /* Check if we created a new hive */
1359 if (CmpMachineHiveList
[i
].CmHive2
)
1361 /* TODO: Add to HiveList key */
1365 /* Get rid of the SD */
1366 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1368 /* FIXME: Link SECURITY to SAM */
1370 /* FIXME: Link S-1-5-18 to .Default */
1378 OBJECT_ATTRIBUTES ObjectAttributes
;
1379 UNICODE_STRING KeyName
;
1382 PCMHIVE HardwareHive
;
1383 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1386 /* Check if this is PE-boot */
1387 if (InitIsWinPEMode
)
1389 /* Set registry to PE mode */
1390 CmpMiniNTBoot
= TRUE
;
1391 CmpShareSystemHives
= TRUE
;
1394 /* Initialize the hive list and lock */
1395 InitializeListHead(&CmpHiveListHead
);
1396 ExInitializePushLock(&CmpHiveListHeadLock
);
1397 ExInitializePushLock(&CmpLoadHiveLock
);
1399 /* Initialize registry lock */
1400 ExInitializeResourceLite(&CmpRegistryLock
);
1402 /* Initialize the cache */
1403 CmpInitializeCache();
1405 /* Initialize allocation and delayed dereferencing */
1406 CmpInitCmPrivateAlloc();
1407 CmpInitCmPrivateDelayAlloc();
1408 CmpInitDelayDerefKCBEngine();
1410 /* Initialize callbacks */
1413 /* Initialize self healing */
1414 KeInitializeGuardedMutex(&CmpSelfHealQueueLock
);
1415 InitializeListHead(&CmpSelfHealQueueListHead
);
1417 /* Save the current process and lock the registry */
1418 CmpSystemProcess
= PsGetCurrentProcess();
1420 /* Create the key object types */
1421 Status
= CmpCreateObjectTypes();
1422 if (!NT_SUCCESS(Status
))
1425 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 1, Status
, 0);
1428 /* Build the master hive */
1429 Status
= CmpInitializeHive((PCMHIVE
*)&CmiVolatileHive
,
1439 if (!NT_SUCCESS(Status
))
1442 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 2, Status
, 0);
1445 /* Create the \REGISTRY key node */
1446 if (!CmpCreateRegistryRoot())
1449 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 3, 0, 0);
1452 /* Create the default security descriptor */
1453 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1455 /* Create '\Registry\Machine' key. */
1456 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE");
1457 InitializeObjectAttributes(&ObjectAttributes
,
1459 OBJ_CASE_INSENSITIVE
,
1461 SecurityDescriptor
);
1462 Status
= NtCreateKey(&KeyHandle
,
1463 KEY_READ
| KEY_WRITE
,
1469 if (!NT_SUCCESS(Status
))
1472 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 5, Status
, 0);
1475 /* Close the handle */
1478 /* Create '\Registry\User' key. */
1479 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\USER");
1480 InitializeObjectAttributes(&ObjectAttributes
,
1482 OBJ_CASE_INSENSITIVE
,
1484 SecurityDescriptor
);
1485 Status
= NtCreateKey(&KeyHandle
,
1486 KEY_READ
| KEY_WRITE
,
1492 if (!NT_SUCCESS(Status
))
1495 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 6, Status
, 0);
1498 /* Close the handle */
1501 /* Initialize the system hive */
1502 if (!CmpInitializeSystemHive(KeLoaderBlock
))
1505 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 7, 0, 0);
1508 /* Create the 'CurrentControlSet' link. */
1509 Status
= CmpCreateControlSet(KeLoaderBlock
);
1510 if (!NT_SUCCESS(Status
))
1513 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 8, Status
, 0);
1516 /* Create the hardware hive */
1517 Status
= CmpInitializeHive((PCMHIVE
*)&HardwareHive
,
1527 if (!NT_SUCCESS(Status
))
1530 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 11, Status
, 0);
1533 /* Add the hive to the hive list */
1534 CmpMachineHiveList
[0].CmHive
= (PCMHIVE
)HardwareHive
;
1536 /* Attach it to the machine key */
1537 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE");
1538 Status
= CmpLinkHiveToMaster(&KeyName
,
1540 (PCMHIVE
)HardwareHive
,
1542 SecurityDescriptor
);
1543 if (!NT_SUCCESS(Status
))
1546 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 12, Status
, 0);
1549 /* FIXME: Add to HiveList key */
1551 /* Free the security descriptor */
1552 ExFreePoolWithTag(SecurityDescriptor
, TAG_CM
);
1554 /* Fill out the Hardware key with the ARC Data from the Loader */
1555 Status
= CmpInitializeHardwareConfiguration(KeLoaderBlock
);
1556 if (!NT_SUCCESS(Status
))
1559 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 13, Status
, 0);
1562 /* Initialize machine-dependent information into the registry */
1563 Status
= CmpInitializeMachineDependentConfiguration(KeLoaderBlock
);
1564 if (!NT_SUCCESS(Status
))
1567 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 14, Status
, 0);
1570 /* Initialize volatile registry settings */
1571 Status
= CmpSetSystemValues(KeLoaderBlock
);
1572 if (!NT_SUCCESS(Status
))
1575 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 15, Status
, 0);
1578 /* Free the load options */
1579 ExFreePoolWithTag(CmpLoadOptions
.Buffer
, TAG_CM
);
1581 /* If we got here, all went well */
1588 CmpFreeDriverList(IN PHHIVE Hive
,
1589 IN PLIST_ENTRY DriverList
)
1591 PLIST_ENTRY NextEntry
, OldEntry
;
1592 PBOOT_DRIVER_NODE DriverNode
;
1595 /* Parse the current list */
1596 NextEntry
= DriverList
->Flink
;
1597 while (NextEntry
!= DriverList
)
1599 /* Get the driver node */
1600 DriverNode
= CONTAINING_RECORD(NextEntry
, BOOT_DRIVER_NODE
, ListEntry
.Link
);
1602 /* Get the next entry now, since we're going to free it later */
1603 OldEntry
= NextEntry
;
1604 NextEntry
= NextEntry
->Flink
;
1606 /* Was there a name? */
1607 if (DriverNode
->Name
.Buffer
)
1610 CmpFree(DriverNode
->Name
.Buffer
, DriverNode
->Name
.Length
);
1613 /* Was there a registry path? */
1614 if (DriverNode
->ListEntry
.RegistryPath
.Buffer
)
1617 CmpFree(DriverNode
->ListEntry
.RegistryPath
.Buffer
,
1618 DriverNode
->ListEntry
.RegistryPath
.MaximumLength
);
1621 /* Was there a file path? */
1622 if (DriverNode
->ListEntry
.FilePath
.Buffer
)
1625 CmpFree(DriverNode
->ListEntry
.FilePath
.Buffer
,
1626 DriverNode
->ListEntry
.FilePath
.MaximumLength
);
1629 /* Now free the node, and move on */
1630 CmpFree(OldEntry
, sizeof(BOOT_DRIVER_NODE
));
1637 CmGetSystemDriverList(VOID
)
1639 LIST_ENTRY DriverList
;
1640 OBJECT_ATTRIBUTES ObjectAttributes
;
1642 PCM_KEY_BODY KeyBody
;
1644 HCELL_INDEX RootCell
, ControlCell
;
1646 UNICODE_STRING KeyName
;
1647 PLIST_ENTRY NextEntry
;
1649 PUNICODE_STRING
* ServicePath
= NULL
;
1650 BOOLEAN Success
, AutoSelect
;
1651 PBOOT_DRIVER_LIST_ENTRY DriverEntry
;
1654 /* Initialize the driver list */
1655 InitializeListHead(&DriverList
);
1657 /* Open the system hive key */
1658 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System");
1659 InitializeObjectAttributes(&ObjectAttributes
,
1661 OBJ_CASE_INSENSITIVE
,
1664 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
1665 if (!NT_SUCCESS(Status
)) return NULL
;
1667 /* Reference the key object to get the root hive/cell to access directly */
1668 Status
= ObReferenceObjectByHandle(KeyHandle
,
1674 if (!NT_SUCCESS(Status
))
1681 /* Do all this under the registry lock */
1682 CmpLockRegistryExclusive();
1684 /* Get the hive and key cell */
1685 Hive
= KeyBody
->KeyControlBlock
->KeyHive
;
1686 RootCell
= KeyBody
->KeyControlBlock
->KeyCell
;
1688 /* Open the current control set key */
1689 RtlInitUnicodeString(&KeyName
, L
"Current");
1690 ControlCell
= CmpFindControlSet(Hive
, RootCell
, &KeyName
, &AutoSelect
);
1691 if (ControlCell
== HCELL_NIL
) goto EndPath
;
1693 /* Find all system drivers */
1694 Success
= CmpFindDrivers(Hive
, ControlCell
, SystemLoad
, NULL
, &DriverList
);
1695 if (!Success
) goto EndPath
;
1697 /* Sort by group/tag */
1698 if (!CmpSortDriverList(Hive
, ControlCell
, &DriverList
)) goto EndPath
;
1700 /* Remove circular dependencies (cycles) and sort */
1701 if (!CmpResolveDriverDependencies(&DriverList
)) goto EndPath
;
1703 /* Loop the list to count drivers */
1704 for (i
= 0, NextEntry
= DriverList
.Flink
;
1705 NextEntry
!= &DriverList
;
1706 i
++, NextEntry
= NextEntry
->Flink
);
1708 /* Allocate the array */
1709 ServicePath
= ExAllocatePool(NonPagedPool
, (i
+ 1) * sizeof(PUNICODE_STRING
));
1710 if (!ServicePath
) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 2, 1, 0, 0);
1712 /* Loop the driver list */
1713 for (i
= 0, NextEntry
= DriverList
.Flink
;
1714 NextEntry
!= &DriverList
;
1715 i
++, NextEntry
= NextEntry
->Flink
)
1718 DriverEntry
= CONTAINING_RECORD(NextEntry
, BOOT_DRIVER_LIST_ENTRY
, Link
);
1720 /* Allocate the path for the caller and duplicate the registry path */
1721 ServicePath
[i
] = ExAllocatePool(NonPagedPool
, sizeof(UNICODE_STRING
));
1722 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1723 &DriverEntry
->RegistryPath
,
1727 /* Terminate the list */
1728 ServicePath
[i
] = NULL
;
1731 /* Free the driver list if we had one */
1732 if (!IsListEmpty(&DriverList
)) CmpFreeDriverList(Hive
, &DriverList
);
1734 /* Unlock the registry */
1735 CmpUnlockRegistry();
1737 /* Close the key handle and dereference the object, then return the path */
1738 ObDereferenceObject(KeyBody
);
1745 CmpLockRegistryExclusive(VOID
)
1747 /* Enter a critical region and lock the registry */
1748 KeEnterCriticalRegion();
1749 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1752 ASSERT(CmpFlushStarveWriters
== 0);
1753 RtlGetCallersAddress(&CmpRegistryLockCaller
, &CmpRegistryLockCallerCaller
);
1758 CmpLockRegistry(VOID
)
1760 /* Enter a critical region */
1761 KeEnterCriticalRegion();
1763 /* Check if we have to starve writers */
1764 if (CmpFlushStarveWriters
)
1766 /* Starve exlusive waiters */
1767 ExAcquireSharedStarveExclusive(&CmpRegistryLock
, TRUE
);
1771 /* Just grab the lock */
1772 ExAcquireResourceSharedLite(&CmpRegistryLock
, TRUE
);
1778 CmpTestRegistryLock(VOID
)
1781 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1786 CmpTestRegistryLockExclusive(VOID
)
1789 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1794 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive
)
1796 /* Lock the flusher. We should already be in a critical section */
1797 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1798 ASSERT((ExIsResourceAcquiredShared(Hive
->FlusherLock
) == 0) &&
1799 (ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) == 0));
1800 ExAcquireResourceExclusiveLite(Hive
->FlusherLock
, TRUE
);
1805 CmpLockHiveFlusherShared(IN PCMHIVE Hive
)
1807 /* Lock the flusher. We should already be in a critical section */
1808 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1809 ASSERT((ExIsResourceAcquiredShared(Hive
->FlusherLock
) == 0) &&
1810 (ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) == 0));
1811 ExAcquireResourceSharedLite(Hive
->FlusherLock
, TRUE
);
1816 CmpUnlockHiveFlusher(IN PCMHIVE Hive
)
1819 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
1820 CMP_ASSERT_FLUSH_LOCK(Hive
);
1822 /* Release the lock */
1823 ExReleaseResourceLite(Hive
->FlusherLock
);
1828 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive
)
1831 return !ExIsResourceAcquiredSharedLite(Hive
->FlusherLock
) ? FALSE
: TRUE
;
1836 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive
)
1839 return !ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) ? FALSE
: TRUE
;
1844 CmpUnlockRegistry(VOID
)
1847 CMP_ASSERT_REGISTRY_LOCK();
1849 /* Check if we should flush the registry */
1850 if (CmpFlushOnLockRelease
)
1852 /* The registry should be exclusively locked for this */
1853 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1855 /* Flush the registry */
1856 CmpDoFlushAll(TRUE
);
1857 CmpFlushOnLockRelease
= FALSE
;
1860 /* Release the lock and leave the critical region */
1861 ExReleaseResourceLite(&CmpRegistryLock
);
1862 KeLeaveCriticalRegion();
1867 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1
,
1870 ULONG Index1
, Index2
;
1873 CMP_ASSERT_REGISTRY_LOCK();
1875 /* Get hash indexes */
1876 Index1
= GET_HASH_INDEX(ConvKey1
);
1877 Index2
= GET_HASH_INDEX(ConvKey2
);
1879 /* See which one is highest */
1880 if (Index1
< Index2
)
1882 /* Grab them in the proper order */
1883 CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1884 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1888 /* Grab the second one first, then the first */
1889 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
1890 if (Index1
!= Index2
) CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
1896 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1
,
1899 ULONG Index1
, Index2
;
1902 CMP_ASSERT_REGISTRY_LOCK();
1904 /* Get hash indexes */
1905 Index1
= GET_HASH_INDEX(ConvKey1
);
1906 Index2
= GET_HASH_INDEX(ConvKey2
);
1907 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey2
).Owner
== KeGetCurrentThread()) ||
1908 (CmpTestRegistryLockExclusive()));
1910 /* See which one is highest */
1911 if (Index1
< Index2
)
1913 /* Grab them in the proper order */
1914 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1915 (CmpTestRegistryLockExclusive()));
1916 CmpReleaseKcbLockByKey(ConvKey2
);
1917 CmpReleaseKcbLockByKey(ConvKey1
);
1921 /* Release the first one first, then the second */
1922 if (Index1
!= Index2
)
1924 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
).Owner
== KeGetCurrentThread()) ||
1925 (CmpTestRegistryLockExclusive()));
1926 CmpReleaseKcbLockByKey(ConvKey1
);
1928 CmpReleaseKcbLockByKey(ConvKey2
);
1934 CmShutdownSystem(VOID
)
1936 /* Kill the workers */
1937 if (!CmFirstTime
) CmpShutdownWorkers();
1939 /* Flush all hives */
1940 CmpLockRegistryExclusive();
1941 CmpDoFlushAll(TRUE
);
1942 CmpUnlockRegistry();
1947 CmpSetVersionData(VOID
)
1949 OBJECT_ATTRIBUTES ObjectAttributes
;
1950 UNICODE_STRING KeyName
;
1951 UNICODE_STRING ValueName
;
1952 UNICODE_STRING ValueData
;
1953 HANDLE SoftwareKeyHandle
= NULL
;
1954 HANDLE MicrosoftKeyHandle
= NULL
;
1955 HANDLE WindowsNtKeyHandle
= NULL
;
1956 HANDLE CurrentVersionKeyHandle
= NULL
;
1960 /* Open the 'CurrentVersion' key */
1961 RtlInitUnicodeString(&KeyName
,
1962 L
"\\REGISTRY\\MACHINE\\SOFTWARE");
1964 InitializeObjectAttributes(&ObjectAttributes
,
1966 OBJ_CASE_INSENSITIVE
,
1970 Status
= NtCreateKey(&SoftwareKeyHandle
,
1977 if (!NT_SUCCESS(Status
))
1979 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
1983 /* Open the 'CurrentVersion' key */
1984 RtlInitUnicodeString(&KeyName
,
1987 InitializeObjectAttributes(&ObjectAttributes
,
1989 OBJ_CASE_INSENSITIVE
,
1993 Status
= NtCreateKey(&MicrosoftKeyHandle
,
2000 if (!NT_SUCCESS(Status
))
2002 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2006 /* Open the 'CurrentVersion' key */
2007 RtlInitUnicodeString(&KeyName
,
2010 InitializeObjectAttributes(&ObjectAttributes
,
2012 OBJ_CASE_INSENSITIVE
,
2016 Status
= NtCreateKey(&WindowsNtKeyHandle
,
2023 if (!NT_SUCCESS(Status
))
2025 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2029 /* Open the 'CurrentVersion' key */
2030 RtlInitUnicodeString(&KeyName
,
2033 InitializeObjectAttributes(&ObjectAttributes
,
2035 OBJ_CASE_INSENSITIVE
,
2039 Status
= NtCreateKey(&CurrentVersionKeyHandle
,
2040 KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
2046 if (!NT_SUCCESS(Status
))
2048 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2052 /* Set the 'CurrentType' value */
2053 RtlInitUnicodeString(&ValueName
,
2057 wcscpy(Buffer
, L
"Multiprocessor");
2059 wcscpy(Buffer
, L
"Uniprocessor");
2062 wcscat(Buffer
, L
" ");
2065 wcscat(Buffer
, L
"Checked");
2067 wcscat(Buffer
, L
"Free");
2070 RtlInitUnicodeString(&ValueData
,
2073 NtSetValueKey(CurrentVersionKeyHandle
,
2078 ValueData
.Length
+ sizeof(WCHAR
));
2081 /* Close the keys */
2082 if (CurrentVersionKeyHandle
!= NULL
)
2083 NtClose(CurrentVersionKeyHandle
);
2085 if (WindowsNtKeyHandle
!= NULL
)
2086 NtClose(WindowsNtKeyHandle
);
2088 if (MicrosoftKeyHandle
!= NULL
)
2089 NtClose(MicrosoftKeyHandle
);
2091 if (SoftwareKeyHandle
!= NULL
)
2092 NtClose(SoftwareKeyHandle
);