- Fix prototype of NtLoadKeyEx.
[reactos.git] / reactos / ntoskrnl / config / cmsysini.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmsysini.c
5 * PURPOSE: Configuration Manager - System Initialization Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #include "cm.h"
13 #define NDEBUG
14 #include "debug.h"
15
16 KGUARDED_MUTEX CmpSelfHealQueueLock;
17 LIST_ENTRY CmpSelfHealQueueListHead;
18 KEVENT CmpLoadWorkerEvent;
19 LONG CmpLoadWorkerIncrement;
20 PEPROCESS CmpSystemProcess;
21 BOOLEAN HvShutdownComplete;
22 PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller;
23 BOOLEAN CmpFlushStarveWriters;
24 BOOLEAN CmpFlushOnLockRelease;
25 BOOLEAN CmpSpecialBootCondition;
26 BOOLEAN CmpNoWrite;
27 BOOLEAN CmpForceForceFlush;
28 BOOLEAN CmpWasSetupBoot;
29
30 /* FUNCTIONS *****************************************************************/
31
32 NTSTATUS
33 NTAPI
34 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,
35 IN ULONG HiveFlags,
36 OUT PCMHIVE *Hive,
37 IN OUT PBOOLEAN New,
38 IN ULONG CheckFlags)
39 {
40 ULONG HiveDisposition, LogDisposition;
41 HANDLE FileHandle = NULL, LogHandle = NULL;
42 NTSTATUS Status;
43 ULONG Operation, FileType;
44 PCMHIVE NewHive;
45 PAGED_CODE();
46
47 /* Assume failure */
48 *Hive = NULL;
49
50 /* Open or create the hive files */
51 Status = CmpOpenHiveFiles(HiveName,
52 L".LOG",
53 &FileHandle,
54 &LogHandle,
55 &HiveDisposition,
56 &LogDisposition,
57 *New,
58 FALSE,
59 TRUE,
60 NULL);
61 if (!NT_SUCCESS(Status)) return Status;
62
63 /* Check if we have a log handle */
64 FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY;
65
66 /* Check if we created or opened the hive */
67 if (HiveDisposition == FILE_CREATED)
68 {
69 /* Do a create operation */
70 Operation = HINIT_CREATE;
71 *New = TRUE;
72 }
73 else
74 {
75 /* Open it as a file */
76 Operation = HINIT_FILE;
77 *New = FALSE;
78 }
79
80 /* Check if we're sharing hives */
81 if (CmpShareSystemHives)
82 {
83 /* Then force using the primary hive */
84 FileType = HFILE_TYPE_PRIMARY;
85 if (LogHandle)
86 {
87 /* Get rid of the log handle */
88 ZwClose(LogHandle);
89 LogHandle = NULL;
90 }
91 }
92
93 /* Check if we're too late */
94 if (HvShutdownComplete)
95 {
96 /* Fail */
97 ZwClose(FileHandle);
98 if (LogHandle) ZwClose(LogHandle);
99 return STATUS_TOO_LATE;
100 }
101
102 /* Initialize the hive */
103 Status = CmpInitializeHive((PCMHIVE*)&NewHive,
104 Operation,
105 HiveFlags,
106 FileType,
107 NULL,
108 FileHandle,
109 LogHandle,
110 NULL,
111 HiveName,
112 0);
113 if (!NT_SUCCESS(Status))
114 {
115 /* Fail */
116 ZwClose(FileHandle);
117 if (LogHandle) ZwClose(LogHandle);
118 return Status;
119 }
120
121 /* Success, return hive */
122 *Hive = NewHive;
123
124 /* ROS: Init root key cell and prepare the hive */
125 if (Operation == HINIT_CREATE) CmCreateRootNode(&NewHive->Hive, L"");
126 CmPrepareHive(&NewHive->Hive);
127
128 /* Duplicate the hive name */
129 NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool,
130 HiveName->Length,
131 TAG_CM);
132 if (NewHive->FileFullPath.Buffer)
133 {
134 /* Copy the string */
135 RtlCopyMemory(NewHive->FileFullPath.Buffer,
136 HiveName->Buffer,
137 HiveName->Length);
138 NewHive->FileFullPath.Length = HiveName->Length;
139 NewHive->FileFullPath.MaximumLength = HiveName->MaximumLength;
140 }
141
142 /* ROS: Close the hive files */
143 ZwClose(FileHandle);
144 if (LogHandle) ZwClose(LogHandle);
145
146 /* Return success */
147 return STATUS_SUCCESS;
148 }
149
150 NTSTATUS
151 NTAPI
152 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
153 {
154 OBJECT_ATTRIBUTES ObjectAttributes;
155 UNICODE_STRING KeyName, ValueName;
156 HANDLE KeyHandle;
157 NTSTATUS Status;
158 ASSERT(LoaderBlock != NULL);
159 if (ExpInTextModeSetup) return STATUS_SUCCESS;
160
161 /* Setup attributes for loader options */
162 RtlInitUnicodeString(&KeyName,
163 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
164 L"Control");
165 InitializeObjectAttributes(&ObjectAttributes,
166 &KeyName,
167 OBJ_CASE_INSENSITIVE,
168 NULL,
169 NULL);
170 Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
171 if (!NT_SUCCESS(Status)) goto Quickie;
172
173 /* Key opened, now write to the key */
174 RtlInitUnicodeString(&KeyName, L"SystemStartOptions");
175 Status = NtSetValueKey(KeyHandle,
176 &KeyName,
177 0,
178 REG_SZ,
179 CmpLoadOptions.Buffer,
180 CmpLoadOptions.Length);
181 if (!NT_SUCCESS(Status)) goto Quickie;
182
183 /* Setup value name for system boot device */
184 RtlInitUnicodeString(&KeyName, L"SystemBootDevice");
185 RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->NtBootPathName);
186 Status = NtSetValueKey(KeyHandle,
187 &KeyName,
188 0,
189 REG_SZ,
190 ValueName.Buffer,
191 ValueName.Length);
192
193 Quickie:
194 /* Free the buffers */
195 RtlFreeUnicodeString(&ValueName);
196
197 /* Close the key and return */
198 NtClose(KeyHandle);
199
200 /* Return the status */
201 return Status;
202 }
203
204 NTSTATUS
205 NTAPI
206 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
207 {
208 UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB");
209 UNICODE_STRING SelectName =
210 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select");
211 UNICODE_STRING KeyName;
212 OBJECT_ATTRIBUTES ObjectAttributes;
213 CHAR ValueInfoBuffer[128];
214 PKEY_VALUE_FULL_INFORMATION ValueInfo;
215 CHAR Buffer[128];
216 WCHAR UnicodeBuffer[128];
217 HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL;
218 HANDLE ParentHandle = NULL;
219 ULONG ControlSet, HwProfile;
220 ANSI_STRING TempString;
221 NTSTATUS Status;
222 ULONG ResultLength, Disposition;
223 PLOADER_PARAMETER_EXTENSION LoaderExtension;
224 PAGED_CODE();
225 if (ExpInTextModeSetup) return STATUS_SUCCESS;
226
227 /* Open the select key */
228 InitializeObjectAttributes(&ObjectAttributes,
229 &SelectName,
230 OBJ_CASE_INSENSITIVE,
231 NULL,
232 NULL);
233 Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes);
234 if (!NT_SUCCESS(Status)) return(Status);
235
236 /* Open the current value */
237 RtlInitUnicodeString(&KeyName, L"Current");
238 Status = NtQueryValueKey(SelectHandle,
239 &KeyName,
240 KeyValueFullInformation,
241 ValueInfoBuffer,
242 sizeof(ValueInfoBuffer),
243 &ResultLength);
244 NtClose(SelectHandle);
245 if (!NT_SUCCESS(Status)) return Status;
246
247 /* Get the actual value pointer, and get the control set ID */
248 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
249 ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
250
251 /* Create the current control set key */
252 RtlInitUnicodeString(&KeyName,
253 L"\\Registry\\Machine\\System\\CurrentControlSet");
254 InitializeObjectAttributes(&ObjectAttributes,
255 &KeyName,
256 OBJ_CASE_INSENSITIVE,
257 NULL,
258 NULL);
259
260 Status = NtCreateKey(&KeyHandle,
261 KEY_CREATE_LINK,
262 &ObjectAttributes,
263 0,
264 NULL,
265 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
266 &Disposition);
267 if (!NT_SUCCESS(Status)) return Status;
268
269 /* Sanity check */
270 ASSERT(Disposition == REG_CREATED_NEW_KEY);
271
272 /* Initialize the symbolic link name */
273 sprintf(Buffer,
274 "\\Registry\\Machine\\System\\ControlSet%03ld",
275 ControlSet);
276 RtlInitAnsiString(&TempString, Buffer);
277
278 /* Create a Unicode string out of it */
279 KeyName.MaximumLength = sizeof(UnicodeBuffer);
280 KeyName.Buffer = UnicodeBuffer;
281 Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
282
283 /* Set the value */
284 Status = NtSetValueKey(KeyHandle,
285 &CmSymbolicLinkValueName,
286 0,
287 REG_LINK,
288 KeyName.Buffer,
289 KeyName.Length);
290 if (!NT_SUCCESS(Status)) return Status;
291
292 /* Get the configuration database key */
293 InitializeObjectAttributes(&ObjectAttributes,
294 &ConfigName,
295 OBJ_CASE_INSENSITIVE,
296 KeyHandle,
297 NULL);
298 Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes);
299 NtClose(KeyHandle);
300
301 /* Check if we don't have one */
302 if (!NT_SUCCESS(Status))
303 {
304 /* Cleanup and exit */
305 ConfigHandle = 0;
306 goto Cleanup;
307 }
308
309 /* Now get the current config */
310 RtlInitUnicodeString(&KeyName, L"CurrentConfig");
311 Status = NtQueryValueKey(ConfigHandle,
312 &KeyName,
313 KeyValueFullInformation,
314 ValueInfoBuffer,
315 sizeof(ValueInfoBuffer),
316 &ResultLength);
317
318 /* Set pointer to buffer */
319 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
320
321 /* Check if we failed or got a non DWORD-value */
322 if (!(NT_SUCCESS(Status)) || (ValueInfo->Type != REG_DWORD)) goto Cleanup;
323
324 /* Get the hadware profile */
325 HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
326
327 /* Open the hardware profile key */
328 RtlInitUnicodeString(&KeyName,
329 L"\\Registry\\Machine\\System\\CurrentControlSet"
330 L"\\Hardware Profiles");
331 InitializeObjectAttributes(&ObjectAttributes,
332 &KeyName,
333 OBJ_CASE_INSENSITIVE,
334 NULL,
335 NULL);
336 Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes);
337 if (!NT_SUCCESS(Status))
338 {
339 /* Exit and clean up */
340 ParentHandle = 0;
341 goto Cleanup;
342 }
343
344 /* Build the profile name */
345 sprintf(Buffer, "%04ld", HwProfile);
346 RtlInitAnsiString(&TempString, Buffer);
347
348 /* Convert it to Unicode */
349 KeyName.MaximumLength = sizeof(UnicodeBuffer);
350 KeyName.Buffer = UnicodeBuffer;
351 Status = RtlAnsiStringToUnicodeString(&KeyName,
352 &TempString,
353 FALSE);
354 ASSERT(Status == STATUS_SUCCESS);
355
356 /* Open the associated key */
357 InitializeObjectAttributes(&ObjectAttributes,
358 &KeyName,
359 OBJ_CASE_INSENSITIVE,
360 ParentHandle,
361 NULL);
362 Status = NtOpenKey(&ProfileHandle,
363 KEY_READ | KEY_WRITE,
364 &ObjectAttributes);
365 if (!NT_SUCCESS (Status))
366 {
367 /* Cleanup and exit */
368 ProfileHandle = 0;
369 goto Cleanup;
370 }
371
372 /* Check if we have a loader block extension */
373 LoaderExtension = LoaderBlock->Extension;
374 if (LoaderExtension)
375 {
376 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE);
377 }
378
379 /* Create the current hardware profile key */
380 RtlInitUnicodeString(&KeyName,
381 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
382 L"Hardware Profiles\\Current");
383 InitializeObjectAttributes(&ObjectAttributes,
384 &KeyName,
385 OBJ_CASE_INSENSITIVE,
386 NULL,
387 NULL);
388 Status = NtCreateKey(&KeyHandle,
389 KEY_CREATE_LINK,
390 &ObjectAttributes,
391 0,
392 NULL,
393 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
394 &Disposition);
395 if (NT_SUCCESS(Status))
396 {
397 /* Sanity check */
398 ASSERT(Disposition == REG_CREATED_NEW_KEY);
399
400 /* Create the profile name */
401 sprintf(Buffer,
402 "\\Registry\\Machine\\System\\CurrentControlSet\\"
403 "Hardware Profiles\\%04ld",
404 HwProfile);
405 RtlInitAnsiString(&TempString, Buffer);
406
407 /* Convert it to Unicode */
408 KeyName.MaximumLength = sizeof(UnicodeBuffer);
409 KeyName.Buffer = UnicodeBuffer;
410 Status = RtlAnsiStringToUnicodeString(&KeyName,
411 &TempString,
412 FALSE);
413 ASSERT(STATUS_SUCCESS == Status);
414
415 /* Set it */
416 Status = NtSetValueKey(KeyHandle,
417 &CmSymbolicLinkValueName,
418 0,
419 REG_LINK,
420 KeyName.Buffer,
421 KeyName.Length);
422 NtClose(KeyHandle);
423 }
424
425 /* Close every opened handle */
426 Cleanup:
427 if (ConfigHandle) NtClose(ConfigHandle);
428 if (ProfileHandle) NtClose(ProfileHandle);
429 if (ParentHandle) NtClose(ParentHandle);
430
431 /* Return success */
432 return STATUS_SUCCESS;
433 }
434
435 BOOLEAN
436 NTAPI
437 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
438 {
439 PVOID HiveBase;
440 ANSI_STRING LoadString;
441 PVOID Buffer;
442 ULONG Length;
443 NTSTATUS Status;
444 BOOLEAN Allocate;
445 UNICODE_STRING KeyName;
446 PCMHIVE SystemHive = NULL;
447 UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM");
448 PSECURITY_DESCRIPTOR SecurityDescriptor;
449 PAGED_CODE();
450
451 /* Setup the ansi string */
452 RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions);
453
454 /* Allocate the unicode buffer */
455 Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL);
456 Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
457 if (!Buffer)
458 {
459 /* Fail */
460 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0);
461 }
462
463 /* Setup the unicode string */
464 RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length);
465
466 /* Add the load options and null-terminate */
467 RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);
468 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;
469 CmpLoadOptions.Length += sizeof(WCHAR);
470
471 /* Get the System Hive base address */
472 HiveBase = LoaderBlock->RegistryBase;
473 if (HiveBase)
474 {
475 /* Import it */
476 ((PHBASE_BLOCK)HiveBase)->Length = LoaderBlock->RegistryLength;
477 Status = CmpInitializeHive((PCMHIVE*)&SystemHive,
478 HINIT_MEMORY,
479 0, //HIVE_NOLAZYFLUSH,
480 HFILE_TYPE_LOG,
481 HiveBase,
482 NULL,
483 NULL,
484 NULL,
485 &HiveName,
486 2);
487 if (!NT_SUCCESS(Status)) return FALSE;
488 CmPrepareHive(&SystemHive->Hive);
489
490 /* Set the hive filename */
491 RtlCreateUnicodeString(&SystemHive->FileFullPath, SYSTEM_REG_FILE);
492
493 /* We imported, no need to create a new hive */
494 Allocate = FALSE;
495
496 /* Manually set the hive as volatile, if in Live CD mode */
497 if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
498 }
499 else
500 {
501 /* Create it */
502 #if 0
503 Status = CmpInitializeHive(&SystemHive,
504 HINIT_CREATE,
505 0, //HIVE_NOLAZYFLUSH,
506 HFILE_TYPE_LOG,
507 NULL,
508 NULL,
509 NULL,
510 NULL,
511 &HiveName,
512 0);
513 if (!NT_SUCCESS(Status)) return FALSE;
514
515 /* Set the hive filename */
516 RtlCreateUnicodeString(&SystemHive->FileFullPath, SYSTEM_REG_FILE);
517 #endif
518 /* Tell CmpLinkHiveToMaster to allocate a hive */
519 Allocate = TRUE;
520 }
521
522 /* Save the boot type */
523 if (SystemHive) CmpBootType = SystemHive->Hive.BaseBlock->BootType;
524
525 /* Are we in self-healing mode? */
526 if (!CmSelfHeal)
527 {
528 /* Disable self-healing internally and check if boot type wanted it */
529 CmpSelfHeal = FALSE;
530 if (CmpBootType & 4)
531 {
532 /* We're disabled, so bugcheck */
533 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO,
534 3,
535 3,
536 (ULONG_PTR)SystemHive,
537 0);
538 }
539 }
540
541 /* Create the default security descriptor */
542 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
543
544 /* Attach it to the system key */
545 RtlInitUnicodeString(&KeyName, REG_SYSTEM_KEY_NAME);
546 Status = CmpLinkHiveToMaster(&KeyName,
547 NULL,
548 (PCMHIVE)SystemHive,
549 Allocate,
550 SecurityDescriptor);
551
552 /* Free the security descriptor */
553 ExFreePool(SecurityDescriptor);
554 if (!NT_SUCCESS(Status)) return FALSE;
555
556 /* Add the hive to the hive list */
557 CmpMachineHiveList[3].CmHive = (PCMHIVE)SystemHive;
558
559 /* Success! */
560 return TRUE;
561 }
562
563 NTSTATUS
564 NTAPI
565 CmpCreateObjectTypes(VOID)
566 {
567 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
568 UNICODE_STRING Name;
569 GENERIC_MAPPING CmpKeyMapping = {KEY_READ,
570 KEY_WRITE,
571 KEY_EXECUTE,
572 KEY_ALL_ACCESS};
573 PAGED_CODE();
574
575 /* Initialize the Key object type */
576 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
577 RtlInitUnicodeString(&Name, L"Key");
578 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
579 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
580 ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
581 ObjectTypeInitializer.PoolType = PagedPool;
582 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
583 ObjectTypeInitializer.UseDefaultObject = TRUE;
584 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
585 ObjectTypeInitializer.ParseProcedure = CmpParseKey;
586 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
587 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
588 //ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
589 ObjectTypeInitializer.SecurityRequired = TRUE;
590
591 /* Create it */
592 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);
593 }
594
595 BOOLEAN
596 NTAPI
597 CmpCreateRootNode(IN PHHIVE Hive,
598 IN PCWSTR Name,
599 OUT PHCELL_INDEX Index)
600 {
601 UNICODE_STRING KeyName;
602 PCM_KEY_NODE KeyCell;
603 LARGE_INTEGER SystemTime;
604 PAGED_CODE();
605
606 /* Initialize the node name and allocate it */
607 RtlInitUnicodeString(&KeyName, Name);
608 *Index = HvAllocateCell(Hive,
609 FIELD_OFFSET(CM_KEY_NODE, Name) +
610 CmpNameSize(Hive, &KeyName),
611 Stable,
612 HCELL_NIL);
613 if (*Index == HCELL_NIL) return FALSE;
614
615 /* Set the cell index and get the data */
616 Hive->BaseBlock->RootCell = *Index;
617 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);
618 if (!KeyCell) return FALSE;
619
620 /* Setup the cell */
621 KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE;
622 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
623 KeQuerySystemTime(&SystemTime);
624 KeyCell->LastWriteTime = SystemTime;
625 KeyCell->Parent = HCELL_NIL;
626 KeyCell->SubKeyCounts[Stable] = 0;
627 KeyCell->SubKeyCounts[Volatile] = 0;
628 KeyCell->SubKeyLists[Stable] = HCELL_NIL;
629 KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
630 KeyCell->ValueList.Count = 0;
631 KeyCell->ValueList.List = HCELL_NIL;
632 KeyCell->Security = HCELL_NIL;
633 KeyCell->Class = HCELL_NIL;
634 KeyCell->ClassLength = 0;
635 KeyCell->MaxNameLen = 0;
636 KeyCell->MaxClassLen = 0;
637 KeyCell->MaxValueNameLen = 0;
638 KeyCell->MaxValueDataLen = 0;
639
640 /* Copy the name (this will also set the length) */
641 KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName);
642
643 /* Check if the name was compressed */
644 if (KeyCell->NameLength < KeyName.Length)
645 {
646 /* Set the flag */
647 KeyCell->Flags |= KEY_COMP_NAME;
648 }
649
650 /* Return success */
651 HvReleaseCell(Hive, *Index);
652 return TRUE;
653 }
654
655 BOOLEAN
656 NTAPI
657 CmpCreateRegistryRoot(VOID)
658 {
659 UNICODE_STRING KeyName;
660 OBJECT_ATTRIBUTES ObjectAttributes;
661 #if 0
662 PCM_KEY_BODY RootKey;
663 #else
664 PKEY_OBJECT RootKey;
665 #endif
666 HCELL_INDEX RootIndex;
667 NTSTATUS Status;
668 PCM_KEY_NODE KeyCell;
669 PSECURITY_DESCRIPTOR SecurityDescriptor;
670 PCM_KEY_CONTROL_BLOCK Kcb;
671 PAGED_CODE();
672
673 /* Setup the root node */
674 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))
675 {
676 /* We failed */
677 return FALSE;
678 }
679
680 /* Create '\Registry' key. */
681 RtlInitUnicodeString(&KeyName, L"\\Registry");
682 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
683 InitializeObjectAttributes(&ObjectAttributes,
684 &KeyName,
685 OBJ_CASE_INSENSITIVE,
686 NULL,
687 NULL);
688 Status = ObCreateObject(KernelMode,
689 CmpKeyObjectType,
690 &ObjectAttributes,
691 KernelMode,
692 NULL,
693 sizeof(KEY_OBJECT),
694 0,
695 0,
696 (PVOID*)&RootKey);
697 ExFreePool(SecurityDescriptor);
698 if (!NT_SUCCESS(Status)) return FALSE;
699
700 /* Sanity check, and get the key cell */
701 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);
702 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);
703 if (!KeyCell) return FALSE;
704
705 /* Create the KCB */
706 RtlInitUnicodeString(&KeyName, L"Registry");
707 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,
708 RootIndex,
709 KeyCell,
710 NULL,
711 0,
712 &KeyName);
713 if (!Kcb) return FALSE;
714
715 /* Initialize the object */
716 RootKey->Type = TAG('k', 'v', '0', '2');
717 RootKey->KeyControlBlock = Kcb;
718 #if 0
719 RootKey->NotifyBlock = NULL;
720 RootKey->ProcessID = PsGetCurrentProcessId();
721 #else
722 RtlpCreateUnicodeString(&RootKey->Name, L"Registry", NonPagedPool);
723 RootKey->SubKeyCounts = 0;
724 RootKey->SubKeys = NULL;
725 RootKey->SizeOfSubKeys = 0;
726 #endif
727
728 /* Insert it into the object list head */
729 EnlistKeyBodyWithKeyObject(RootKey, 0);
730
731 /* Insert the key into the namespace */
732 Status = ObInsertObject(RootKey,
733 NULL,
734 KEY_ALL_ACCESS,
735 0,
736 NULL,
737 &CmpRegistryRootHandle);
738 if (!NT_SUCCESS(Status)) return FALSE;
739
740 /* Reference the key again so that we never lose it */
741 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
742 KEY_READ,
743 NULL,
744 KernelMode,
745 (PVOID*)&RootKey,
746 NULL);
747 if (!NT_SUCCESS(Status)) return FALSE;
748
749 /* Completely sucessful */
750 return TRUE;
751 }
752
753 VOID
754 NTAPI
755 CmpLoadHiveThread(IN PVOID StartContext)
756 {
757 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH];
758 UNICODE_STRING TempName, FileName, RegName;
759 ULONG FileStart, RegStart, i, ErrorResponse, ClusterSize, WorkerCount;
760 ULONG PrimaryDisposition, SecondaryDisposition, Length;
761 PCMHIVE CmHive;
762 HANDLE PrimaryHandle, LogHandle;
763 NTSTATUS Status = STATUS_SUCCESS;
764 PVOID ErrorParameters;
765 PAGED_CODE();
766
767 /* Get the hive index, make sure it makes sense */
768 i = (ULONG)StartContext;
769 ASSERT(CmpMachineHiveList[i].Name != NULL);
770 DPRINT1("[HiveLoad] Parallel Thread: %d\n", i);
771
772 /* We were started */
773 CmpMachineHiveList[i].ThreadStarted = TRUE;
774
775 /* Build the file name and registry name strings */
776 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
777 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
778
779 /* Now build the system root path */
780 RtlInitUnicodeString(&TempName, L"\\SystemRoot\\System32\\Config\\");
781 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
782 FileStart = FileName.Length;
783
784 /* And build the registry root path */
785 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
786 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
787 RegStart = RegName.Length;
788
789 /* Build the base name */
790 RegName.Length = RegStart;
791 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
792 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
793
794 /* Check if this is a child of the root */
795 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
796 {
797 /* Then setup the whole name */
798 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
799 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
800 }
801
802 /* Now Add tge rest if the file name */
803 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
804 FileName.Length = FileStart;
805 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
806 if (!CmpMachineHiveList[i].CmHive)
807 {
808 /* We need to allocate a ne whive structure */
809 CmpMachineHiveList[i].Allocate = TRUE;
810
811 /* Load the hive file */
812 DPRINT1("[HiveLoad]: Load from file %wZ\n", &FileName);
813 CmpMachineHiveList[i].CmHive2 = (PVOID)0xBAADBEEF;
814 goto Later;
815 Status = CmpInitHiveFromFile(&FileName,
816 CmpMachineHiveList[i].HHiveFlags,
817 &CmHive,
818 &CmpMachineHiveList[i].Allocate,
819 0);
820 if (!(NT_SUCCESS(Status)) || !(CmHive->FileHandles[HFILE_TYPE_LOG]))
821 {
822 /* We failed or couldn't get a log file, raise a hard error */
823 ErrorParameters = &FileName;
824 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
825 1,
826 1,
827 (PULONG_PTR)&ErrorParameters,
828 OptionOk,
829 &ErrorResponse);
830 }
831
832 /* Set the hive flags and newly allocated hive pointer */
833 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
834 CmpMachineHiveList[i].CmHive2 = CmHive;
835 }
836 else
837 {
838 /* We already have a hive, is it volatile? */
839 CmHive = CmpMachineHiveList[i].CmHive;
840 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
841 {
842 DPRINT1("[HiveLoad]: Open from file %wZ\n", &FileName);
843 CmpMachineHiveList[i].CmHive2 = CmHive;
844 goto Later;
845
846 /* It's now, open the hive file and log */
847 Status = CmpOpenHiveFiles(&FileName,
848 L".LOG",
849 &PrimaryHandle,
850 &LogHandle,
851 &PrimaryDisposition,
852 &SecondaryDisposition,
853 TRUE,
854 TRUE,
855 FALSE,
856 &ClusterSize);
857 if (!(NT_SUCCESS(Status)) || !(LogHandle))
858 {
859 /* Couldn't open the hive or its log file, raise a hard error */
860 ErrorParameters = &FileName;
861 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
862 1,
863 1,
864 (PULONG_PTR)&ErrorParameters,
865 OptionOk,
866 &ErrorResponse);
867
868 /* And bugcheck for posterity's sake */
869 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);
870 }
871
872 /* Save the file handles. This should remove our sync hacks */
873 CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
874 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
875
876 /* Allow lazy flushing since the handles are there -- remove sync hacks */
877 ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
878 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
879
880 /* Get the real size of the hive */
881 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
882
883 /* Check if the cluster size doesn't match */
884 if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);
885
886 /* Set the file size */
887 if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
888 {
889 /* This shouldn't fail */
890 ASSERT(FALSE);
891 }
892
893 /* Another thing we don't support is NTLDR-recovery */
894 if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE);
895
896 /* Finally, set our allocated hive to the same hive we've had */
897 CmpMachineHiveList[i].CmHive2 = CmHive;
898 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);
899 }
900 }
901
902 /* We're done */
903 Later:
904 CmpMachineHiveList[i].ThreadFinished = TRUE;
905
906 /* Check if we're the last worker */
907 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);
908 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)
909
910 {
911 /* Signal the event */
912 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);
913 }
914
915 /* Kill the thread */
916 PsTerminateSystemThread(Status);
917 }
918
919 VOID
920 NTAPI
921 CmpInitializeHiveList(IN USHORT Flag)
922 {
923 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH];
924 UNICODE_STRING TempName, FileName, RegName;
925 HANDLE Thread;
926 NTSTATUS Status;
927 ULONG FileStart, RegStart, i;
928 PSECURITY_DESCRIPTOR SecurityDescriptor;
929 PAGED_CODE();
930
931 /* Allow writing for now */
932 CmpNoWrite = FALSE;
933
934 /* Build the file name and registry name strings */
935 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
936 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
937
938 /* Now build the system root path */
939 RtlInitUnicodeString(&TempName, L"\\SystemRoot\\System32\\Config\\");
940 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
941 FileStart = FileName.Length;
942
943 /* And build the registry root path */
944 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
945 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
946 RegStart = RegName.Length;
947
948 /* Setup the event to synchronize workers */
949 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
950
951 /* Enter special boot condition */
952 CmpSpecialBootCondition = TRUE;
953
954 /* Create the SD for the root hives */
955 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
956
957 /* Loop every hive we care about */
958 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
959 {
960 /* Make sure the list is setup */
961 ASSERT(CmpMachineHiveList[i].Name != NULL);
962
963 /* Create a thread to handle this hive */
964 Status = PsCreateSystemThread(&Thread,
965 THREAD_ALL_ACCESS,
966 NULL,
967 0,
968 NULL,
969 CmpLoadHiveThread,
970 (PVOID)i);
971 if (NT_SUCCESS(Status))
972 {
973 /* We don't care about the handle -- the thread self-terminates */
974 ZwClose(Thread);
975 }
976 else
977 {
978 /* Can't imagine this happening */
979 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);
980 }
981 }
982
983 /* Make sure we've reached the end of the list */
984 ASSERT(CmpMachineHiveList[i].Name == NULL);
985
986 /* Wait for hive loading to finish */
987 KeWaitForSingleObject(&CmpLoadWorkerEvent,
988 Executive,
989 KernelMode,
990 FALSE,
991 NULL);
992
993 /* Exit the special boot condition and make sure all workers completed */
994 CmpSpecialBootCondition = FALSE;
995 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);
996
997 /* Loop hives again */
998 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
999 {
1000 /* Make sure the thread ran and finished */
1001 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);
1002 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);
1003
1004 /* Check if this was a new hive */
1005 if (!CmpMachineHiveList[i].CmHive)
1006 {
1007 /* Make sure we allocated something */
1008 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);
1009
1010 /* Build the base name */
1011 RegName.Length = RegStart;
1012 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1013 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1014
1015 /* Check if this is a child of the root */
1016 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1017 {
1018 /* Then setup the whole name */
1019 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1020 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1021 }
1022
1023 /* Now link the hive to its master */
1024 DPRINT1("[HiveLoad]: Link %wZ\n", &RegName);
1025 #if 0
1026 Status = CmpLinkHiveToMaster(&RegName,
1027 NULL,
1028 CmpMachineHiveList[i].CmHive2,
1029 CmpMachineHiveList[i].Allocate,
1030 SecurityDescriptor);
1031 if (Status != STATUS_SUCCESS)
1032 {
1033 /* Linking needs to work */
1034 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);
1035 }
1036
1037 /* Check if we had to allocate a new hive */
1038 if (CmpMachineHiveList[i].Allocate)
1039 {
1040 /* Sync the new hive */
1041 HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1042 }
1043 #endif
1044 }
1045
1046 /* Check if we created a new hive */
1047 if (CmpMachineHiveList[i].CmHive2)
1048 {
1049 /* TODO: Add to HiveList key */
1050 }
1051 }
1052
1053 /* Get rid of the SD */
1054 ExFreePool(SecurityDescriptor);
1055
1056 /* FIXME: Link SECURITY to SAM */
1057
1058 /* FIXME: Link S-1-5-18 to .Default */
1059 }
1060
1061 BOOLEAN
1062 NTAPI
1063 CmInitSystem1(VOID)
1064 {
1065 OBJECT_ATTRIBUTES ObjectAttributes;
1066 UNICODE_STRING KeyName;
1067 HANDLE KeyHandle;
1068 NTSTATUS Status;
1069 PCMHIVE HardwareHive;
1070 PVOID BaseAddress;
1071 ULONG Length;
1072 PSECURITY_DESCRIPTOR SecurityDescriptor;
1073 PAGED_CODE();
1074
1075 /* Check if this is PE-boot */
1076 if (InitIsWinPEMode)
1077 {
1078 /* Set registry to PE mode */
1079 CmpMiniNTBoot = TRUE;
1080 CmpShareSystemHives = TRUE;
1081 }
1082
1083 /* Initialize the hive list and lock */
1084 InitializeListHead(&CmpHiveListHead);
1085 ExInitializePushLock((PVOID)&CmpHiveListHeadLock);
1086 ExInitializePushLock((PVOID)&CmpLoadHiveLock);
1087
1088 /* Initialize registry lock */
1089 ExInitializeResourceLite(&CmpRegistryLock);
1090
1091 /* Initialize the cache */
1092 CmpInitializeCache();
1093
1094 /* Initialize allocation and delayed dereferencing */
1095 CmpInitCmPrivateAlloc();
1096 CmpInitCmPrivateDelayAlloc();
1097 CmpInitDelayDerefKCBEngine();
1098
1099 /* Initialize callbacks */
1100 CmpInitCallback();
1101
1102 /* Initialize self healing */
1103 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1104 InitializeListHead(&CmpSelfHealQueueListHead);
1105
1106 /* Save the current process and lock the registry */
1107 CmpSystemProcess = PsGetCurrentProcess();
1108
1109 #if 1
1110 /* OLD CM: Initialize the key object list */
1111 InitializeListHead(&CmiKeyObjectListHead);
1112 InitializeListHead(&CmiConnectedHiveList);
1113 #endif
1114
1115 /* Create the key object types */
1116 Status = CmpCreateObjectTypes();
1117 if (!NT_SUCCESS(Status))
1118 {
1119 /* Bugcheck */
1120 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1121 }
1122
1123 /* Build the master hive */
1124 Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive,
1125 HINIT_CREATE,
1126 HIVE_VOLATILE,
1127 HFILE_TYPE_PRIMARY,
1128 NULL,
1129 NULL,
1130 NULL,
1131 NULL,
1132 NULL,
1133 0);
1134 if (!NT_SUCCESS(Status))
1135 {
1136 /* Bugcheck */
1137 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1138 }
1139
1140 /* Create the \REGISTRY key node */
1141 if (!CmpCreateRegistryRoot())
1142 {
1143 /* Bugcheck */
1144 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1145 }
1146
1147 /* Create the default security descriptor */
1148 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1149
1150 /* Create '\Registry\Machine' key. */
1151 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1152 InitializeObjectAttributes(&ObjectAttributes,
1153 &KeyName,
1154 OBJ_CASE_INSENSITIVE,
1155 NULL,
1156 SecurityDescriptor);
1157 Status = NtCreateKey(&KeyHandle,
1158 KEY_READ | KEY_WRITE,
1159 &ObjectAttributes,
1160 0,
1161 NULL,
1162 0,
1163 NULL);
1164 if (!NT_SUCCESS(Status))
1165 {
1166 /* Bugcheck */
1167 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1168 }
1169
1170 /* Close the handle */
1171 NtClose(KeyHandle);
1172
1173 /* Create '\Registry\User' key. */
1174 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1175 InitializeObjectAttributes(&ObjectAttributes,
1176 &KeyName,
1177 OBJ_CASE_INSENSITIVE,
1178 NULL,
1179 SecurityDescriptor);
1180 Status = NtCreateKey(&KeyHandle,
1181 KEY_READ | KEY_WRITE,
1182 &ObjectAttributes,
1183 0,
1184 NULL,
1185 0,
1186 NULL);
1187 if (!NT_SUCCESS(Status))
1188 {
1189 /* Bugcheck */
1190 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1191 }
1192
1193 /* Close the handle */
1194 NtClose(KeyHandle);
1195
1196 /* Initialize the system hive */
1197 if (!CmpInitializeSystemHive(KeLoaderBlock))
1198 {
1199 /* Bugcheck */
1200 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1201 }
1202
1203 /* Create the 'CurrentControlSet' link. */
1204 Status = CmpCreateControlSet(KeLoaderBlock);
1205 if (!NT_SUCCESS(Status))
1206 {
1207 /* Bugcheck */
1208 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1209 }
1210
1211 /* Import the hardware hive (FIXME: We should create it from scratch) */
1212 BaseAddress = CmpRosGetHardwareHive(&Length);
1213 ((PHBASE_BLOCK)BaseAddress)->Length = Length;
1214 Status = CmpInitializeHive((PCMHIVE*)&HardwareHive,
1215 HINIT_MEMORY, //HINIT_CREATE,
1216 HIVE_VOLATILE,
1217 HFILE_TYPE_PRIMARY,
1218 BaseAddress, // NULL,
1219 NULL,
1220 NULL,
1221 NULL,
1222 NULL,
1223 0);
1224 CmPrepareHive(&HardwareHive->Hive);
1225 if (!NT_SUCCESS(Status))
1226 {
1227 /* Bugcheck */
1228 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1229 }
1230
1231 /* Attach it to the machine key */
1232 RtlInitUnicodeString(&KeyName, REG_HARDWARE_KEY_NAME);
1233 Status = CmpLinkHiveToMaster(&KeyName,
1234 NULL,
1235 (PCMHIVE)HardwareHive,
1236 FALSE,
1237 SecurityDescriptor);
1238 if (!NT_SUCCESS(Status))
1239 {
1240 /* Bugcheck */
1241 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1242 }
1243
1244 /* Fill out the Hardware key with the ARC Data from the Loader */
1245 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1246 if (!NT_SUCCESS(Status))
1247 {
1248 /* Bugcheck */
1249 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1250 }
1251
1252 /* Initialize machine-dependent information into the registry */
1253 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1254 if (!NT_SUCCESS(Status))
1255 {
1256 /* Bugcheck */
1257 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1258 }
1259
1260 /* Initialize volatile registry settings */
1261 Status = CmpSetSystemValues(KeLoaderBlock);
1262 if (!NT_SUCCESS(Status))
1263 {
1264 /* Bugcheck */
1265 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1266 }
1267
1268 /* Free the load options */
1269 ExFreePool(CmpLoadOptions.Buffer);
1270
1271 /* If we got here, all went well */
1272 return TRUE;
1273 }
1274
1275 VOID
1276 NTAPI
1277 CmpLockRegistryExclusive(VOID)
1278 {
1279 /* Enter a critical region and lock the registry */
1280 KeEnterCriticalRegion();
1281 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1282
1283 /* Sanity check */
1284 ASSERT(CmpFlushStarveWriters == 0);
1285 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
1286 }
1287
1288 VOID
1289 NTAPI
1290 CmpLockRegistry(VOID)
1291 {
1292 /* Enter a critical region */
1293 KeEnterCriticalRegion();
1294
1295 /* Check if we have to starve writers */
1296 if (CmpFlushStarveWriters)
1297 {
1298 /* Starve exlusive waiters */
1299 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
1300 }
1301 else
1302 {
1303 /* Just grab the lock */
1304 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
1305 }
1306 }
1307
1308 BOOLEAN
1309 NTAPI
1310 CmpTestRegistryLock(VOID)
1311 {
1312 /* Test the lock */
1313 return (BOOLEAN)ExIsResourceAcquiredSharedLite(&CmpRegistryLock);
1314 }
1315
1316 BOOLEAN
1317 NTAPI
1318 CmpTestRegistryLockExclusive(VOID)
1319 {
1320 /* Test the lock */
1321 return ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock);
1322 }
1323
1324 VOID
1325 NTAPI
1326 CmpUnlockRegistry(VOID)
1327 {
1328 /* Sanity check */
1329 CMP_ASSERT_REGISTRY_LOCK();
1330
1331 /* Check if we should flush the registry */
1332 if (CmpFlushOnLockRelease)
1333 {
1334 /* The registry should be exclusively locked for this */
1335 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1336
1337 /* Flush the registry */
1338 CmpDoFlushAll(TRUE);
1339 CmpFlushOnLockRelease = FALSE;
1340 }
1341
1342 /* Release the lock and leave the critical region */
1343 ExReleaseResourceLite(&CmpRegistryLock);
1344 KeLeaveCriticalRegion();
1345 }
1346
1347 VOID
1348 NTAPI
1349 CmShutdownSystem(VOID)
1350 {
1351 /* Kill the workers and fush all hives */
1352 CmpShutdownWorkers();
1353 CmpDoFlushAll(TRUE);
1354 }