test: cmsysini.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# cmsysini.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1991  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     cmsysini.c
    00008
    00009 Abstract:
    00010
    00011     This module contains init support for the configuration manager,
    00012     particularly the registry.
    00013
    00014 Author:
    00015
    00016     Bryan M. Willman (bryanwi) 26-Aug-1991
    00017
    00018 Revision History:
    00019
    00020     Elliot Shmukler (t-ellios) 24-Aug-1998
    00021
    00022          Added CmpSaveBootControlSet & CmpDeleteCloneTree in order to
    00023          perform some of the LKG work that has been moved into the kernel.
    00024          Modified system initialization to permit operation and LKG control
    00025          set saves without a CurrentControlSet clone.
    00026
    00027 --*/
    00028
    00029 #include    "cmp.h"
    00030 #pragma hdrstop
    00031 #include    "arccodes.h"
    00032
    00033 //
    00034 // paths
    00035 //
    00036
    00037 #define INIT_SYSTEMROOT_HIVEPATH L"\\SystemRoot\\System32\\Config\\"
    00038
    00039 #define INIT_REGISTRY_MASTERPATH   L"\\REGISTRY\\"
    00040
    00041 #if DBG
    00042 //
    00043 // Logging support
    00044 //
    00045
    00046 ULONG   CmLogLevel = 1;
    00047 ULONG   CmLogSelect = CMS_DEFAULT;
    00048 #endif
    00049
    00050 extern  PKPROCESS   CmpSystemProcess;
    00051 extern  ERESOURCE CmpRegistryLock;
    00052 extern  FAST_MUTEX    CmpKcbLock;
    00053 extern  FAST_MUTEX CmpPostLock;
    00054
    00055 extern  BOOLEAN     CmFirstTime;
    00056
    00057
    00058 //
    00059 // List of MACHINE hives to load.
    00060 //
    00061 extern  HIVE_LIST_ENTRY CmpMachineHiveList[];
    00062
    00063 #define SYSTEM_HIVE_INDEX 3
    00064 #define CLONE_HIVE_INDEX 6
    00065
    00066 #define SYSTEM_PATH L"\\registry\\machine\\system"
    00067
    00068 //
    00069 // special keys for backwards compatibility with 1.0
    00070 //
    00071 #define HKEY_PERFORMANCE_TEXT       (( HANDLE ) (ULONG_PTR)((LONG)0x80000050) )
    00072 #define HKEY_PERFORMANCE_NLSTEXT    (( HANDLE ) (ULONG_PTR)((LONG)0x80000060) )
    00073
    00074 extern UNICODE_STRING  CmpSystemFileName;
    00075 extern UNICODE_STRING  CmSymbolicLinkValueName;
    00076 extern UNICODE_STRING  CmpLoadOptions;         // sys options from FW or boot.ini
    00077 extern PWCHAR CmpProcessorControl;
    00078 extern PWCHAR CmpControlSessionManager;
    00079
    00080 //
    00081 //
    00082 // Object type definition support.
    00083 //
    00084 // Key objects (CmpKeyObjectType) represent open instances of keys in the
    00085 // registry.  They do not have object names, rather, their names are
    00086 // defined by the registry backing store.
    00087 //
    00088
    00089 //
    00090 // Master Hive
    00091 //
    00092 //  The KEY_NODEs for \REGISTRY, \REGISTRY\MACHINE, and \REGISTRY\USER
    00093 //  are stored in a small memory only hive called the Master Hive.
    00094 //  All other hives have link nodes in this hive which point to them.
    00095 //
    00096 extern   PCMHIVE CmpMasterHive;
    00097 extern   BOOLEAN CmpNoMasterCreates;    // Init False, Set TRUE after we're done to
    00098                                         // prevent random creates in the
    00099                                         // master hive, which is not backed
    00100                                         // by a file.
    00101
    00102 extern   LIST_ENTRY  CmpHiveListHead;   // List of CMHIVEs
    00103
    00104
    00105 //
    00106 // Addresses of object type descriptors:
    00107 //
    00108
    00109 extern   POBJECT_TYPE CmpKeyObjectType;
    00110
    00111 //
    00112 // Define attributes that Key objects are not allowed to have.
    00113 //
    00114
    00115 #define CMP_KEY_INVALID_ATTRIBUTES  (OBJ_EXCLUSIVE  |\
    00116                                      OBJ_PERMANENT)
    00117
    00118
    00119 //
    00120 // Global control values
    00121 //
    00122
    00123 //
    00124 // Write-Control:
    00125 //  CmpNoWrite is initially true.  When set this way write and flush
    00126 //  do nothing, simply returning success.  When cleared to FALSE, I/O
    00127 //  is enabled.  This change is made after the I/O system is started
    00128 //  AND autocheck (chkdsk) has done its thing.
    00129 //
    00130
    00131 extern BOOLEAN CmpNoWrite;
    00132
    00133 extern BOOLEAN HvShutdownComplete;
    00134
    00135 //
    00136 // Buffer used for quick-stash transfers in CmSetValueKey
    00137 //
    00138 extern PUCHAR  CmpStashBuffer;
    00139 extern ULONG   CmpStashBufferSize;
    00140
    00141
    00142 //
    00143 // set to true if disk full when trying to save the changes made between system hive loading and registry initalization
    00144 //
    00145 extern BOOLEAN CmpCannotWriteConfiguration;
    00146 //
    00147 // Global "constants"
    00148 //
    00149
    00150 extern   UNICODE_STRING nullclass;
    00151
    00152 //
    00153 // Private prototypes
    00154 //
    00155 VOID
    00156 CmpCreatePredefined(
    00157     IN HANDLE Root,
    00158     IN PWSTR KeyName,
    00159     IN HANDLE PredefinedHandle
    00160     );
    00161
    00162 VOID
    00163 CmpCreatePerfKeys(
    00164     VOID
    00165     );
    00166
    00167 BOOLEAN
    00168 CmpLinkKeyToHive(
    00169     PWSTR   KeyPath,
    00170     PWSTR   HivePath
    00171     );
    00172
    00173 BOOLEAN
    00174 CmpValidateAlternate(
    00175     IN HANDLE FileHandle,
    00176     IN PCMHIVE PrimaryHive
    00177     );
    00178
    00179 NTSTATUS
    00180 CmpCreateControlSet(
    00181     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    00182     );
    00183
    00184 NTSTATUS
    00185 CmpCloneControlSet(
    00186     VOID
    00187     );
    00188
    00189 BOOLEAN
    00190 CmpCreateObjectTypes(
    00191     VOID
    00192     );
    00193
    00194 BOOLEAN
    00195 CmpCreateRegistryRoot(
    00196     VOID
    00197     );
    00198
    00199 BOOLEAN
    00200 CmpCreateRootNode(
    00201     IN PHHIVE   Hive,
    00202     IN PWSTR    Name,
    00203     OUT PHCELL_INDEX RootCellIndex
    00204     );
    00205
    00206 VOID
    00207 CmpFreeDriverList(
    00208     IN PHHIVE Hive,
    00209     IN PLIST_ENTRY DriverList
    00210     );
    00211
    00212 VOID
    00213 CmpInitializeHiveList(
    00214     VOID
    00215     );
    00216
    00217 BOOLEAN
    00218 CmpInitializeSystemHive(
    00219     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    00220     );
    00221
    00222 NTSTATUS
    00223 CmpInterlockedFunction (
    00224     PWCHAR RegistryValueKey,
    00225     VOID (*InterlockedFunction)(VOID)
    00226     );
    00227
    00228 VOID
    00229 CmpConfigureProcessors (
    00230     VOID
    00231     );
    00232
    00233 #if i386
    00234 VOID
    00235 KeOptimizeProcessorControlState (
    00236     VOID
    00237     );
    00238 #endif
    00239
    00240 NTSTATUS
    00241 CmpAddDockingInfo (
    00242     IN HANDLE Key,
    00243     IN PROFILE_PARAMETER_BLOCK * ProfileBlock
    00244     );
    00245
    00246 NTSTATUS
    00247 CmpAddAliasEntry (
    00248     IN HANDLE IDConfigDB,
    00249     IN PROFILE_PARAMETER_BLOCK * ProfileBlock,
    00250     IN ULONG  ProfileNumber
    00251     );
    00252
    00253 NTSTATUS CmpDeleteCloneTree(VOID);
    00254
    00255 VOID
    00256 CmpDiskFullWarning(
    00257     VOID
    00258     );
    00259
    00260
    00261 #ifdef ALLOC_PRAGMA
    00262 #pragma alloc_text(INIT,CmInitSystem1)
    00263 #pragma alloc_text(INIT,CmpCreateControlSet)
    00264 #pragma alloc_text(INIT,CmpCloneControlSet)
    00265 #pragma alloc_text(INIT,CmpCreateObjectTypes)
    00266 #pragma alloc_text(INIT,CmpCreateRegistryRoot)
    00267 #pragma alloc_text(INIT,CmpCreateRootNode)
    00268 #pragma alloc_text(INIT,CmpInitializeSystemHive)
    00269 #pragma alloc_text(INIT,CmGetSystemDriverList)
    00270 #pragma alloc_text(INIT,CmpFreeDriverList)
    00271 #pragma alloc_text(PAGE,CmpInitializeHiveList)
    00272 #pragma alloc_text(PAGE,CmpLinkHiveToMaster)
    00273 #pragma alloc_text(PAGE,CmpSetVersionData)
    00274 #pragma alloc_text(PAGE,CmBootLastKnownGood)
    00275 #pragma alloc_text(PAGE,CmpSaveBootControlSet)
    00276 #pragma alloc_text(PAGE,CmpInitHiveFromFile)
    00277 #pragma alloc_text(INIT,CmpIsLastKnownGoodBoot)
    00278 #pragma alloc_text(PAGE,CmpLinkKeyToHive)
    00279 #pragma alloc_text(PAGE,CmShutdownSystem)
    00280 #pragma alloc_text(PAGE,CmpValidateAlternate)
    00281 #pragma alloc_text(PAGE,CmpCreatePredefined)
    00282 #pragma alloc_text(PAGE,CmpCreatePerfKeys)
    00283 #pragma alloc_text(PAGE,CmpInterlockedFunction)
    00284 #pragma alloc_text(PAGE,CmpConfigureProcessors)
    00285 #pragma alloc_text(INIT,CmpAddDockingInfo)
    00286 #pragma alloc_text(INIT,CmpAddAliasEntry)
    00287 #pragma alloc_text(PAGE,CmpDeleteCloneTree)
    00288 #endif
    00289
    00290
    00291
    00292 BOOLEAN
    00293 CmInitSystem1(
    00294     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    00295     )
    00296 /*++
    00297
    00298 Routine Description:
    00299
    00300     This function is called as part of phase1 init, after the object
    00301     manager has been inited, but before IoInit.  It's purpose is to
    00302     set up basic registry object operations, and transform data
    00303     captured during boot into registry format (whether it was read
    00304     from the SYSTEM hive file by the osloader or computed by recognizers.)
    00305     After this call, Nt*Key calls work, but only part of the name
    00306     space is available and any changes written must be held in
    00307     memory.
    00308
    00309     CmpMachineHiveList entries marked CM_PHASE_1 are available
    00310     after return from this call, but writes must be held in memory.
    00311
    00312     This function will:
    00313
    00314         1.  Create the regisrty worker/lazy-write thread
    00315         2.  Create the registry key object type
    00316         4.  Create the master hive
    00317         5.  Create the \REGISTRY node
    00318         6.  Create a KEY object that refers to \REGISTRY
    00319         7.  Create \REGISTRY\MACHINE node
    00320         8.  Create the SYSTEM hive, fill in with data from loader
    00321         9.  Create the HARDWARE hive, fill in with data from loader
    00322        10.  Create:
    00323                 \REGISTRY\MACHINE\SYSTEM
    00324                 \REGISTRY\MACHINE\HARDWARE
    00325                 Both of which will be link nodes in the master hive.
    00326
    00327     NOTE:   We do NOT free allocated pool in failure case.  This is because
    00328             our caller is going to bugcheck anyway, and having the memory
    00329             object to look at is useful.
    00330
    00331 Arguments:
    00332
    00333     LoaderBlock - supplies the LoaderBlock passed in from the OSLoader.
    00334         By looking through the memory descriptor list we can find the
    00335         SYSTEM hive which the OSLoader has placed in memory for us.
    00336
    00337 Return Value:
    00338
    00339     TRUE if all operations were successful, false if any failed.
    00340
    00341     Bugchecks when something went wrong (CONFIG_INITIALIZATION_FAILED,4,.....)
    00342
    00343 --*/
    00344 {
    00345     HANDLE  key1;
    00346     OBJECT_ATTRIBUTES ObjectAttributes;
    00347     NTSTATUS    status;
    00348     NTSTATUS    status2;
    00349     PSECURITY_DESCRIPTOR SecurityDescriptor;
    00350     PCMHIVE HardwareHive;
    00351     PCMHIVE CloneHive;
    00352     UNICODE_STRING NameString;
    00353
    00354     PAGED_CODE();
    00355     CMLOG(CML_MAJOR, CMS_INIT) KdPrint(("CmInitSystem1\n"));
    00356
    00357     //
    00358     // Initialize Names of all registry paths.
    00359     // This simply initializes unicode strings so we don't have to bother
    00360     // with it later. This can not fail.
    00361     //
    00362     CmpInitializeRegistryNames();
    00363
    00364     //
    00365     // Compute registry global quota
    00366     //
    00367     CmpComputeGlobalQuotaAllowed();
    00368
    00369     //
    00370     // Initialize the hive list head
    00371     //
    00372     InitializeListHead(&CmpHiveListHead);
    00373
    00374     //
    00375     // Initialize the global registry resource
    00376     //
    00377     ExInitializeResource(&CmpRegistryLock);
    00378
    00379     //
    00380     // Initialize the KCB tree mutex
    00381     //
    00382     ExInitializeFastMutex(&CmpKcbLock);
    00383
    00384     //
    00385     // Initialize the PostList mutex
    00386     //
    00387     ExInitializeFastMutex(&CmpPostLock);
    00388
    00389     //
    00390     // Initialize the cache
    00391     //
    00392     CmpInitializeCache ();
    00393
    00394     //
    00395     // Save the current process to allow us to attach to it later.
    00396     //
    00397     CmpSystemProcess = &PsGetCurrentProcess()->Pcb;
    00398
    00399     CmpLockRegistryExclusive();
    00400
    00401     //
    00402     // Create the Key object type.
    00403     //
    00404     if (!CmpCreateObjectTypes()) {
    00405         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    00406             KdPrint(("CmInitSystem1: CmpCreateObjectTypes failed\n"));
    00407         }
    00408         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,1,0,0); // could not registrate with object manager
    00409         return FALSE;
    00410     }
    00411
    00412
    00413     //
    00414     // Create the master hive and initialize it.
    00415     //
    00416     status = CmpInitializeHive(&CmpMasterHive,
    00417                 HINIT_CREATE,
    00418                 HIVE_VOLATILE,
    00419                 HFILE_TYPE_PRIMARY,     // i.e. no logging, no alterate
    00420                 NULL,
    00421                 NULL,
    00422                 NULL,
    00423                 NULL,
    00424                 NULL,
    00425                 NULL);
    00426     if (!NT_SUCCESS(status)) {
    00427         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    00428             KdPrint(("CmInitSystem1: CmpInitializeHive(master) failed\n"));
    00429         }
    00430         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,2,0,0); // could not initialize master hive
    00431         return (FALSE);
    00432     }
    00433
    00434     //
    00435     // try to allocate a stash buffer.  if we can't get 1 page this
    00436     // early on, we're in deep trouble, so punt.
    00437     //
    00438     CmpStashBuffer = ExAllocatePoolWithTag(PagedPool, HBLOCK_SIZE,'bSmC');
    00439     if (CmpStashBuffer == NULL) {
    00440         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,3,0,0); // odds against this are huge
    00441         return FALSE;
    00442     }
    00443     CmpStashBufferSize = HBLOCK_SIZE;
    00444
    00445     //
    00446     // Create the \REGISTRY node
    00447     //
    00448     if (!CmpCreateRegistryRoot()) {
    00449         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    00450             KdPrint(("CmInitSystem1: CmpCreateRegistryRoot failed\n"));
    00451         }
    00452         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,4,0,0); // could not create root of the registry
    00453         return FALSE;
    00454     }
    00455
    00456     //
    00457     // --- 6. Create \REGISTRY\MACHINE and \REGISTRY\USER nodes ---
    00458     //
    00459
    00460     //
    00461     // Get default security descriptor for the nodes we will create.
    00462     //
    00463     SecurityDescriptor = CmpHiveRootSecurityDescriptor();
    00464
    00465     InitializeObjectAttributes(
    00466         &ObjectAttributes,
    00467         &CmRegistryMachineName,
    00468         OBJ_CASE_INSENSITIVE,
    00469         (HANDLE)NULL,
    00470         SecurityDescriptor
    00471         );
    00472
    00473     if (!NT_SUCCESS(NtCreateKey(
    00474                         &key1,
    00475                         KEY_READ | KEY_WRITE,
    00476                         &ObjectAttributes,
    00477                         0,
    00478                         &nullclass,
    00479                         0,
    00480                         NULL
    00481         )))
    00482     {
    00483         ExFreePool(SecurityDescriptor);
    00484         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    00485             KdPrint(("CmInitSystem1: NtCreateKey(MACHINE) failed\n"));
    00486         }
    00487         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,5,0,0); // could not create HKLM
    00488         return FALSE;
    00489     }
    00490
    00491     NtClose(key1);
    00492
    00493     InitializeObjectAttributes(
    00494         &ObjectAttributes,
    00495         &CmRegistryUserName,
    00496         OBJ_CASE_INSENSITIVE,
    00497         (HANDLE)NULL,
    00498         SecurityDescriptor
    00499         );
    00500
    00501     if (!NT_SUCCESS(NtCreateKey(
    00502                         &key1,
    00503                         KEY_READ | KEY_WRITE,
    00504                         &ObjectAttributes,
    00505                         0,
    00506                         &nullclass,
    00507                         0,
    00508                         NULL
    00509         )))
    00510     {
    00511         ExFreePool(SecurityDescriptor);
    00512         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    00513             KdPrint(("CmInitSystem1: NtCreateKey(USER) failed\n"));
    00514         }
    00515         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,6,0,0); // could not create HKUSER
    00516         return FALSE;
    00517     }
    00518
    00519     NtClose(key1);
    00520
    00521
    00522     //
    00523     // --- 7. Create the SYSTEM hive, fill in with data from loader ---
    00524     //
    00525     if (!CmpInitializeSystemHive(LoaderBlock)) {
    00526         ExFreePool(SecurityDescriptor);
    00527         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    00528             KdPrint(("CmpInitSystem1: "));
    00529             KdPrint(("Hive allocation failure for SYSTEM\n"));
    00530         }
    00531         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,7,0,0); // could not create SystemHive
    00532         return(FALSE);
    00533     }
    00534
    00535     //
    00536     // Create the symbolic link \Registry\Machine\System\CurrentControlSet
    00537     //
    00538     status = CmpCreateControlSet(LoaderBlock);
    00539     if (!NT_SUCCESS(status)) {
    00540         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,8,0,0); // could not create CurrentControlSet
    00541         return(FALSE);
    00542     }
    00543
    00544     //
    00545     // Handle the copying of the CurrentControlSet to a Clone volatile
    00546     // hive (but only if we really want to have a clone)
    00547     //
    00548
    00549 #if CLONE_CONTROL_SET
    00550
    00551     //
    00552     // Create the Clone temporary hive, link it into the master hive,
    00553     // and make a symbolic link to it.
    00554     //
    00555     status = CmpInitializeHive(&CloneHive,
    00556                 HINIT_CREATE,
    00557                 HIVE_VOLATILE,
    00558                 HFILE_TYPE_PRIMARY,
    00559                 NULL,
    00560                 NULL,
    00561                 NULL,
    00562                 NULL,
    00563                 NULL,
    00564                 NULL);
    00565     if (!NT_SUCCESS(status)) {
    00566         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    00567             KdPrint(("CmpInitSystem1: "));
    00568             KdPrint(("Could not initialize CLONE hive\n"));
    00569         }
    00570         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,9,0,0); // could not initialize clone hive
    00571         return(FALSE);
    00572     }
    00573
    00574     if (CmpLinkHiveToMaster(
    00575             &CmRegistrySystemCloneName,
    00576             NULL,
    00577             CloneHive,
    00578             TRUE,
    00579             SecurityDescriptor
    00580             ) != STATUS_SUCCESS)
    00581     {
    00582         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    00583             KdPrint(("CmInitSystem1: CmpLinkHiveToMaster(Clone) failed\n"));
    00584         }
    00585         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,10,0,0); // could not link clone hive to master hive
    00586         return FALSE;
    00587     }
    00588     CmpAddToHiveFileList(CloneHive);
    00589     CmpMachineHiveList[CLONE_HIVE_INDEX].CmHive = CloneHive;
    00590
    00591     CmpLinkKeyToHive(
    00592         L"\\Registry\\Machine\\System\\Clone",
    00593         L"\\Registry\\Machine\\CLONE\\CLONE"
    00594         );
    00595
    00596
    00597     //
    00598     // Clone the current control set for the service controller
    00599     //
    00600     status = CmpCloneControlSet();
    00601
    00602     //
    00603     // If this didn't work, it's bad, but not bad enough to fail the boot
    00604     //
    00605     ASSERT(NT_SUCCESS(status));
    00606
    00607 #endif
    00608
    00609     //
    00610     // --- 8. Create the HARDWARE hive, fill in with data from loader ---
    00611     //
    00612     status = CmpInitializeHive(&HardwareHive,
    00613                 HINIT_CREATE,
    00614                 HIVE_VOLATILE,
    00615                 HFILE_TYPE_PRIMARY,     // i.e. no log, no alternate
    00616                 NULL,
    00617                 NULL,
    00618                 NULL,
    00619                 NULL,
    00620                 NULL,
    00621                 NULL);
    00622     if (!NT_SUCCESS(status)) {
    00623         ExFreePool(SecurityDescriptor);
    00624         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    00625             KdPrint(("CmpInitSystem1: "));
    00626             KdPrint(("Could not initialize HARDWARE hive\n"));
    00627         }
    00628         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,11,0,0); // could not initialize hardware hive
    00629         return(FALSE);
    00630     }
    00631
    00632     //
    00633     // Allocate the root node
    00634     //
    00635     if (CmpLinkHiveToMaster(
    00636             &CmRegistryMachineHardwareName,
    00637             NULL,
    00638             HardwareHive,
    00639             TRUE,
    00640             SecurityDescriptor
    00641             ) != STATUS_SUCCESS)
    00642     {
    00643         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    00644             KdPrint(("CmInitSystem1: CmpLinkHiveToMaster(Hardware) failed\n"));
    00645         }
    00646         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,12,0,0); // could not link hardware hive to master hive
    00647         return FALSE;
    00648     }
    00649     CmpAddToHiveFileList(HardwareHive);
    00650
    00651     ExFreePool(SecurityDescriptor);
    00652
    00653     CmpMachineHiveList[0].CmHive = HardwareHive;
    00654
    00655     //
    00656     // put loader configuration tree data to our hardware registry.
    00657     //
    00658     status = CmpInitializeHardwareConfiguration(LoaderBlock);
    00659
    00660     if (!NT_SUCCESS(status)) {
    00661         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,13,0,0); // could not initialize hardware configuration
    00662         return(FALSE);
    00663     }
    00664
    00665     CmpNoMasterCreates = TRUE;
    00666     CmpUnlockRegistry();
    00667
    00668     //
    00669     // put machine dependant configuration data to our hardware registry.
    00670     //
    00671     status = CmpInitializeMachineDependentConfiguration(LoaderBlock);
    00672
    00673
    00674     //
    00675     // store boot loader command tail in registry
    00676     //
    00677     RtlInitUnicodeString(
    00678         &NameString,
    00679         L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control"
    00680         );
    00681
    00682     InitializeObjectAttributes(
    00683         &ObjectAttributes,
    00684         &NameString,
    00685         OBJ_CASE_INSENSITIVE,
    00686         (HANDLE)NULL,
    00687         NULL
    00688         );
    00689
    00690     status2 = NtOpenKey(
    00691                 &key1,
    00692                 KEY_WRITE,
    00693                 &ObjectAttributes
    00694                 );
    00695
    00696     if (NT_SUCCESS(status2)) {
    00697         RtlInitUnicodeString(
    00698             &NameString,
    00699             L"SystemStartOptions"
    00700             );
    00701
    00702         NtSetValueKey(
    00703             key1,
    00704             &NameString,
    00705             0,              // TitleIndex
    00706             REG_SZ,
    00707             CmpLoadOptions.Buffer,
    00708             CmpLoadOptions.Length
    00709             );
    00710
    00711         NtClose(key1);
    00712     }
    00713     ExFreePool(CmpLoadOptions.Buffer);
    00714
    00715
    00716     if (!NT_SUCCESS(status)) {
    00717         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,4,14,0,0); // could not open CurrentControlSet\\Control
    00718         return(FALSE);
    00719     }
    00720
    00721     return TRUE;
    00722 }
    00723
    00724
    00725 VOID
    00726 CmpInitializeHiveList(
    00727     VOID
    00728     )
    00729 /*++
    00730
    00731 Routine Description:
    00732
    00733     This function is called to map hive files to hives.  It both
    00734     maps existing hives to files, and creates new hives from files.
    00735
    00736     It operates on files in "\SYSTEMROOT\CONFIG".
    00737
    00738     NOTE:   MUST run in the context of the process that the CmpWorker
    00739             thread runs in.  Caller is expected to arrange this.
    00740
    00741     NOTE:   Will bugcheck on failure.
    00742
    00743 Arguments:
    00744
    00745 Return Value:
    00746
    00747     NONE.
    00748
    00749 --*/
    00750 {
    00751     #define MAX_NAME    128
    00752     UCHAR   FileBuffer[MAX_NAME];
    00753     UCHAR   RegBuffer[MAX_NAME];
    00754
    00755     UNICODE_STRING TempName;
    00756     UNICODE_STRING FileName;
    00757     UNICODE_STRING RegName;
    00758
    00759     USHORT  FileStart;
    00760     USHORT  RegStart;
    00761     ULONG   i;
    00762     PCMHIVE CmHive;
    00763     BOOLEAN Allocate;
    00764     HANDLE  PrimaryHandle;
    00765     HANDLE  LogHandle;
    00766     ULONG   PrimaryDisposition;
    00767     ULONG   SecondaryDisposition;
    00768     ULONG   Length;
    00769     NTSTATUS Status;
    00770     PSECURITY_DESCRIPTOR SecurityDescriptor;
    00771     BOOLEAN RegistryLocked = TRUE;
    00772
    00773     PVOID   ErrorParameters;
    00774     ULONG   ErrorResponse;
    00775     ULONG   ClusterSize;
    00776
    00777     PAGED_CODE();
    00778     CMLOG(CML_MAJOR, CMS_INIT) KdPrint(("CmpInitializeHiveList\n"));
    00779
    00780     CmpNoWrite = FALSE;
    00781
    00782     FileName.MaximumLength = MAX_NAME;
    00783     FileName.Length = 0;
    00784     FileName.Buffer = (PWSTR)&(FileBuffer[0]);
    00785
    00786     RegName.MaximumLength = MAX_NAME;
    00787     RegName.Length = 0;
    00788     RegName.Buffer = (PWSTR)&(RegBuffer[0]);
    00789
    00790     RtlInitUnicodeString(
    00791         &TempName,
    00792         INIT_SYSTEMROOT_HIVEPATH
    00793         );
    00794     RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
    00795     FileStart = FileName.Length;
    00796
    00797     RtlInitUnicodeString(
    00798         &TempName,
    00799         INIT_REGISTRY_MASTERPATH
    00800         );
    00801     RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
    00802     RegStart = RegName.Length;
    00803
    00804     SecurityDescriptor = CmpHiveRootSecurityDescriptor();
    00805
    00806
    00807     for (i = 0; CmpMachineHiveList[i].Name != NULL; i++) {
    00808
    00809         //
    00810         // Compute the name of the file, and the name to link to in
    00811         // the registry.
    00812         //
    00813
    00814         // REGISTRY
    00815
    00816         RegName.Length = RegStart;
    00817         RtlInitUnicodeString(
    00818             &TempName,
    00819             CmpMachineHiveList[i].BaseName
    00820             );
    00821         RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
    00822
    00823         // REGISTRY\MACHINE or REGISTRY\USER
    00824
    00825         if (RegName.Buffer[ (RegName.Length / sizeof( WCHAR )) - 1 ] == '\\') {
    00826             RtlInitUnicodeString(
    00827                 &TempName,
    00828                 CmpMachineHiveList[i].Name
    00829                 );
    00830             RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
    00831         }
    00832
    00833         // REGISTRY\[MACHINE|USER]\HIVE
    00834
    00835         // <sysroot>\config
    00836
    00837         RtlInitUnicodeString(
    00838             &TempName,
    00839             CmpMachineHiveList[i].Name
    00840             );
    00841         FileName.Length = FileStart;
    00842         RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
    00843
    00844         // <sysroot>\config\hive
    00845
    00846
    00847         if (CmpMachineHiveList[i].CmHive == NULL) {
    00848
    00849             //
    00850             // Hive has not been inited in any way.
    00851             //
    00852
    00853             Allocate = TRUE;
    00854             Status = CmpInitHiveFromFile(&FileName,
    00855                                          CmpMachineHiveList[i].Flags,
    00856                                          &CmHive,
    00857                                          &Allocate,
    00858                                          &RegistryLocked
    00859                                          );
    00860
    00861             if ( (!NT_SUCCESS(Status)) ||
    00862                  (CmHive->FileHandles[HFILE_TYPE_LOG] == NULL) )
    00863             {
    00864                 ErrorParameters = &FileName;
    00865                 ExRaiseHardError(
    00866                     STATUS_CANNOT_LOAD_REGISTRY_FILE,
    00867                     1,
    00868                     1,
    00869                     (PULONG_PTR)&ErrorParameters,
    00870                     OptionOk,
    00871                     &ErrorResponse
    00872                     );
    00873
    00874                 continue;           // If we are here it isn't SYSTEM,
    00875                                     // so punt and go on.
    00876             }
    00877
    00878             CMLOG(CML_MINOR, CMS_INIT) {
    00879                 KdPrint(("CmpInitializeHiveList:\n"));
    00880                 KdPrint(("\tCmHive for '%ws' @", CmpMachineHiveList[i]));
    00881                 KdPrint(("%08lx", CmHive));
    00882             }
    00883
    00884             //
    00885             // Link hive into master hive
    00886             //
    00887             if (CmpLinkHiveToMaster(
    00888                     &RegName,
    00889                     NULL,
    00890                     CmHive,
    00891                     Allocate,
    00892                     SecurityDescriptor
    00893                     ) != STATUS_SUCCESS)
    00894             {
    00895                 CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    00896                     KdPrint(("CmpInitializeHiveList: "));
    00897                     KdPrint(("CmpLinkHiveToMaster failed\n"));
    00898                     KdPrint(("\ti=%d s='%ws'\n", i, CmpMachineHiveList[i]));
    00899                 }
    00900                 KeBugCheckEx(CONFIG_LIST_FAILED,5,2,i,(ULONG_PTR)&RegName);
    00901             }
    00902             CmpAddToHiveFileList(CmHive);
    00903
    00904             if (Allocate) {
    00905                 HvSyncHive((PHHIVE)CmHive);
    00906             }
    00907
    00908         } else {
    00909
    00910             CmHive = CmpMachineHiveList[i].CmHive;
    00911
    00912             if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) {
    00913
    00914                 //
    00915                 // CmHive already exists.  It is not an entirely volatile
    00916                 // hive (we do nothing for those.)
    00917                 //
    00918                 // First, open the files (Primary and Alternate) that
    00919                 // back the hive.  Stuff their handles into the CmHive
    00920                 // object.  Force the size of the files to match the
    00921                 // in memory images.  Call HvSyncHive to write changes
    00922                 // out to disk.
    00923                 //
    00924                 Status = CmpOpenHiveFiles(&FileName,
    00925                                           L".ALT",
    00926                                           &PrimaryHandle,
    00927                                           &LogHandle,
    00928                                           &PrimaryDisposition,
    00929                                           &SecondaryDisposition,
    00930                                           TRUE,
    00931                                           TRUE,
    00932                                           &ClusterSize);
    00933
    00934                 if ( ( ! NT_SUCCESS(Status)) ||
    00935                      (LogHandle == NULL) )
    00936                 {
    00937                     ErrorParameters = &FileName;
    00938                     ExRaiseHardError(
    00939                         STATUS_CANNOT_LOAD_REGISTRY_FILE,
    00940                         1,
    00941                         1,
    00942                         (PULONG_PTR)&ErrorParameters,
    00943                         OptionOk,
    00944                         &ErrorResponse
    00945                         );
    00946
    00947                     //
    00948                     // WARNNOTE
    00949                     // We've just told the user that something essential,
    00950                     // like the SYSTEM hive, is hosed.  Don't try to run,
    00951                     // we just risk destroying user data.  Punt.
    00952                     //
    00953                     KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,5,3,i,Status);
    00954                 }
    00955
    00956                 CmHive->FileHandles[HFILE_TYPE_ALTERNATE] = LogHandle;
    00957                 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
    00958
    00959                 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
    00960
    00961                 //
    00962                 // When an in-memory hive is opened with no backing
    00963                 // file, ClusterSize is assumed to be 1.  When the file
    00964                 // is opened later (for the SYSTEM hive) we need
    00965                 // to update this field in the hive if we are
    00966                 // booting from media where the cluster size > 1
    00967                 //
    00968                 if (CmHive->Hive.Cluster != ClusterSize) {
    00969                     //
    00970                     // The cluster size is different than previous assumed.
    00971                     // Since a cluster in the dirty vector must be either
    00972                     // completely dirty or completely clean, go through the
    00973                     // dirty vector and mark all clusters that contain a dirty
    00974                     // logical sector as completely dirty.
    00975                     //
    00976                     PRTL_BITMAP  BitMap;
    00977                     ULONG        Index;
    00978
    00979                     BitMap = &(CmHive->Hive.DirtyVector);
    00980                     for (Index = 0;
    00981                          Index < CmHive->Hive.DirtyVector.SizeOfBitMap;
    00982                          Index += ClusterSize)
    00983                     {
    00984                         if (!RtlAreBitsClear (BitMap, Index, ClusterSize)) {
    00985                             RtlSetBits (BitMap, Index, ClusterSize);
    00986                         }
    00987                     }
    00988                     //
    00989                     // Update DirtyCount and Cluster
    00990                     //
    00991                     CmHive->Hive.DirtyCount = RtlNumberOfSetBits(&CmHive->Hive.DirtyVector);
    00992                     CmHive->Hive.Cluster = ClusterSize;
    00993                 }
    00994
    00995                 if (!CmpFileSetSize(
    00996                         (PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length) ||
    00997                     !CmpFileSetSize(
    00998                         (PHHIVE)CmHive, HFILE_TYPE_ALTERNATE, Length)
    00999                    )
    01000                 {
    01001                     //
    01002                     // WARNNOTE
    01003                     // Data written into the system hive since boot
    01004                     // cannot be written out, punt.
    01005                     //
    01006                     CmpCannotWriteConfiguration = TRUE;
    01007
    01008                     //KeBugCheckEx(CANNOT_WRITE_CONFIGURATION,5,4,i,0);
    01009                 }
    01010
    01011                 ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
    01012
    01013                 if ( (PrimaryDisposition == FILE_CREATED) ||
    01014                      (SecondaryDisposition == FILE_CREATED) ||
    01015                      (!CmpValidateAlternate(LogHandle,CmHive)))
    01016                 {
    01017                     //
    01018                     // Force all data to be written to the secondary (.alt)
    01019                     //
    01020                     CmHive->FileHandles[HFILE_TYPE_EXTERNAL] =
    01021                         CmHive->FileHandles[HFILE_TYPE_ALTERNATE];
    01022                     Status = HvWriteHive((PHHIVE)CmHive);
    01023                     CmHive->FileHandles[HFILE_TYPE_EXTERNAL] = NULL;
    01024
    01025                     if (!NT_SUCCESS(Status)) {
    01026                         //
    01027                         // WARNNOTE
    01028                         //  If we keep running here, we risk REALLY
    01029                         //  screwing the user over (eating all their
    01030                         //  data), while if we fail, we'll at least
    01031                         //  fail clean.
    01032                         //
    01033                         CmpCannotWriteConfiguration = TRUE;
    01034
    01035                         //KeBugCheckEx(CANNOT_WRITE_CONFIGURATION,5,5,0,0);
    01036                     }
    01037                 }
    01038                 CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive);
    01039
    01040                 HvSyncHive((PHHIVE)CmHive);
    01041
    01042                 if( CmpCannotWriteConfiguration ) {
    01043                     //
    01044                     // The system disk is full; Give user a chance to log-on and make room
    01045                     //
    01046                     CmpDiskFullWarning();
    01047                     CmpLazyFlush();
    01048                 }
    01049             }
    01050         }
    01051     }   // for
    01052
    01053     ExFreePool(SecurityDescriptor);
    01054
    01055     //
    01056     // Create symbolic link from SECURITY hive into SAM hive.
    01057     //
    01058     CmpLinkKeyToHive(
    01059         L"\\Registry\\Machine\\Security\\SAM",
    01060         L"\\Registry\\Machine\\SAM\\SAM"
    01061         );
    01062
    01063     //
    01064     // Create predefined handles.
    01065     //
    01066     CmpCreatePerfKeys();
    01067
    01068     return;
    01069 }
    01070
    01071
    01072
    01073 BOOLEAN
    01074 CmpCreateObjectTypes(
    01075     VOID
    01076     )
    01077 /*++
    01078
    01079 Routine Description:
    01080
    01081     Create the Key object type
    01082
    01083 Arguments:
    01084
    01085     NONE.
    01086
    01087 Return Value:
    01088
    01089     TRUE == success,  FALSE == failure.
    01090
    01091 --*/
    01092 {
    01093    NTSTATUS Status;
    01094    OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
    01095    UNICODE_STRING TypeName;
    01096
    01097    //
    01098    // Structure that describes the mapping of generic access rights to object
    01099    // specific access rights for registry key objects.
    01100    //
    01101
    01102    GENERIC_MAPPING CmpKeyMapping = {
    01103       KEY_READ,
    01104       KEY_WRITE,
    01105       KEY_EXECUTE,
    01106       KEY_ALL_ACCESS
    01107    };
    01108
    01109     PAGED_CODE();
    01110     //
    01111     // --- Create the registry key object type ---
    01112     //
    01113
    01114     //
    01115     // Initialize string descriptor.
    01116     //
    01117
    01118     RtlInitUnicodeString(&TypeName, L"Key");
    01119
    01120     //
    01121     // Create key object type descriptor.
    01122     //
    01123
    01124     RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
    01125     ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
    01126     ObjectTypeInitializer.InvalidAttributes = CMP_KEY_INVALID_ATTRIBUTES;
    01127     ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
    01128     ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
    01129     ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
    01130     ObjectTypeInitializer.SecurityRequired = TRUE;
    01131     ObjectTypeInitializer.PoolType = PagedPool;
    01132     ObjectTypeInitializer.MaintainHandleCount = FALSE;
    01133     ObjectTypeInitializer.UseDefaultObject = TRUE;
    01134
    01135     ObjectTypeInitializer.DumpProcedure = NULL;
    01136     ObjectTypeInitializer.OpenProcedure = NULL;
    01137     ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
    01138     ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
    01139     ObjectTypeInitializer.ParseProcedure = CmpParseKey;
    01140     ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
    01141     ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
    01142
    01143     Status = ObCreateObjectType(
    01144                 &TypeName,
    01145                 &ObjectTypeInitializer,
    01146                 (PSECURITY_DESCRIPTOR)NULL,
    01147                 &CmpKeyObjectType
    01148                 );
    01149
    01150
    01151     if (!NT_SUCCESS(Status)) {
    01152         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    01153             KdPrint(("CmpCreateObjectTypes: "));
    01154             KdPrint(("ObCreateObjectType(Key) failed %08lx\n", Status));
    01155         }
    01156         return FALSE;
    01157     }
    01158
    01159     return TRUE;
    01160 }
    01161
    01162
    01163
    01164 BOOLEAN
    01165 CmpCreateRegistryRoot(
    01166     VOID
    01167     )
    01168 /*++
    01169
    01170 Routine Description:
    01171
    01172     Manually create \REGISTRY in the master hive, create a key
    01173     object to refer to it, and insert the key object into
    01174     the root (\) of the object space.
    01175
    01176 Arguments:
    01177
    01178     None
    01179
    01180 Return Value:
    01181
    01182     TRUE == success, FALSE == failure
    01183
    01184 --*/
    01185 {
    01186     NTSTATUS Status;
    01187     UNICODE_STRING NullString = { 0, 0, NULL };
    01188     HANDLE  ObjHandle;
    01189     PVOID   ObjectPointer;
    01190     PCM_KEY_BODY Object;
    01191     OBJECT_ATTRIBUTES ObjectAttributes;
    01192     PCM_KEY_CONTROL_BLOCK kcb;
    01193     HCELL_INDEX RootCellIndex;
    01194     PSECURITY_DESCRIPTOR SecurityDescriptor;
    01195
    01196     PAGED_CODE();
    01197     //
    01198     // --- Create hive entry for \REGISTRY ---
    01199     //
    01200
    01201     if (!CmpCreateRootNode(
    01202             &(CmpMasterHive->Hive), L"REGISTRY", &RootCellIndex))
    01203     {
    01204         return FALSE;
    01205     }
    01206
    01207     //
    01208     // --- Create a KEY object that refers to \REGISTRY ---
    01209     //
    01210
    01211
    01212     //
    01213     // Create the object manager object
    01214     //
    01215
    01216     //
    01217     // WARNING: \\REGISTRY is not in pool, so if anybody ever tries to
    01218     //          free it, we are in deep trouble.  On the other hand,
    01219     //          this implies somebody has removed \\REGISTRY from the
    01220     //          root, so we're in trouble anyway.
    01221     //
    01222
    01223     SecurityDescriptor = CmpHiveRootSecurityDescriptor();
    01224
    01225     InitializeObjectAttributes(
    01226         &ObjectAttributes,
    01227         &CmRegistryRootName,
    01228         OBJ_CASE_INSENSITIVE,
    01229         (HANDLE)NULL,
    01230         SecurityDescriptor
    01231         );
    01232
    01233
    01234     Status = ObCreateObject(
    01235         KernelMode,
    01236         CmpKeyObjectType,
    01237         &ObjectAttributes,
    01238         UserMode,
    01239         NULL,                   // Parse context
    01240         sizeof(CM_KEY_BODY),
    01241         0,
    01242         0,
    01243         (PVOID *)&Object
    01244         );
    01245
    01246     ExFreePool(SecurityDescriptor);
    01247
    01248     if (!NT_SUCCESS(Status)) {
    01249         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    01250             KdPrint(("CmpCreateRegistryRoot: "));
    01251             KdPrint(("ObCreateObject(\\REGISTRY) failed %08lx\n", Status));
    01252         }
    01253         return FALSE;
    01254     }
    01255
    01256     //
    01257     // Create the key control block
    01258     //
    01259     kcb = CmpCreateKeyControlBlock(
    01260             &(CmpMasterHive->Hive),
    01261             RootCellIndex,
    01262             (PCM_KEY_NODE)HvGetCell(&CmpMasterHive->Hive,RootCellIndex),
    01263             NULL,
    01264             FALSE,
    01265             &CmRegistryRootName
    01266             );
    01267
    01268     if (kcb==NULL) {
    01269         return(FALSE);
    01270     }
    01271
    01272     //
    01273     // Initialize the type specific body
    01274     //
    01275     Object->Type = KEY_BODY_TYPE;
    01276     Object->KeyControlBlock = kcb;
    01277     Object->NotifyBlock = NULL;
    01278     Object->Process = PsGetCurrentProcess();
    01279     ENLIST_KEYBODY_IN_KEYBODY_LIST(Object);
    01280
    01281     //
    01282     // Put the object in the root directory
    01283     //
    01284     Status = ObInsertObject(
    01285                 Object,
    01286                 NULL,
    01287                 (ACCESS_MASK)0,
    01288                 0,
    01289                 NULL,
    01290                 &ObjHandle
    01291                 );
    01292
    01293     if (!NT_SUCCESS(Status)) {
    01294         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    01295             KdPrint(("CmpCreateRegistryRoot: "));
    01296             KdPrint(("ObInsertObject(\\REGISTRY) failed %08lx\n", Status));
    01297         }
    01298         return FALSE;
    01299     }
    01300
    01301     //
    01302     // We cannot make the root permanent because registry objects in
    01303     // general are not allowed to be.  (They're stable via virtue of being
    01304     // stored in the registry, not the object manager.)  But we never
    01305     // ever want the root to go away.  So reference it.
    01306     //
    01307     if (! NT_SUCCESS(Status = ObReferenceObjectByHandle(
    01308                         ObjHandle,
    01309                         KEY_READ,
    01310                         NULL,
    01311                         KernelMode,
    01312                         &ObjectPointer,
    01313                         NULL
    01314                         )))
    01315     {
    01316         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    01317             KdPrint(("CmpCreateRegistryRoot: "));
    01318             KdPrint(("ObReferenceObjectByHandle failed %08lx\n", Status));
    01319         }
    01320         return FALSE;
    01321     }
    01322
    01323     return TRUE;
    01324 }
    01325
    01326
    01327 BOOLEAN
    01328 CmpCreateRootNode(
    01329     IN PHHIVE   Hive,
    01330     IN PWSTR    Name,
    01331     OUT PHCELL_INDEX RootCellIndex
    01332     )
    01333 /*++
    01334
    01335 Routine Description:
    01336
    01337     Manually create the root node of a hive.
    01338
    01339 Arguments:
    01340
    01341     Hive - pointer to a Hive (Hv level) control structure
    01342
    01343     Name - pointer to a unicode name string
    01344
    01345     RootCellIndex - supplies pointer to a variable to recieve
    01346                     the cell index of the created node.
    01347
    01348 Return Value:
    01349
    01350     TRUE == success, FALSE == failure
    01351
    01352 --*/
    01353 {
    01354     UNICODE_STRING temp;
    01355     PCELL_DATA CellData;
    01356     CM_KEY_REFERENCE Key;
    01357     LARGE_INTEGER systemtime;
    01358
    01359     PAGED_CODE();
    01360     //
    01361     // Allocate the node.
    01362     //
    01363     RtlInitUnicodeString(&temp, Name);
    01364     *RootCellIndex = HvAllocateCell(
    01365                 Hive,
    01366                 CmpHKeyNodeSize(Hive, &temp),
    01367                 Stable
    01368                 );
    01369     if (*RootCellIndex == HCELL_NIL) {
    01370         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    01371             KdPrint(("CmpCreateRootNode: HvAllocateCell failed\n"));
    01372         }
    01373         return FALSE;
    01374     }
    01375
    01376     Hive->BaseBlock->RootCell = *RootCellIndex;
    01377
    01378     CellData = HvGetCell(Hive, *RootCellIndex);
    01379
    01380     //
    01381     // Initialize the node
    01382     //
    01383     CellData->u.KeyNode.Signature = CM_KEY_NODE_SIGNATURE;
    01384     CellData->u.KeyNode.Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
    01385     KeQuerySystemTime(&systemtime);
    01386     CellData->u.KeyNode.LastWriteTime = systemtime;
    01387 //    CellData->u.KeyNode.TitleIndex = 0;
    01388     CellData->u.KeyNode.Parent = HCELL_NIL;
    01389
    01390     CellData->u.KeyNode.SubKeyCounts[Stable] = 0;
    01391     CellData->u.KeyNode.SubKeyCounts[Volatile] = 0;
    01392     CellData->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL;
    01393     CellData->u.KeyNode.SubKeyLists[Volatile] = HCELL_NIL;
    01394
    01395     CellData->u.KeyNode.ValueList.Count = 0;
    01396     CellData->u.KeyNode.ValueList.List = HCELL_NIL;
    01397     CellData->u.KeyNode.Security = HCELL_NIL;
    01398     CellData->u.KeyNode.Class = HCELL_NIL;
    01399     CellData->u.KeyNode.ClassLength = 0;
    01400
    01401     CellData->u.KeyNode.MaxValueDataLen = 0;
    01402     CellData->u.KeyNode.MaxNameLen = 0;
    01403     CellData->u.KeyNode.MaxValueNameLen = 0;
    01404     CellData->u.KeyNode.MaxClassLen = 0;
    01405
    01406     CellData->u.KeyNode.NameLength = CmpCopyName(Hive,
    01407                                                  CellData->u.KeyNode.Name,
    01408                                                  &temp);
    01409     if (CellData->u.KeyNode.NameLength < temp.Length) {
    01410         CellData->u.KeyNode.Flags |= KEY_COMP_NAME;
    01411     }
    01412
    01413     Key.KeyHive = Hive;
    01414     Key.KeyCell = *RootCellIndex;
    01415
    01416     return TRUE;
    01417 }
    01418
    01419
    01420 NTSTATUS
    01421 CmpLinkHiveToMaster(
    01422     PUNICODE_STRING LinkName,
    01423     HANDLE RootDirectory,
    01424     PCMHIVE CmHive,
    01425     BOOLEAN Allocate,
    01426     PSECURITY_DESCRIPTOR SecurityDescriptor
    01427     )
    01428 /*++
    01429
    01430 Routine Description:
    01431
    01432     The existing, "free floating" hive CmHive describes is linked into
    01433     the name space at the node named by LinkName.  The node will be created.
    01434     The hive is assumed to already have an appropriate root node.
    01435
    01436 Arguments:
    01437
    01438     LinkName - supplies a pointer to a unicode string which describes where
    01439                 in the registry name space the hive is to be linked.
    01440                 All components but the last must exist.  The last must not.
    01441
    01442     RootDirectory - Supplies the handle the LinkName is relative to.
    01443
    01444     CmHive - pointer to a CMHIVE structure describing the hive to link in.
    01445
    01446     Allocate - TRUE indicates that the root cell is to be created
    01447                FALSE indicates the root cell already exists.
    01448
    01449     SecurityDescriptor - supplies a pointer to the security descriptor to
    01450                be placed on the hive root.
    01451
    01452 Return Value:
    01453
    01454     TRUE == success, FALSE == failure
    01455
    01456 --*/
    01457 {
    01458     OBJECT_ATTRIBUTES   ObjectAttributes;
    01459     HANDLE              KeyHandle;
    01460     CM_PARSE_CONTEXT    ParseContext;
    01461     NTSTATUS            Status;
    01462     PCM_KEY_BODY        KeyBody;
    01463
    01464     PAGED_CODE();
    01465     //
    01466     // Fill in special ParseContext to indicate that we are creating
    01467     // a link node and opening or creating a root node.
    01468     //
    01469     ParseContext.TitleIndex = 0;
    01470     ParseContext.Class.Length = 0;
    01471     ParseContext.Class.MaximumLength = 0;
    01472     ParseContext.Class.Buffer = NULL;
    01473     ParseContext.CreateOptions = 0;
    01474     ParseContext.CreateLink = TRUE;
    01475     ParseContext.ChildHive.KeyHive = &CmHive->Hive;
    01476     if (Allocate) {
    01477
    01478         //
    01479         // Creating a new root node
    01480         //
    01481
    01482         ParseContext.ChildHive.KeyCell = HCELL_NIL;
    01483     } else {
    01484
    01485         //
    01486         // Opening an existing root node
    01487         //
    01488
    01489         ParseContext.ChildHive.KeyCell = CmHive->Hive.BaseBlock->RootCell;
    01490     }
    01491
    01492     //
    01493     // Create a path to the hive
    01494     //
    01495     InitializeObjectAttributes(
    01496         &ObjectAttributes,
    01497         LinkName,
    01498         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
    01499         (HANDLE)RootDirectory,
    01500         SecurityDescriptor
    01501         );
    01502
    01503     Status = ObOpenObjectByName( &ObjectAttributes,
    01504                                  CmpKeyObjectType,
    01505                                  KernelMode,
    01506                                  NULL,
    01507                                  KEY_READ | KEY_WRITE,
    01508                                  (PVOID)&ParseContext,
    01509                                  &KeyHandle );
    01510
    01511     if (!NT_SUCCESS(Status)) {
    01512         CMLOG(CML_MAJOR, CMS_INIT_ERROR) {
    01513             KdPrint(("CmpLinkHiveToMaster: "));
    01514             KdPrint(("ObOpenObjectByName() failed %08lx\n", Status));
    01515             KdPrint(("\tLinkName='%ws'\n", LinkName));
    01516         }
    01517         return Status;
    01518     }
    01519
    01520     //
    01521     // Report the notification event
    01522     //
    01523     Status = ObReferenceObjectByHandle(KeyHandle,
    01524                                        0,
    01525                                        CmpKeyObjectType,
    01526                                        KernelMode,
    01527                                        (PVOID *)&KeyBody,
    01528                                        NULL);
    01529     ASSERT(NT_SUCCESS(Status));
    01530     if (NT_SUCCESS(Status)) {
    01531         CmpReportNotify(KeyBody->KeyControlBlock,
    01532                         KeyBody->KeyControlBlock->KeyHive,
    01533                         KeyBody->KeyControlBlock->KeyCell,
    01534                         REG_NOTIFY_CHANGE_NAME);
    01535
    01536         ObDereferenceObject((PVOID)KeyBody);
    01537     }
    01538
    01539     ZwClose(KeyHandle);
    01540     return STATUS_SUCCESS;
    01541 }
    01542
    01543
    01544 VOID
    01545 CmpSetVersionData(
    01546     VOID
    01547     )
    01548 /*++
    01549
    01550 Routine Description:
    01551
    01552     Create \REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion:
    01553                 CurrentVersion = VER_PRODUCTVERSION_STR             // From ntverp.h
    01554                 CurrentBuildNumber = VER_PRODUCTBUILD               // From ntverp.h
    01555                 CurrentType = "[Multiprocessor|Uniprocessor]        // From NT_UP
    01556                                 [Retail|Free|Checked]"              // From DBG, DEVL
    01557                 SystemRoot = "[c:\nt]"
    01558
    01559
    01560     NOTE:   It is not worth bugchecking over this, so if it doesn't
    01561             work, just fail.
    01562
    01563 Arguments:
    01564
    01565 Return Value:
    01566
    01567 --*/
    01568 {
    01569     ANSI_STRING     AnsiString;
    01570     UNICODE_STRING  NameString;
    01571     UNICODE_STRING  ValueString;
    01572     HANDLE          key1, key2;
    01573     UCHAR           WorkString[128];
    01574     WCHAR           ValueBuffer[128];
    01575     OBJECT_ATTRIBUTES   ObjectAttributes;
    01576     NTSTATUS            status;
    01577     PUCHAR              proctype;
    01578     PUCHAR              buildtype;
    01579     PSECURITY_DESCRIPTOR SecurityDescriptor;
    01580
    01581     PAGED_CODE();
    01582     //
    01583     // Get default security descriptor for the nodes we will create.
    01584     //
    01585     SecurityDescriptor = CmpHiveRootSecurityDescriptor();
    01586
    01587     //
    01588     // Create the key
    01589     //
    01590     RtlInitUnicodeString(
    01591         &NameString,
    01592         L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft"
    01593         );
    01594
    01595     InitializeObjectAttributes(
    01596         &ObjectAttributes,
    01597         &NameString,
    01598         OBJ_CASE_INSENSITIVE,
    01599         (HANDLE)NULL,
    01600         SecurityDescriptor
    01601         );
    01602
    01603     status = NtCreateKey(
    01604                 &key1,
    01605                 KEY_CREATE_SUB_KEY,
    01606                 &ObjectAttributes,
    01607                 0,
    01608                 &nullclass,
    01609                 0,
    01610                 NULL
    01611                 );
    01612
    01613     if (!NT_SUCCESS(status)) {
    01614 #if DBG
    01615         DbgPrint("CMINIT: CreateKey of %wZ failed - Status == %lx\n",
    01616                  &NameString, status);
    01617 #endif
    01618         ExFreePool(SecurityDescriptor);
    01619         return;
    01620     }
    01621
    01622     RtlInitUnicodeString(
    01623         &NameString,
    01624         L"Windows NT"
    01625         );
    01626
    01627     InitializeObjectAttributes(
    01628         &ObjectAttributes,
    01629         &NameString,
    01630         OBJ_CASE_INSENSITIVE,
    01631         key1,
    01632         SecurityDescriptor
    01633         );
    01634
    01635     status = NtCreateKey(
    01636                 &key2,
    01637                 KEY_SET_VALUE,
    01638                 &ObjectAttributes,
    01639                 0,
    01640                 &nullclass,
    01641                 0,
    01642                 NULL
    01643                 );
    01644     NtClose(key1);
    01645     RtlInitUnicodeString(
    01646         &NameString,
    01647         L"CurrentVersion"
    01648         );
    01649
    01650     InitializeObjectAttributes(
    01651         &ObjectAttributes,
    01652         &NameString,
    01653         OBJ_CASE_INSENSITIVE,
    01654         key2,
    01655         SecurityDescriptor
    01656         );
    01657
    01658     status = NtCreateKey(
    01659                 &key1,
    01660                 KEY_SET_VALUE,
    01661                 &ObjectAttributes,
    01662                 0,
    01663                 &nullclass,
    01664                 0,
    01665                 NULL
    01666                 );
    01667     NtClose(key2);
    01668     ExFreePool(SecurityDescriptor);
    01669     if (!NT_SUCCESS(status)) {
    01670 #if DBG
    01671         DbgPrint("CMINIT: CreateKey of %wZ failed - Status == %lx\n",
    01672                  &NameString, status);
    01673 #endif
    01674         return;
    01675     }
    01676
    01677
    01678     //
    01679     // Set the value entries for the key
    01680     //
    01681     RtlInitUnicodeString(
    01682         &NameString,
    01683         L"CurrentVersion"
    01684         );
    01685
    01686     status = NtSetValueKey(
    01687         key1,
    01688         &NameString,
    01689         0,              // TitleIndex
    01690         REG_SZ,
    01691         CmVersionString.Buffer,
    01692         CmVersionString.Length + sizeof( UNICODE_NULL )
    01693         );
    01694 #if DBG
    01695     if (!NT_SUCCESS(status)) {
    01696         DbgPrint("CMINIT: SetValueKey of %wZ failed - Status == %lx\n",
    01697                  &NameString, status);
    01698     }
    01699 #endif
    01700     (RtlFreeStringRoutine)( CmVersionString.Buffer );
    01701     RtlInitUnicodeString( &CmVersionString, NULL );
    01702
    01703     RtlInitUnicodeString(
    01704         &NameString,
    01705         L"CurrentBuildNumber"
    01706         );
    01707
    01708     sprintf(
    01709         WorkString,
    01710         "%u",
    01711         NtBuildNumber & 0xFFFF
    01712         );
    01713     RtlInitAnsiString( &AnsiString, WorkString );
    01714
    01715     ValueString.Buffer = ValueBuffer;
    01716     ValueString.Length = 0;
    01717     ValueString.MaximumLength = sizeof( ValueBuffer );
    01718
    01719     RtlAnsiStringToUnicodeString( &ValueString, &AnsiString, FALSE );
    01720
    01721     status = NtSetValueKey(
    01722         key1,
    01723         &NameString,
    01724         0,              // TitleIndex
    01725         REG_SZ,
    01726         ValueString.Buffer,
    01727         ValueString.Length + sizeof( UNICODE_NULL )
    01728         );
    01729 #if DBG
    01730     if (!NT_SUCCESS(status)) {
    01731         DbgPrint("CMINIT: SetValueKey of %wZ failed - Status == %lx\n",
    01732                  &NameString, status);
    01733     }
    01734 #endif
    01735
    01736     RtlInitUnicodeString(
    01737         &NameString,
    01738         L"CurrentType"
    01739         );
    01740
    01741 #if defined(NT_UP)
    01742     proctype = "Uniprocessor";
    01743 #else
    01744     proctype = "Multiprocessor";
    01745 #endif
    01746
    01747 #if DBG
    01748     buildtype = "Checked";
    01749 #else
    01750 #if DEVL
    01751     buildtype = "Free";
    01752 #else
    01753     buildtype = "Retail";
    01754 #endif
    01755
    01756 #endif
    01757
    01758     sprintf(
    01759         WorkString,
    01760         "%s %s",
    01761         proctype,
    01762         buildtype
    01763         );
    01764     RtlInitAnsiString( &AnsiString, WorkString );
    01765
    01766     ValueString.Buffer = ValueBuffer;
    01767     ValueString.Length = 0;
    01768     ValueString.MaximumLength = sizeof( ValueBuffer );
    01769
    01770     RtlAnsiStringToUnicodeString( &ValueString, &AnsiString, FALSE );
    01771
    01772     status = NtSetValueKey(
    01773         key1,
    01774         &NameString,
    01775         0,              // TitleIndex
    01776         REG_SZ,
    01777         ValueString.Buffer,
    01778         ValueString.Length + sizeof( UNICODE_NULL )
    01779         );
    01780
    01781     RtlInitUnicodeString(
    01782         &NameString,
    01783         L"CSDVersion"
    01784         );
    01785
    01786     if (CmCSDVersionString.Length != 0) {
    01787         status = NtSetValueKey(
    01788             key1,
    01789             &NameString,
    01790             0,              // TitleIndex
    01791             REG_SZ,
    01792             CmCSDVersionString.Buffer,
    01793             CmCSDVersionString.Length + sizeof( UNICODE_NULL )
    01794             );
    01795 #if DBG
    01796         if (!NT_SUCCESS(status)) {
    01797             DbgPrint("CMINIT: SetValueKey of %wZ failed - Status == %lx\n",
    01798                      &NameString, status);
    01799         }
    01800 #endif
    01801         (RtlFreeStringRoutine)( CmCSDVersionString.Buffer );
    01802         RtlInitUnicodeString( &CmCSDVersionString, NULL );
    01803     } else {
    01804         status = NtDeleteValueKey(
    01805             key1,
    01806             &NameString
    01807             );
    01808 #if DBG
    01809         if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) {
    01810             DbgPrint("CMINIT: DeleteValueKey of %wZ failed - Status == %lx\n",
    01811                      &NameString, status);
    01812         }
    01813 #endif
    01814     }
    01815     RtlInitUnicodeString(&NameString,
    01816                          L"SystemRoot");
    01817     status = NtSetValueKey(key1,
    01818                            &NameString,
    01819                            0,
    01820                            REG_SZ,
    01821                            NtSystemRoot.Buffer,
    01822                            NtSystemRoot.Length + sizeof(UNICODE_NULL));
    01823 #if DBG
    01824     if (!NT_SUCCESS(status)) {
    01825         DbgPrint("CMINIT: SetValueKey of %wZ failed - Status == %lx\n",
    01826                  &NameString,
    01827                  status);
    01828     }
    01829 #endif
    01830     NtClose(key1);
    01831
    01832     //
    01833     // Set each processor to it's optimal configuration.
    01834     //
    01835     // Note: this call is performed interlocked such that the user
    01836     // can disable this automatic configuration update.
    01837     //
    01838
    01839     CmpInterlockedFunction(CmpProcessorControl, CmpConfigureProcessors);
    01840
    01841     return;
    01842 }
    01843
    01844 NTSTATUS
    01845 CmpInterlockedFunction (
    01846     PWCHAR RegistryValueKey,
    01847     VOID (*InterlockedFunction)(VOID)
    01848     )
    01849 /*++
    01850
    01851 Routine Description:
    01852
    01853     This routine guards calling the InterlockedFunction in the
    01854     passed RegistryValueKey.
    01855
    01856     The RegistryValueKey will record the status of the first
    01857     call to the InterlockedFunction.  If the system crashes
    01858     durning this call then ValueKey will be left in a state
    01859     where the InterlockedFunction will not be called on subsequent
    01860     attempts.
    01861
    01862 Arguments:
    01863
    01864     RegistryValueKey - ValueKey name for Control\Session Manager
    01865     InterlockedFunction - Function to call
    01866
    01867 Return Value:
    01868
    01869     STATUS_SUCCESS  - The interlocked function was successfully called
    01870
    01871
    01872 --*/
    01873 {
    01874     OBJECT_ATTRIBUTES   objectAttributes;
    01875     HANDLE              hControl, hSession;
    01876     UNICODE_STRING      Name;
    01877     UCHAR               Buffer [sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG)];
    01878     ULONG               length, Value;
    01879     NTSTATUS            status;
    01880
    01881     PAGED_CODE();
    01882
    01883     //
    01884     // Open CurrentControlSet
    01885     //
    01886
    01887     InitializeObjectAttributes (
    01888         &objectAttributes,
    01889         &CmRegistryMachineSystemCurrentControlSet,
    01890         OBJ_CASE_INSENSITIVE,
    01891         NULL,
    01892         NULL
    01893         );
    01894
    01895     status = NtOpenKey (&hControl, KEY_READ | KEY_WRITE, &objectAttributes);
    01896     if (!NT_SUCCESS(status)) {
    01897         return status;
    01898     }
    01899
    01900     //
    01901     // Open Control\Session Manager
    01902     //
    01903
    01904     RtlInitUnicodeString (&Name, CmpControlSessionManager);
    01905     InitializeObjectAttributes (
    01906         &objectAttributes,
    01907         &Name,
    01908         OBJ_CASE_INSENSITIVE,
    01909         hControl,
    01910         NULL
    01911         );
    01912
    01913     status = NtOpenKey (&hSession, KEY_READ | KEY_WRITE, &objectAttributes );
    01914     NtClose (hControl);
    01915     if (!NT_SUCCESS(status)) {
    01916         return status;
    01917     }
    01918
    01919     //
    01920     // Read ValueKey to interlock operation with
    01921     //
    01922
    01923     RtlInitUnicodeString (&Name, RegistryValueKey);
    01924     status = NtQueryValueKey (hSession,
    01925                               &Name,
    01926                               KeyValuePartialInformation,
    01927                               Buffer,
    01928                               sizeof (Buffer),
    01929                               &length );
    01930
    01931     Value = 0;
    01932     if (NT_SUCCESS(status)) {
    01933         Value = ((PKEY_VALUE_PARTIAL_INFORMATION)Buffer)->Data[0];
    01934     }
    01935
    01936     //
    01937     // Value 0  - Before InterlockedFunction
    01938     //       1  - In the middle of InterlockedFunction
    01939     //       2  - After InterlockedFunction
    01940     //
    01941     // If the value is a 0, then we haven't tried calling this
    01942     // interlocked function, set the value to a 1 and try it.
    01943     //
    01944     // If the value is a 1, then we crased durning an execution
    01945     // of the interlocked function last time, don't try it again.
    01946     //
    01947     // If the value is a 2, then we called the interlocked function
    01948     // before and it worked.  Call it again this time.
    01949     //
    01950
    01951     if (Value != 1) {
    01952
    01953         if (Value != 2) {
    01954             //
    01955             // This interlocked function is not known to work.  Write
    01956             // a 1 to this value so we can detect if we crash durning
    01957             // this call.
    01958             //
    01959
    01960             Value = 1;
    01961             NtSetValueKey (hSession, &Name, 0L, REG_DWORD, &Value, sizeof (Value));
    01962             NtFlushKey    (hSession);   // wait until it's on the disk
    01963         }
    01964
    01965         InterlockedFunction();
    01966
    01967         if (Value != 2) {
    01968             //
    01969             // The worker function didn't crash - update the value for
    01970             // this interlocked function to 2.
    01971             //
    01972
    01973             Value = 2;
    01974             NtSetValueKey (hSession, &Name, 0L, REG_DWORD, &Value, sizeof (Value));
    01975         }
    01976
    01977     } else {
    01978         status = STATUS_UNSUCCESSFUL;
    01979     }
    01980
    01981     NtClose (hSession);
    01982     return status;
    01983 }
    01984
    01985 VOID
    01986 CmpConfigureProcessors (
    01987     VOID
    01988     )
    01989 /*++
    01990
    01991 Routine Description:
    01992
    01993     Set each processor to it's optimal settings for NT.
    01994
    01995 --*/
    01996 {
    01997     ULONG   i;
    01998
    01999     PAGED_CODE();
    02000
    02001     //
    02002     // Set each processor into its best NT configuration
    02003     //
    02004
    02005     for (i=0; i < (ULONG)KeNumberProcessors; i++) {
    02006         KeSetSystemAffinityThread((KAFFINITY) 1 << i);
    02007
    02008 #if i386
    02009         // for now x86 only
    02010         KeOptimizeProcessorControlState ();
    02011 #endif
    02012     }
    02013
    02014     //
    02015     // Restore threads affinity
    02016     //
    02017
    02018     KeRevertToUserAffinityThread();
    02019 }
    02020
    02021 BOOLEAN
    02022 CmpInitializeSystemHive(
    02023     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    02024     )
    02025 /*++
    02026
    02027 Routine Description:
    02028
    02029     Initializes the SYSTEM hive based on the raw hive image passed in
    02030     from the OS Loader.
    02031
    02032 Arguments:
    02033
    02034     LoaderBlock - Supplies a pointer to the Loader Block passed in by
    02035         the OS Loader.
    02036
    02037 Return Value:
    02038
    02039     TRUE - it worked
    02040
    02041     FALSE - it failed
    02042
    02043 --*/
    02044
    02045 {
    02046     PCMHIVE SystemHive;
    02047     PVOID HiveImageBase;
    02048     BOOLEAN Allocate=FALSE;
    02049     PSECURITY_DESCRIPTOR SecurityDescriptor;
    02050     NTSTATUS Status;
    02051     STRING  TempString;
    02052
    02053
    02054     PAGED_CODE();
    02055
    02056     //
    02057     // capture tail of boot.ini line (load options, portable)
    02058     //
    02059     RtlInitAnsiString(
    02060         &TempString,
    02061         LoaderBlock->LoadOptions
    02062         );
    02063
    02064     CmpLoadOptions.Length = 0;
    02065     CmpLoadOptions.MaximumLength = (TempString.Length+1)*sizeof(WCHAR);
    02066     CmpLoadOptions.Buffer = ExAllocatePool(
    02067                                 PagedPool, (TempString.Length+1)*sizeof(WCHAR));
    02068
    02069     if (CmpLoadOptions.Buffer == NULL) {
    02070         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,5,6,0,0); // odds against this are huge
    02071     }
    02072     RtlAnsiStringToUnicodeString(
    02073         &CmpLoadOptions,
    02074         &TempString,
    02075         FALSE
    02076         );
    02077     CmpLoadOptions.Buffer[TempString.Length] = UNICODE_NULL;
    02078     CmpLoadOptions.Length += sizeof(WCHAR);
    02079
    02080
    02081     //
    02082     // move the loaded registry into the real registry
    02083     //
    02084     HiveImageBase = LoaderBlock->RegistryBase;
    02085
    02086     if (HiveImageBase == NULL) {
    02087         //
    02088         // No memory descriptor for the hive, so we must recreate it.
    02089         //
    02090         Status = CmpInitializeHive(&SystemHive,
    02091                     HINIT_CREATE,
    02092                     0,
    02093                     HFILE_TYPE_ALTERNATE,
    02094                     NULL,
    02095                     NULL,
    02096                     NULL,
    02097                     NULL,
    02098                     NULL,
    02099                     &CmpSystemFileName);
    02100         if (!NT_SUCCESS(Status)) {
    02101             CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02102                 KdPrint(("CmpInitializeSystemHive: "));
    02103                 KdPrint(("Couldn't initialize newly allocated SYSTEM hive\n"));
    02104             }
    02105             return(FALSE);
    02106         }
    02107         Allocate = TRUE;
    02108
    02109     } else {
    02110
    02111         //
    02112         // There is a memory image for the hive, copy it and make it active
    02113         //
    02114         Status = CmpInitializeHive(&SystemHive,
    02115                     HINIT_MEMORY,
    02116                     0,
    02117                     HFILE_TYPE_ALTERNATE,
    02118                     HiveImageBase,
    02119                     NULL,
    02120                     NULL,
    02121                     NULL,
    02122                     NULL,
    02123                     &CmpSystemFileName);
    02124         if (!NT_SUCCESS(Status)) {
    02125                 CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02126                 KdPrint(("CmpInitializeSystemHive: "));
    02127                 KdPrint(("Couldn't initialize OS Loader-loaded SYSTEM hive\n"));
    02128             }
    02129             return(FALSE);
    02130         }
    02131
    02132         if ( CmCheckRegistry(SystemHive, TRUE) != 0) {
    02133             //
    02134             // We couldn't use the SYSTEM hive passed in from the loader.
    02135             // We are dead.
    02136             //
    02137             //
    02138             KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,5,7,0,0);
    02139         }
    02140         Allocate = FALSE;
    02141     }
    02142
    02143     //
    02144     // Create the link node
    02145     //
    02146     SecurityDescriptor = CmpHiveRootSecurityDescriptor();
    02147
    02148     Status = CmpLinkHiveToMaster(&CmRegistryMachineSystemName,
    02149                                  NULL,
    02150                                  SystemHive,
    02151                                  Allocate,
    02152                                  SecurityDescriptor);
    02153     ExFreePool(SecurityDescriptor);
    02154
    02155     if (!NT_SUCCESS(Status)) {
    02156         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02157             KdPrint(("CmInitSystem1: CmpLinkHiveToMaster(Hardware) failed\n"));
    02158         }
    02159         return(FALSE);
    02160     }
    02161
    02162     CmpMachineHiveList[SYSTEM_HIVE_INDEX].CmHive = SystemHive;
    02163
    02164     return(TRUE);
    02165 }
    02166
    02167
    02168 PHANDLE
    02169 CmGetSystemDriverList(
    02170     VOID
    02171     )
    02172
    02173 /*++
    02174
    02175 Routine Description:
    02176
    02177     Traverses the current SERVICES subtree and creates the list of drivers
    02178     to be loaded during Phase 1 initialization.
    02179
    02180 Arguments:
    02181
    02182     None
    02183
    02184 Return Value:
    02185
    02186     A pointer to an array of handles, each of which refers to a key in
    02187     the \Services section of the control set.  The caller will traverse
    02188     this array and load and initialize the drivers described by the keys.
    02189
    02190     The last key will be NULL.  The array is allocated in Pool and should
    02191     be freed by the caller.
    02192
    02193 --*/
    02194
    02195 {
    02196     OBJECT_ATTRIBUTES ObjectAttributes;
    02197     HANDLE SystemHandle;
    02198     UNICODE_STRING Name;
    02199     NTSTATUS Status;
    02200     PCM_KEY_BODY KeyBody;
    02201     LIST_ENTRY DriverList;
    02202     PHHIVE Hive;
    02203     HCELL_INDEX RootCell;
    02204     HCELL_INDEX ControlCell;
    02205     ULONG DriverCount;
    02206     PLIST_ENTRY Current;
    02207     PHANDLE Handle;
    02208     PBOOT_DRIVER_LIST_ENTRY DriverEntry;
    02209     BOOLEAN Success;
    02210     BOOLEAN AutoSelect;
    02211
    02212     PAGED_CODE();
    02213     InitializeListHead(&DriverList);
    02214     RtlInitUnicodeString(&Name,
    02215                          L"\\Registry\\Machine\\System");
    02216
    02217     InitializeObjectAttributes(&ObjectAttributes,
    02218                                &Name,
    02219                                OBJ_CASE_INSENSITIVE,
    02220                                (HANDLE)NULL,
    02221                                NULL);
    02222     Status = NtOpenKey(&SystemHandle,
    02223                        KEY_READ,
    02224                        &ObjectAttributes);
    02225
    02226     if (!NT_SUCCESS(Status)) {
    02227         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02228             KdPrint(("CM: CmGetSystemDriverList couldn't open registry key %wZ\n",&Name));
    02229             KdPrint(("CM:     status %08lx\n", Status));
    02230         }
    02231         return(NULL);
    02232     }
    02233
    02234
    02235     Status = ObReferenceObjectByHandle( SystemHandle,
    02236                                         KEY_QUERY_VALUE,
    02237                                         CmpKeyObjectType,
    02238                                         KernelMode,
    02239                                         (PVOID *)(&KeyBody),
    02240                                         NULL );
    02241     if (!NT_SUCCESS(Status)) {
    02242         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02243             KdPrint(("CM: CmGetSystemDriverList couldn't dereference Systemhandle\n"));
    02244             KdPrint(("CM:     status %08lx\n", Status));
    02245         }
    02246         NtClose(SystemHandle);
    02247         return(NULL);
    02248     }
    02249
    02250     CmpLockRegistryExclusive();
    02251
    02252     Hive = KeyBody->KeyControlBlock->KeyHive;
    02253     RootCell = KeyBody->KeyControlBlock->KeyCell;
    02254
    02255     //
    02256     // Now we have found out the PHHIVE and HCELL_INDEX of the root of the
    02257     // SYSTEM hive, we can use all the same code that the OS Loader does.
    02258     //
    02259
    02260     RtlInitUnicodeString(&Name, L"Current");
    02261     ControlCell = CmpFindControlSet(Hive,
    02262                                     RootCell,
    02263                                     &Name,
    02264                                     &AutoSelect);
    02265     if (ControlCell == HCELL_NIL) {
    02266         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02267             KdPrint(("CM: CmGetSystemDriverList couldn't find control set\n"));
    02268         }
    02269         CmpUnlockRegistry();
    02270         ObDereferenceObject((PVOID)KeyBody);
    02271         NtClose(SystemHandle);
    02272         return(NULL);
    02273     }
    02274
    02275     Success = CmpFindDrivers(Hive,
    02276                              ControlCell,
    02277                              SystemLoad,
    02278                              NULL,
    02279                              &DriverList);
    02280
    02281
    02282     if (!Success) {
    02283         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02284             KdPrint(("CM: CmGetSystemDriverList couldn't find any valid drivers\n"));
    02285         }
    02286         CmpFreeDriverList(Hive, &DriverList);
    02287         CmpUnlockRegistry();
    02288         ObDereferenceObject((PVOID)KeyBody);
    02289         NtClose(SystemHandle);
    02290         return(NULL);
    02291     }
    02292
    02293     if (!CmpSortDriverList(Hive,
    02294                            ControlCell,
    02295                            &DriverList)) {
    02296         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02297             KdPrint(("CM: CmGetSystemDriverList couldn't sort driver list\n"));
    02298         }
    02299         CmpFreeDriverList(Hive, &DriverList);
    02300         CmpUnlockRegistry();
    02301         ObDereferenceObject((PVOID)KeyBody);
    02302         NtClose(SystemHandle);
    02303         return(NULL);
    02304     }
    02305
    02306     if (!CmpResolveDriverDependencies(&DriverList)) {
    02307         CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02308             KdPrint(("CM: CmGetSystemDriverList couldn't resolve driver dependencies\n"));
    02309         }
    02310         CmpFreeDriverList(Hive, &DriverList);
    02311         CmpUnlockRegistry();
    02312         ObDereferenceObject((PVOID)KeyBody);
    02313         NtClose(SystemHandle);
    02314         return(NULL);
    02315     }
    02316     CmpUnlockRegistry();
    02317     ObDereferenceObject((PVOID)KeyBody);
    02318     NtClose(SystemHandle);
    02319
    02320     //
    02321     // We now have a fully sorted and ordered list of drivers to be loaded
    02322     // by IoInit.
    02323     //
    02324
    02325     //
    02326     // Count the nodes in the list.
    02327     //
    02328     Current = DriverList.Flink;
    02329     DriverCount = 0;
    02330     while (Current != &DriverList) {
    02331         ++DriverCount;
    02332         Current = Current->Flink;
    02333     }
    02334
    02335     Handle = (PHANDLE)ExAllocatePool(NonPagedPool,
    02336                                      (DriverCount+1) * sizeof(HANDLE));
    02337
    02338     if (Handle == NULL) {
    02339         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,5,8,0,0); // odds against this are huge
    02340     }
    02341
    02342     //
    02343     // Walk the list, opening each registry key and adding it to the
    02344     // table of handles.
    02345     //
    02346     Current = DriverList.Flink;
    02347     DriverCount = 0;
    02348     while (Current != &DriverList) {
    02349         DriverEntry = CONTAINING_RECORD(Current,
    02350                                         BOOT_DRIVER_LIST_ENTRY,
    02351                                         Link);
    02352
    02353         InitializeObjectAttributes(&ObjectAttributes,
    02354                                    &DriverEntry->RegistryPath,
    02355                                    OBJ_CASE_INSENSITIVE,
    02356                                    (HANDLE)NULL,
    02357                                    NULL);
    02358
    02359         Status = NtOpenKey(Handle+DriverCount,
    02360                            KEY_READ | KEY_WRITE,
    02361                            &ObjectAttributes);
    02362         if (!NT_SUCCESS(Status)) {
    02363             CMLOG(CML_BUGCHECK, CMS_INIT_ERROR) {
    02364                 KdPrint(("CM: CmGetSystemDriverList couldn't open driver "));
    02365                 KdPrint(("key %wZ\n", &DriverEntry->RegistryPath));
    02366                 KdPrint(("    status %08lx\n",Status));
    02367             }
    02368         } else {
    02369             ++DriverCount;
    02370         }
    02371         Current = Current->Flink;
    02372     }
    02373     Handle[DriverCount] = NULL;
    02374
    02375     return(Handle);
    02376 }
    02377
    02378
    02379 VOID
    02380 CmpFreeDriverList(
    02381     IN PHHIVE Hive,
    02382     IN PLIST_ENTRY DriverList
    02383     )
    02384
    02385 /*++
    02386
    02387 Routine Description:
    02388
    02389     Walks down the driver list, freeing each node in it.
    02390
    02391     Note that this calls the hive's free routine pointer to free the memory.
    02392
    02393 Arguments:
    02394
    02395     Hive - Supplies  a pointer to the hive control structure.
    02396
    02397     DriverList - Supplies a pointer to the head of the Driver List.  Note
    02398             that the head of the list is not actually freed, only all the
    02399             entries in the list.
    02400
    02401 Return Value:
    02402
    02403     None.
    02404
    02405 --*/
    02406
    02407 {
    02408     PLIST_ENTRY Next;
    02409     PLIST_ENTRY Current;
    02410
    02411     PAGED_CODE();
    02412     Current = DriverList->Flink;
    02413     while (Current != DriverList) {
    02414         Next = Current->Flink;
    02415         (Hive->Free)((PVOID)Current, sizeof(BOOT_DRIVER_NODE));
    02416         Current = Next;
    02417     }
    02418 }
    02419
    02420
    02421 NTSTATUS
    02422 CmpInitHiveFromFile(
    02423     IN PUNICODE_STRING FileName,
    02424     IN ULONG HiveFlags,
    02425     OUT PCMHIVE *CmHive,
    02426     IN OUT PBOOLEAN Allocate,
    02427     IN OUT PBOOLEAN RegistryLocked
    02428     )
    02429
    02430 /*++
    02431
    02432 Routine Description:
    02433
    02434     This routine opens a file and log, allocates a CMHIVE, and initializes
    02435     it.
    02436
    02437 Arguments:
    02438
    02439     FileName - Supplies name of file to be loaded.
    02440
    02441     HiveFlags - Supplies hive flags to be passed to CmpInitializeHive
    02442
    02443     CmHive   - Returns pointer to initialized hive (if successful)
    02444
    02445     Allocate - IN: if TRUE ok to allocate, if FALSE hive must exist
    02446                     (bug .log may get created)
    02447                OUT: TRUE if actually created hive, FALSE if existed before
    02448
    02449 Return Value:
    02450
    02451     NTSTATUS
    02452
    02453 --*/
    02454
    02455 {
    02456     PCMHIVE NewHive;
    02457     ULONG Disposition;
    02458     ULONG SecondaryDisposition;
    02459     HANDLE PrimaryHandle;
    02460     HANDLE LogHandle;
    02461     NTSTATUS Status;
    02462     ULONG FileType;
    02463     ULONG Operation;
    02464
    02465     BOOLEAN Success;
    02466
    02467     PAGED_CODE();
    02468     *CmHive = NULL;
    02469
    02470     Status = CmpOpenHiveFiles(FileName,
    02471                               L".LOG",
    02472                               &PrimaryHandle,
    02473                               &LogHandle,
    02474                               &Disposition,
    02475                               &SecondaryDisposition,
    02476                               *Allocate,
    02477                               FALSE,
    02478                               NULL);
    02479
    02480     if (!NT_SUCCESS(Status)) {
    02481         return(Status);
    02482     }
    02483
    02484     if (LogHandle == NULL) {
    02485         FileType = HFILE_TYPE_PRIMARY;
    02486     } else {
    02487         FileType = HFILE_TYPE_LOG;
    02488     }
    02489
    02490     if (Disposition == FILE_CREATED) {
    02491         Operation = HINIT_CREATE;
    02492         *Allocate = TRUE;
    02493     } else {
    02494         Operation = HINIT_FILE;
    02495         *Allocate = FALSE;
    02496     }
    02497
    02498     if( !(*RegistryLocked) ) {
    02499         //
    02500         // Registry should be locked exclusive
    02501         // if not, lock it now and signal this to the caller
    02502         //
    02503         CmpLockRegistryExclusive();
    02504         *RegistryLocked = TRUE;
    02505     }
    02506
    02507     Status = CmpInitializeHive(&NewHive,
    02508                                 Operation,
    02509                                 HiveFlags,
    02510                                 FileType,
    02511                                 NULL,
    02512                                 PrimaryHandle,
    02513                                 NULL,
    02514                                 LogHandle,
    02515                                 NULL,
    02516                                 FileName
    02517                                 );
    02518     if (!NT_SUCCESS(Status)) {
    02519         ZwClose(PrimaryHandle);
    02520         if (LogHandle != NULL) {
    02521             ZwClose(LogHandle);
    02522         }
    02523         return(Status);
    02524     } else {
    02525         *CmHive = NewHive;
    02526         return(STATUS_SUCCESS);
    02527     }
    02528 }
    02529
    02530
    02531 NTSTATUS
    02532 CmpAddDockingInfo (
    02533     IN HANDLE Key,
    02534     IN PROFILE_PARAMETER_BLOCK * ProfileBlock
    02535     )
    02536 /*++
    02537 Routine Description:
    02538     Write DockID SerialNumber DockState and Capabilities intot the given
    02539     registry key.
    02540
    02541 --*/
    02542 {
    02543     NTSTATUS status = STATUS_SUCCESS;
    02544     UNICODE_STRING name;
    02545     ULONG value;
    02546
    02547     PAGED_CODE ();
    02548
    02549     value = ProfileBlock->DockingState;
    02550     RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKING_STATE);
    02551     status = NtSetValueKey (Key,
    02552                             &name,
    02553                             0,
    02554                             REG_DWORD,
    02555                             &value,
    02556                             sizeof (value));
    02557
    02558     if (!NT_SUCCESS (status)) {
    02559         return status;
    02560     }
    02561
    02562     value = ProfileBlock->Capabilities;
    02563     RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CAPABILITIES);
    02564     status = NtSetValueKey (Key,
    02565                             &name,
    02566                             0,
    02567                             REG_DWORD,
    02568                             &value,
    02569                             sizeof (value));
    02570
    02571     if (!NT_SUCCESS (status)) {
    02572         return status;
    02573     }
    02574
    02575     value = ProfileBlock->DockID;
    02576     RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKID);
    02577     status = NtSetValueKey (Key,
    02578                             &name,
    02579                             0,
    02580                             REG_DWORD,
    02581                             &value,
    02582                             sizeof (value));
    02583
    02584     if (!NT_SUCCESS (status)) {
    02585         return status;
    02586     }
    02587
    02588     value = ProfileBlock->SerialNumber;
    02589     RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_SERIAL_NUMBER);
    02590     status = NtSetValueKey (Key,
    02591                             &name,
    02592                             0,
    02593                             REG_DWORD,
    02594                             &value,
    02595                             sizeof (value));
    02596
    02597     if (!NT_SUCCESS (status)) {
    02598         return status;
    02599     }
    02600
    02601     return status;
    02602 }
    02603
    02604
    02605 NTSTATUS
    02606 CmpAddAliasEntry (
    02607     IN HANDLE IDConfigDB,
    02608     IN PROFILE_PARAMETER_BLOCK * ProfileBlock,
    02609     IN ULONG  ProfileNumber
    02610     )
    02611 /*++
    02612 Routine Description:
    02613     Create an alias entry in the IDConfigDB database for the given
    02614     hardware profile.
    02615
    02616     Create the "Alias" key if it does not exist.
    02617
    02618 Parameters:
    02619
    02620     IDConfigDB - Pointer to "..\CurrentControlSet\Control\IDConfigDB"
    02621
    02622     ProfileBlock - Description of the current Docking information
    02623
    02624     ProfileNumber -
    02625
    02626 --*/
    02627 {
    02628     OBJECT_ATTRIBUTES attributes;
    02629     NTSTATUS        status = STATUS_SUCCESS;
    02630     CHAR            asciiBuffer [128];
    02631     WCHAR           unicodeBuffer [128];
    02632     ANSI_STRING     ansiString;
    02633     UNICODE_STRING  name;
    02634     HANDLE          aliasKey = NULL;
    02635     HANDLE          aliasEntry = NULL;
    02636     ULONG           value;
    02637     ULONG           disposition;
    02638     ULONG           aliasNumber = 0;
    02639
    02640     PAGED_CODE ();
    02641
    02642     //
    02643     // Find the Alias Key or Create it if it does not already exist.
    02644     //
    02645     RtlInitUnicodeString (&name,CM_HARDWARE_PROFILE_STR_ALIAS);
    02646
    02647     InitializeObjectAttributes (&attributes,
    02648                                 &name,
    02649                                 OBJ_CASE_INSENSITIVE,
    02650                                 IDConfigDB,
    02651                                 NULL);
    02652
    02653     status = NtOpenKey (&aliasKey,
    02654                         KEY_READ | KEY_WRITE,
    02655                         &attributes);
    02656
    02657     if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
    02658         status = NtCreateKey (&aliasKey,
    02659                               KEY_READ | KEY_WRITE,
    02660                               &attributes,
    02661                               0, // no title
    02662                               NULL, // no class
    02663                               0, // no options
    02664                               &disposition);
    02665     }
    02666
    02667     if (!NT_SUCCESS (status)) {
    02668         aliasKey = NULL;
    02669         goto Exit;
    02670     }
    02671
    02672     //
    02673     // Create an entry key
    02674     //
    02675
    02676     while (aliasNumber < 200) {
    02677         aliasNumber++;
    02678
    02679         sprintf(asciiBuffer, "%04d", aliasNumber);
    02680
    02681         RtlInitAnsiString(&ansiString, asciiBuffer);
    02682         name.MaximumLength = sizeof(unicodeBuffer);
    02683         name.Buffer = unicodeBuffer;
    02684         status = RtlAnsiStringToUnicodeString(&name,
    02685                                               &ansiString,
    02686                                               FALSE);
    02687         ASSERT (STATUS_SUCCESS == status);
    02688
    02689         InitializeObjectAttributes(&attributes,
    02690                                    &name,
    02691                                    OBJ_CASE_INSENSITIVE,
    02692                                    aliasKey,
    02693                                    NULL);
    02694
    02695         status = NtOpenKey (&aliasEntry,
    02696                             KEY_READ | KEY_WRITE,
    02697                             &attributes);
    02698
    02699         if (NT_SUCCESS (status)) {
    02700             NtClose (aliasEntry);
    02701
    02702         } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
    02703             status = STATUS_SUCCESS;
    02704             break;
    02705
    02706         } else {
    02707             break;
    02708         }
    02709
    02710     }
    02711     if (!NT_SUCCESS (status)) {
    02712         CMLOG(CML_BUGCHECK, CMS_INIT) {
    02713             KdPrint(("CM: cmpCreateAliasEntry error finding new set %08lx\n",
    02714                      status));
    02715         }
    02716         aliasEntry = 0;
    02717         goto Exit;
    02718     }
    02719
    02720     status = NtCreateKey (&aliasEntry,
    02721                           KEY_READ | KEY_WRITE,
    02722                           &attributes,
    02723                           0,
    02724                           NULL,
    02725                           0,
    02726                           &disposition);
    02727
    02728     if (!NT_SUCCESS (status)) {
    02729         CMLOG(CML_BUGCHECK, CMS_INIT) {
    02730             KdPrint(("CM: cmpCreateAliasEntry error creating new set %08lx\n",
    02731                      status));
    02732         }
    02733         aliasEntry = 0;
    02734         goto Exit;
    02735     }
    02736
    02737     //
    02738     // Write the standard goo
    02739     //
    02740     CmpAddDockingInfo (aliasEntry, ProfileBlock);
    02741
    02742     //
    02743     // Write the Profile Number
    02744     //
    02745     value = ProfileNumber;
    02746     RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PROFILE_NUMBER);
    02747     status = NtSetValueKey (aliasEntry,
    02748                             &name,
    02749                             0,
    02750                             REG_DWORD,
    02751                             &value,
    02752                             sizeof (value));
    02753
    02754 Exit:
    02755
    02756     if (aliasKey) {
    02757         NtClose (aliasKey);
    02758     }
    02759
    02760     if (aliasEntry) {
    02761         NtClose (aliasEntry);
    02762     }
    02763
    02764     return status;
    02765 }
    02766
    02767
    02768 NTSTATUS
    02769 CmpHwprofileDefaultSelect (
    02770     IN  PCM_HARDWARE_PROFILE_LIST ProfileList,
    02771     OUT PULONG ProfileIndexToUse,
    02772     IN  PVOID Context
    02773     )
    02774 {
    02775     UNREFERENCED_PARAMETER (Context);
    02776
    02777     * ProfileIndexToUse = 0;
    02778
    02779     return STATUS_SUCCESS;
    02780 }
    02781
    02782
    02783
    02784
    02785 NTSTATUS
    02786 CmpCreateControlSet(
    02787     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    02788     )
    02789
    02790 /*++
    02791
    02792 Routine Description:
    02793
    02794     This routine sets up the symbolic links from
    02795
    02796         \Registry\Machine\System\CurrentControlSet to
    02797         \Registry\Machine\System\ControlSetNNN
    02798
    02799         \Registry\Machine\System\CurrentControlSet\Hardware Profiles\Current to
    02800         \Registry\Machine\System\ControlSetNNN\Hardware Profiles\NNNN
    02801
    02802     based on the value of \Registry\Machine\System\Select:Current. and
    02803                           \Registry\Machine\System\ControlSetNNN\Control\IDConfigDB:CurrentConfig
    02804
    02805 Arguments:
    02806
    02807     None
    02808
    02809 Return Value:
    02810
    02811     status
    02812
    02813 --*/
    02814
    02815 {
    02816     UNICODE_STRING IDConfigDBName;
    02817     UNICODE_STRING SelectName;
    02818     UNICODE_STRING CurrentName;
    02819     OBJECT_ATTRIBUTES Attributes;
    02820     HANDLE SelectHandle;
    02821     HANDLE CurrentHandle;
    02822     HANDLE IDConfigDB = NULL;
    02823     HANDLE CurrentProfile = NULL;
    02824     HANDLE ParentOfProfile = NULL;
    02825     CHAR AsciiBuffer[128];
    02826     WCHAR UnicodeBuffer[128];
    02827     UCHAR ValueBuffer[128];
    02828     ULONG ControlSet;
    02829     ULONG HWProfile;
    02830     PKEY_VALUE_FULL_INFORMATION Value;
    02831     ANSI_STRING AnsiString;
    02832     NTSTATUS Status;
    02833     ULONG ResultLength;
    02834     ULONG Disposition;
    02835     BOOLEAN signalAcpiEvent = FALSE;
    02836
    02837     PAGED_CODE();
    02838
    02839     RtlInitUnicodeString(&SelectName, L"\\Registry\\Machine\\System\\Select");
    02840     InitializeObjectAttributes(&Attributes,
    02841                                &SelectName,
    02842                                OBJ_CASE_INSENSITIVE,
    02843                                NULL,
    02844                                NULL);
    02845     Status = NtOpenKey(&SelectHandle,
    02846                        KEY_READ,
    02847                        &Attributes);
    02848     if (!NT_SUCCESS(Status)) {
    02849         CMLOG(CML_BUGCHECK, CMS_INIT) {
    02850             KdPrint(("CM: CmpCreateControlSet: Couldn't open Select node %08lx\n",Status));
    02851         }
    02852         return(Status);
    02853     }
    02854
    02855     RtlInitUnicodeString(&CurrentName, L"Current");
    02856     Status = NtQueryValueKey(SelectHandle,
    02857                              &CurrentName,
    02858                              KeyValueFullInformation,
    02859                              ValueBuffer,
    02860                              sizeof(ValueBuffer),
    02861                              &ResultLength);
    02862     NtClose(SelectHandle);
    02863     if (!NT_SUCCESS(Status)) {
    02864         CMLOG(CML_BUGCHECK, CMS_INIT) {
    02865             KdPrint(("CM: CmpCreateControlSet: Couldn't query Select value %08lx\n",Status));
    02866         }
    02867         return(Status);
    02868     }
    02869     Value = (PKEY_VALUE_FULL_INFORMATION)ValueBuffer;
    02870     ControlSet = *(PULONG)((PUCHAR)Value + Value->DataOffset);
    02871
    02872     RtlInitUnicodeString(&CurrentName, L"\\Registry\\Machine\\System\\CurrentControlSet");
    02873     InitializeObjectAttributes(&Attributes,
    02874                                &CurrentName,
    02875                                OBJ_CASE_INSENSITIVE,
    02876                                NULL,
    02877                                NULL);
    02878     Status = NtCreateKey(&CurrentHandle,
    02879                          KEY_CREATE_LINK,
    02880                          &Attributes,
    02881                          0,
    02882                          NULL,
    02883                          REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
    02884                          &Disposition);
    02885     if (!NT_SUCCESS(Status)) {
    02886         CMLOG(CML_BUGCHECK, CMS_INIT) {
    02887             KdPrint(("CM: CmpCreateControlSet: couldn't create CurrentControlSet %08lx\n",Status));
    02888         }
    02889         return(Status);
    02890     }
    02891
    02892     //
    02893     // Check to make sure that the key was created, not just opened.  Since
    02894     // this key is always created volatile, it should never be present in
    02895     // the hive when we boot.
    02896     //
    02897     ASSERT(Disposition == REG_CREATED_NEW_KEY);
    02898
    02899     //
    02900     // Create symbolic link for current hardware profile.
    02901     //
    02902     sprintf(AsciiBuffer, "\\Registry\\Machine\\System\\ControlSet%03d", ControlSet);
    02903     RtlInitAnsiString(&AnsiString, AsciiBuffer);
    02904
    02905     CurrentName.MaximumLength = sizeof(UnicodeBuffer);
    02906     CurrentName.Buffer = UnicodeBuffer;
    02907     Status = RtlAnsiStringToUnicodeString(&CurrentName,
    02908                                           &AnsiString,
    02909                                           FALSE);
    02910     Status = NtSetValueKey(CurrentHandle,
    02911                            &CmSymbolicLinkValueName,
    02912                            0,
    02913                            REG_LINK,
    02914                            CurrentName.Buffer,
    02915                            CurrentName.Length);
    02916
    02917     if (!NT_SUCCESS(Status)) {
    02918         CMLOG(CML_BUGCHECK, CMS_INIT) {
    02919             KdPrint(("CM: CmpCreateControlSet: couldn't create symbolic link "));
    02920             KdPrint(("to %wZ\n",&CurrentName));
    02921             KdPrint(("    Status=%08lx\n",Status));
    02922         }
    02923         return(Status);
    02924     }
    02925
    02926     //
    02927     // Determine the Current Hardware Profile Number
    02928     //
    02929     RtlInitUnicodeString(&IDConfigDBName, L"Control\\IDConfigDB");
    02930     InitializeObjectAttributes(&Attributes,
    02931                                &IDConfigDBName,
    02932                                OBJ_CASE_INSENSITIVE,
    02933                                CurrentHandle,
    02934                                NULL);
    02935     Status = NtOpenKey(&IDConfigDB,
    02936                        KEY_READ,
    02937                        &Attributes);
    02938     NtClose(CurrentHandle);
    02939
    02940     if (!NT_SUCCESS(Status)) {
    02941         IDConfigDB = 0;
    02942         goto Cleanup;
    02943     }
    02944
    02945     RtlInitUnicodeString(&CurrentName, L"CurrentConfig");
    02946     Status = NtQueryValueKey(IDConfigDB,
    02947                              &CurrentName,
    02948                              KeyValueFullInformation,
    02949                              ValueBuffer,
    02950                              sizeof(ValueBuffer),
    02951                              &ResultLength);
    02952
    02953     if (!NT_SUCCESS(Status) ||
    02954         (((PKEY_VALUE_FULL_INFORMATION)ValueBuffer)->Type != REG_DWORD)) {
    02955
    02956         goto Cleanup;
    02957     }
    02958
    02959     Value = (PKEY_VALUE_FULL_INFORMATION)ValueBuffer;
    02960     HWProfile = *(PULONG)((PUCHAR)Value + Value->DataOffset);
    02961     //
    02962     // We know now the config set that the user selected.
    02963     // namely: HWProfile.
    02964     //
    02965
    02966     RtlInitUnicodeString(
    02967               &CurrentName,
    02968               L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles");
    02969     InitializeObjectAttributes(&Attributes,
    02970                                &CurrentName,
    02971                                OBJ_CASE_INSENSITIVE,
    02972                                NULL,
    02973                                NULL);
    02974     Status = NtOpenKey(&ParentOfProfile,
    02975                        KEY_READ,
    02976                        &Attributes);
    02977
    02978     if (!NT_SUCCESS (Status)) {
    02979         ParentOfProfile = 0;
    02980         goto Cleanup;
    02981     }
    02982
    02983     sprintf(AsciiBuffer, "%04d",HWProfile);
    02984     RtlInitAnsiString(&AnsiString, AsciiBuffer);
    02985     CurrentName.MaximumLength = sizeof(UnicodeBuffer);
    02986     CurrentName.Buffer = UnicodeBuffer;
    02987     Status = RtlAnsiStringToUnicodeString(&CurrentName,
    02988                                           &AnsiString,
    02989                                           FALSE);
    02990     ASSERT (STATUS_SUCCESS == Status);
    02991
    02992     InitializeObjectAttributes(&Attributes,
    02993                                &CurrentName,
    02994                                OBJ_CASE_INSENSITIVE,
    02995                                ParentOfProfile,
    02996                                NULL);
    02997
    02998     Status = NtOpenKey (&CurrentProfile,
    02999                         KEY_READ | KEY_WRITE,
    03000                         &Attributes);
    03001
    03002     if (!NT_SUCCESS (Status)) {
    03003         CurrentProfile = 0;
    03004         goto Cleanup;
    03005     }
    03006
    03007     //
    03008     // We need to determine if Value was selected by exact match
    03009     // (TRUE_MATCH) or because the profile selected was aliasable.
    03010     //
    03011     // If aliasable we need to manufacture another alias entry in the
    03012     // alias table.
    03013     //
    03014     // If the profile information is there and not failed then we should
    03015     // mark the Docking state information:
    03016     // (DockID, SerialNumber, DockState, and Capabilities)
    03017     //
    03018
    03019     if (NULL != LoaderBlock->Extension) {
    03020         PLOADER_PARAMETER_EXTENSION extension;
    03021         extension = LoaderBlock->Extension;
    03022         switch (extension->Profile.Status) {
    03023         case HW_PROFILE_STATUS_PRISTINE_MATCH:
    03024             //
    03025             // If the selected profile is pristine then we need to clone.
    03026             //
    03027             Status = CmpCloneHwProfile (IDConfigDB,
    03028                                         ParentOfProfile,
    03029                                         CurrentProfile,
    03030                                         HWProfile,
    03031                                         extension->Profile.DockingState,
    03032                                         &CurrentProfile,
    03033                                         &HWProfile);
    03034             if (!NT_SUCCESS (Status)) {
    03035                 CurrentProfile = 0;
    03036                 goto Cleanup;
    03037             }
    03038
    03039             RtlInitUnicodeString(&CurrentName, L"CurrentConfig");
    03040             Status = NtSetValueKey (IDConfigDB,
    03041                                     &CurrentName,
    03042                                     0,
    03043                                     REG_DWORD,
    03044                                     &HWProfile,
    03045                                     sizeof (HWProfile));
    03046             if (!NT_SUCCESS (Status)) {
    03047                 goto Cleanup;
    03048             }
    03049
    03050             //
    03051             // Fall through
    03052             //
    03053         case HW_PROFILE_STATUS_ALIAS_MATCH:
    03054             //
    03055             // Create the alias entry for this profile.
    03056             //
    03057
    03058             Status = CmpAddAliasEntry (IDConfigDB,
    03059                                        &extension->Profile,
    03060                                        HWProfile);
    03061
    03062 #if 0
    03063             //
    03064             // If we are booting in the undocked state, and creating a brand
    03065             // new alias for this undocked state, we need to create an acpi
    03066             // alias as well that points to this new profile.
    03067             //
    03068             // BUGBUG.
    03069             // We are not checking for the case where we may manufacture more
    03070             // than one bios alias entry for the undocked state.
    03071             // If we do create more than one, then we will of course create
    03072             // more than one acpi alias entry for the undocked state.
    03073             //
    03074             // Therefore we are assuming that when undocked the machine always
    03075             // returns the same serial number.  (Not a bad assumption.)
    03076             //
    03077             // But we are also assuming that if we have more than one NT4 style
    03078             // HW profile (which would allow the user to select such a profile
    03079             // for each boot, and the user selected more than one for two
    03080             // different undocked boots, then we will create two undocked acpi
    03081             // aliases.  (Perhaps that is what we actually want.  I'm not sure,
    03082             // but at least it's noted.
    03083             //
    03084
    03085             if (HW_PROFILE_DOCKSTATE_UNDOCKED == extension->Profile.DockingState) {
    03086                 PROFILE_ACPI_DOCKING_STATE newDockState;
    03087                 //
    03088                 // Note the definition of PROFILE_ACPI_DOCKING_STATE has a
    03089                 // WCHAR array of length 1.
    03090                 //
    03091
    03092
    03093                 newDockState.DockingState = extension->Profile.DockingState;
    03094                 newDockState.SerialLength = 2;
    03095                 newDockState.SerialNumber[0] = L'\0';
    03096
    03097                 Status = CmpAddAcpiAliasEntry (IDConfigDB,
    03098                                                &newDockState,
    03099                                                HWProfile,
    03100                                                UnicodeBuffer,
    03101                                                ValueBuffer,
    03102                                                sizeof (ValueBuffer),
    03103                                                TRUE); // Prevent Duplication
    03104
    03105                 ASSERT (NT_SUCCESS (Status));
    03106             }
    03107 #endif
    03108
    03109             //
    03110             // Fall through
    03111             //
    03112         case HW_PROFILE_STATUS_TRUE_MATCH:
    03113             //
    03114             // Write DockID, SerialNumber, DockState, and Caps into the current
    03115             // Hardware profile.
    03116             //
    03117
    03118 #ifndef DISABLE_CLEAN_HW_PROFILE_INFO
    03119             RtlInitUnicodeString (&CurrentName, CM_HARDWARE_PROFILE_STR_DOCKING_STATE);
    03120             NtDeleteValueKey (CurrentProfile, &CurrentName);
    03121
    03122             RtlInitUnicodeString (&CurrentName, CM_HARDWARE_PROFILE_STR_CAPABILITIES);
    03123             NtDeleteValueKey (CurrentProfile, &CurrentName);
    03124
    03125             RtlInitUnicodeString (&CurrentName, CM_HARDWARE_PROFILE_STR_DOCKID);
    03126             NtDeleteValueKey (CurrentProfile, &CurrentName);
    03127
    03128             RtlInitUnicodeString (&CurrentName, CM_HARDWARE_PROFILE_STR_SERIAL_NUMBER);
    03129             NtDeleteValueKey (CurrentProfile, &CurrentName);
    03130 #endif
    03131
    03132             RtlInitUnicodeString (&CurrentName,
    03133                                   CM_HARDWARE_PROFILE_STR_CURRENT_DOCK_INFO);
    03134
    03135             InitializeObjectAttributes (&Attributes,
    03136                                         &CurrentName,
    03137                                         OBJ_CASE_INSENSITIVE,
    03138                                         IDConfigDB,
    03139                                         NULL);
    03140
    03141             Status = NtCreateKey (&CurrentHandle,
    03142                                   KEY_READ | KEY_WRITE,
    03143                                   &Attributes,
    03144                                   0,
    03145                                   NULL,
    03146                                   REG_OPTION_VOLATILE,
    03147                                   &Disposition);
    03148
    03149             ASSERT (STATUS_SUCCESS == Status);
    03150
    03151             Status = CmpAddDockingInfo (CurrentHandle, &extension->Profile);
    03152
    03153             if (HW_PROFILE_DOCKSTATE_UNDOCKED == extension->Profile.DockingState) {
    03154                 signalAcpiEvent = TRUE;
    03155             }
    03156
    03157             break;
    03158
    03159
    03160         case HW_PROFILE_STATUS_SUCCESS:
    03161         case HW_PROFILE_STATUS_FAILURE:
    03162             break;
    03163
    03164         default:
    03165             ASSERTMSG ("Invalid Profile status state", FALSE);
    03166         }
    03167     }
    03168
    03169     //
    03170     // Create the symbolic link.
    03171     //
    03172     RtlInitUnicodeString(&CurrentName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current");
    03173     InitializeObjectAttributes(&Attributes,
    03174                                &CurrentName,
    03175                                OBJ_CASE_INSENSITIVE,
    03176                                NULL,
    03177                                NULL);
    03178     Status = NtCreateKey(&CurrentHandle,
    03179                          KEY_CREATE_LINK,
    03180                          &Attributes,
    03181                          0,
    03182                          NULL,
    03183                          REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
    03184                          &Disposition);
    03185     if (!NT_SUCCESS(Status)) {
    03186         CMLOG(CML_BUGCHECK, CMS_INIT) {
    03187             KdPrint(("CM: CmpCreateControlSet: couldn't create Hardware Profile\\Current %08lx\n",Status));
    03188         }
    03189     } else {
    03190         ASSERT(Disposition == REG_CREATED_NEW_KEY);
    03191
    03192         sprintf(AsciiBuffer, "\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\%04d",HWProfile);
    03193         RtlInitAnsiString(&AnsiString, AsciiBuffer);
    03194         CurrentName.MaximumLength = sizeof(UnicodeBuffer);
    03195         CurrentName.Buffer = UnicodeBuffer;
    03196         Status = RtlAnsiStringToUnicodeString(&CurrentName,
    03197                                               &AnsiString,
    03198                                               FALSE);
    03199         ASSERT (STATUS_SUCCESS == Status);
    03200
    03201         Status = NtSetValueKey(CurrentHandle,
    03202                                &CmSymbolicLinkValueName,
    03203                                0,
    03204                                REG_LINK,
    03205                                CurrentName.Buffer,
    03206                                CurrentName.Length);
    03207         if (!NT_SUCCESS(Status)) {
    03208             CMLOG(CML_BUGCHECK, CMS_INIT) {
    03209                 KdPrint(("CM: CmpCreateControlSet: couldn't create symbolic link "));
    03210                 KdPrint(("to %wZ\n",&CurrentName));
    03211                 KdPrint(("    Status=%08lx\n",Status));
    03212             }
    03213         }
    03214     }
    03215
    03216     if (signalAcpiEvent) {
    03217         //
    03218         // We are booting in the undocked state.
    03219         // This is interesting because our buddies in PnP cannot tell
    03220         // us when we are booting without a dock.  They can only tell
    03221         // us when they see a hot undock.
    03222         //
    03223         // Therefore in the interest of matching a boot undocked with
    03224         // a hot undock, we need to simulate an acpi undock event.
    03225         //
    03226
    03227         PROFILE_ACPI_DOCKING_STATE newDockState;
    03228         HANDLE profile;
    03229         BOOLEAN changed;
    03230
    03231         newDockState.DockingState = HW_PROFILE_DOCKSTATE_UNDOCKED;
    03232         newDockState.SerialLength = 2;
    03233         newDockState.SerialNumber[0] = L'\0';
    03234
    03235         Status = CmSetAcpiHwProfile (&newDockState,
    03236                                      CmpHwprofileDefaultSelect,
    03237                                      NULL,
    03238                                      &profile,
    03239                                      &changed);
    03240
    03241         ASSERT (NT_SUCCESS (Status));
    03242         NtClose (profile);
    03243     }
    03244
    03245
    03246 Cleanup:
    03247     if (IDConfigDB) {
    03248         NtClose (IDConfigDB);
    03249     }
    03250     if (CurrentProfile) {
    03251         NtClose (CurrentProfile);
    03252     }
    03253     if (ParentOfProfile) {
    03254         NtClose (ParentOfProfile);
    03255     }
    03256
    03257     return(STATUS_SUCCESS);
    03258 }
    03259
    03260
    03261 NTSTATUS
    03262 CmpCloneControlSet(
    03263     VOID
    03264     )
    03265
    03266 /*++
    03267
    03268 Routine Description:
    03269
    03270     First, create a new hive, \registry\machine\clone, which will be
    03271     HIVE_VOLATILE.
    03272
    03273     Second, link \Registry\Machine\System\Clone to it.
    03274
    03275     Third, tree copy \Registry\Machine\System\CurrentControlSet into
    03276     \Registry\Machine\System\Clone (and thus into the clone hive.)
    03277
    03278     When the service controller is done with the clone hive, it can
    03279     simply NtUnloadKey it to free its storage.
    03280
    03281 Arguments:
    03282
    03283     None.  \Registry\Machine\System\CurrentControlSet must already exist.
    03284
    03285 Return Value:
    03286
    03287     NTSTATUS
    03288
    03289 --*/
    03290
    03291 {
    03292     UNICODE_STRING Current;
    03293     UNICODE_STRING Clone;
    03294     HANDLE CurrentHandle;
    03295     HANDLE CloneHandle;
    03296     OBJECT_ATTRIBUTES Attributes;
    03297     NTSTATUS Status;
    03298     PCM_KEY_BODY CurrentKey;
    03299     PCM_KEY_BODY CloneKey;
    03300     ULONG Disposition;
    03301     PSECURITY_DESCRIPTOR Security;
    03302     ULONG SecurityLength;
    03303
    03304     PAGED_CODE();
    03305
    03306     RtlInitUnicodeString(&Current,
    03307                          L"\\Registry\\Machine\\System\\CurrentControlSet");
    03308     RtlInitUnicodeString(&Clone,
    03309                          L"\\Registry\\Machine\\System\\Clone");
    03310
    03311     InitializeObjectAttributes(&Attributes,
    03312                                &Current,
    03313                                OBJ_CASE_INSENSITIVE,
    03314                                NULL,
    03315                                NULL);
    03316     Status = NtOpenKey(&CurrentHandle,
    03317                        KEY_READ,
    03318                        &Attributes);
    03319     if (!NT_SUCCESS(Status)) {
    03320         CMLOG(CML_BUGCHECK, CMS_INIT) {
    03321             KdPrint(("CM: CmpCloneControlSet couldn't open CurrentControlSet %08lx\n",Status));
    03322         }
    03323         return(Status);
    03324     }
    03325
    03326     //
    03327     // Get the security descriptor from the key so we can create the clone
    03328     // tree with the correct ACL.
    03329     //
    03330     Status = NtQuerySecurityObject(CurrentHandle,
    03331                                    DACL_SECURITY_INFORMATION,
    03332                                    NULL,
    03333                                    0,
    03334                                    &SecurityLength);
    03335     if (Status==STATUS_BUFFER_TOO_SMALL) {
    03336         Security=ExAllocatePool(PagedPool,SecurityLength);
    03337         if (Security!=NULL) {
    03338             Status = NtQuerySecurityObject(CurrentHandle,
    03339                                            DACL_SECURITY_INFORMATION,
    03340                                            Security,
    03341                                            SecurityLength,
    03342                                            &SecurityLength);
    03343             if (!NT_SUCCESS(Status)) {
    03344                 CMLOG(CML_BUGCHECK, CMS_INIT) {
    03345                     KdPrint(("CM: CmpCloneControlSet - NtQuerySecurityObject failed %08lx\n",Status));
    03346                 }
    03347                 ExFreePool(Security);
    03348                 Security=NULL;
    03349             }
    03350         }
    03351     } else {
    03352         CMLOG(CML_BUGCHECK, CMS_INIT) {
    03353             KdPrint(("CM: CmpCloneControlSet - NtQuerySecurityObject returned %08lx\n",Status));
    03354         }
    03355         Security=NULL;
    03356     }
    03357
    03358     InitializeObjectAttributes(&Attributes,
    03359                                &Clone,
    03360                                OBJ_CASE_INSENSITIVE,
    03361                                NULL,
    03362                                Security);
    03363     Status = NtCreateKey(&CloneHandle,
    03364                          KEY_READ | KEY_WRITE,
    03365                          &Attributes,
    03366                          0,
    03367                          NULL,
    03368                          REG_OPTION_VOLATILE,
    03369                          &Disposition);
    03370     if (Security!=NULL) {
    03371         ExFreePool(Security);
    03372     }
    03373     if (!NT_SUCCESS(Status)) {
    03374         CMLOG(CML_BUGCHECK, CMS_INIT) {
    03375             KdPrint(("CM: CmpCloneControlSet couldn't create Clone %08lx\n",Status));
    03376         }
    03377         NtClose(CurrentHandle);
    03378         return(Status);
    03379     }
    03380
    03381     //
    03382     // Check to make sure the key was created.  If it already exists,
    03383     // something is wrong.
    03384     //
    03385     if (Disposition != REG_CREATED_NEW_KEY) {
    03386         CMLOG(CML_BUGCHECK, CMS_INIT) {
    03387         //  KdPrint(("CM: CmpCloneControlSet: Clone tree already exists!\n"));
    03388         }
    03389
    03390         //
    03391         // WARNNOTE:
    03392         //      If somebody somehow managed to create a key in our way,
    03393         //      they'll thwart last known good.  Tough luck.
    03394         //      Claim it worked and go on.
    03395         //
    03396         Status = STATUS_SUCCESS;
    03397         goto Exit;
    03398     }
    03399
    03400     Status = ObReferenceObjectByHandle(CurrentHandle,
    03401                                        KEY_READ,
    03402                                        CmpKeyObjectType,
    03403                                        KernelMode,
    03404                                        (PVOID *)(&CurrentKey),
    03405                                        NULL);
    03406     if (!NT_SUCCESS(Status)) {
    03407         CMLOG(CML_BUGCHECK, CMS_INIT) {
    03408             KdPrint(("CM: CmpCloneControlSet: couldn't reference CurrentHandle %08lx\n",Status));
    03409         }
    03410         goto Exit;
    03411     }
    03412
    03413     Status = ObReferenceObjectByHandle(CloneHandle,
    03414                                        KEY_WRITE,
    03415                                        CmpKeyObjectType,
    03416                                        KernelMode,
    03417                                        (PVOID *)(&CloneKey),
    03418                                        NULL);
    03419     if (!NT_SUCCESS(Status)) {
    03420         CMLOG(CML_BUGCHECK, CMS_INIT) {
    03421             KdPrint(("CM: CmpCloneControlSet: couldn't reference CurrentHandle %08lx\n",Status));
    03422         }
    03423         ObDereferenceObject((PVOID)CurrentKey);
    03424         goto Exit;
    03425     }
    03426
    03427     CmpLockRegistryExclusive();
    03428
    03429     if (CmpCopyTree(CurrentKey->KeyControlBlock->KeyHive,
    03430                     CurrentKey->KeyControlBlock->KeyCell,
    03431                     CloneKey->KeyControlBlock->KeyHive,
    03432                     CloneKey->KeyControlBlock->KeyCell)) {
    03433         //
    03434         // Set the max subkey name property for the new target key.
    03435         //
    03436         CloneKey->KeyControlBlock->KeyNode->MaxNameLen = CurrentKey->KeyControlBlock->KeyNode->MaxNameLen;
    03437         Status = STATUS_SUCCESS;
    03438     } else {
    03439         CMLOG(CML_BUGCHECK, CMS_INIT) {
    03440             KdPrint(("CM: CmpCloneControlSet: tree copy failed.\n"));
    03441         }
    03442         Status = STATUS_REGISTRY_CORRUPT;
    03443     }
    03444
    03445     CmpUnlockRegistry();
    03446
    03447     ObDereferenceObject((PVOID)CurrentKey);
    03448     ObDereferenceObject((PVOID)CloneKey);
    03449
    03450 Exit:
    03451     NtClose(CurrentHandle);
    03452     NtClose(CloneHandle);
    03453     return(Status);
    03454
    03455 }
    03456
    03457 NTSTATUS
    03458 CmpSaveBootControlSet(USHORT ControlSetNum)
    03459 /*++
    03460
    03461 Routine Description:
    03462
    03463    This routine is responsible for saving the control set
    03464    used to accomplish the latest boot into a different control
    03465    set (presumably so that the different control set may be
    03466    marked as the LKG control set).
    03467
    03468    This routine is called from NtInitializeRegistry when
    03469    a boot is accepted via that routine.
    03470
    03471 Arguments:
    03472
    03473    ControlSetNum - The number of the control set that will
    03474                    be used to save the boot control set.
    03475
    03476 Return Value:
    03477
    03478    NTSTATUS result code from call, among the following:
    03479
    03480       STATUS_SUCCESS - everything worked perfectly
    03481       STATUS_REGISTRY_CORRUPT - could not save the boot control set,
    03482                                 it is likely that the copy or sync
    03483                                 operation used for this save failed
    03484                                 and some part of the boot control
    03485                                 set was not saved.
    03486 --*/
    03487 {
    03488    UNICODE_STRING SavedBoot, Boot;
    03489    HANDLE BootHandle, SavedBootHandle;
    03490    OBJECT_ATTRIBUTES Attributes;
    03491    NTSTATUS Status;
    03492    PCM_KEY_BODY BootKey, SavedBootKey;
    03493    ULONG Disposition;
    03494    PSECURITY_DESCRIPTOR Security;
    03495    ULONG SecurityLength;
    03496    BOOLEAN CopyRet;
    03497    WCHAR Buffer[128];
    03498
    03499    //
    03500    // Figure out where the boot control set is
    03501    //
    03502
    03503 #if CLONE_CONTROL_SET
    03504
    03505    //
    03506    // If we have cloned the control set, then use the clone
    03507    // since it is guaranteed to have an untouched copy of the
    03508    // boot control set
    03509    //
    03510
    03511    RtlInitUnicodeString(&Boot,
    03512                         L"\\Registry\\Machine\\System\\Clone");
    03513
    03514    InitializeObjectAttributes(&Attributes,
    03515                               &Boot,
    03516                               OBJ_CASE_INSENSITIVE,
    03517                               NULL,
    03518                               NULL);
    03519 #else
    03520
    03521    //
    03522    // If we are not using the clone, then just use the
    03523    // current control set.
    03524    //
    03525
    03526    InitializeObjectAttributes(&Attributes,
    03527                               &CmRegistryMachineSystemCurrentControlSet,
    03528                               OBJ_CASE_INSENSITIVE,
    03529                               NULL,
    03530                               NULL);
    03531 #endif
    03532
    03533    //
    03534    // Open the boot control set
    03535    //
    03536
    03537    Status = NtOpenKey(&BootHandle,
    03538                       KEY_READ,
    03539                       &Attributes);
    03540
    03541
    03542    if (!NT_SUCCESS(Status)) return(Status);
    03543
    03544    //
    03545    // We may be saving the boot control set into a brand new
    03546    // tree that we will create. If this is true, then we will
    03547    // need to create the root node of this tree below
    03548    // and give it the right security descriptor. So, we fish
    03549    // the security descriptor out of the root node of the
    03550    // boot control set tree.
    03551    //
    03552
    03553    Status = NtQuerySecurityObject(BootHandle,
    03554                                   DACL_SECURITY_INFORMATION,
    03555                                   NULL,
    03556                                   0,
    03557                                   &SecurityLength);
    03558
    03559
    03560    if (Status==STATUS_BUFFER_TOO_SMALL) {
    03561
    03562       Security=ExAllocatePool(PagedPool,SecurityLength);
    03563
    03564       if (Security!=NULL) {
    03565
    03566          Status = NtQuerySecurityObject(BootHandle,
    03567                                         DACL_SECURITY_INFORMATION,
    03568                                         Security,
    03569                                         SecurityLength,
    03570                                         &SecurityLength);
    03571
    03572
    03573          if (!NT_SUCCESS(Status)) {
    03574             ExFreePool(Security);
    03575             Security=NULL;
    03576          }
    03577       }
    03578
    03579    } else {
    03580       Security=NULL;
    03581    }
    03582
    03583    //
    03584    // Now, create the path of the control set we will be saving to
    03585    //
    03586
    03587    swprintf(Buffer, L"\\Registry\\Machine\\System\\ControlSet%03d", ControlSetNum);
    03588
    03589    RtlInitUnicodeString(&SavedBoot,
    03590                         Buffer);
    03591
    03592    //
    03593    // Open/Create the control set to which we are saving
    03594    //
    03595
    03596    InitializeObjectAttributes(&Attributes,
    03597                               &SavedBoot,
    03598                               OBJ_CASE_INSENSITIVE,
    03599                               NULL,
    03600                               Security);
    03601
    03602    Status = NtCreateKey(&SavedBootHandle,
    03603                         KEY_READ | KEY_WRITE,
    03604                         &Attributes,
    03605                         0,
    03606                         NULL,
    03607                         REG_OPTION_NON_VOLATILE,
    03608                         &Disposition);
    03609
    03610
    03611    if (Security) ExFreePool(Security);
    03612
    03613    if (!NT_SUCCESS(Status)) {
    03614       NtClose(BootHandle);
    03615       return(Status);
    03616    }
    03617
    03618    //
    03619    // Get the key objects for out two controls
    03620    //
    03621
    03622    Status = ObReferenceObjectByHandle(BootHandle,
    03623                                       KEY_READ,
    03624                                       CmpKeyObjectType,
    03625                                       KernelMode,
    03626                                       (PVOID *)(&BootKey),
    03627                                       NULL);
    03628
    03629    if (!NT_SUCCESS(Status)) goto Exit;
    03630
    03631    Status = ObReferenceObjectByHandle(SavedBootHandle,
    03632                                       KEY_WRITE,
    03633                                       CmpKeyObjectType,
    03634                                       KernelMode,
    03635                                       (PVOID *)(&SavedBootKey),
    03636                                       NULL);
    03637
    03638
    03639    if (!NT_SUCCESS(Status)) {
    03640       ObDereferenceObject((PVOID)BootKey);
    03641       goto Exit;
    03642    }
    03643
    03644    //
    03645    // Lock the registry and do the actual saving
    03646    //
    03647
    03648    CmpLockRegistryExclusive();
    03649
    03650    if (Disposition == REG_CREATED_NEW_KEY) {
    03651
    03652       //
    03653       // If we are saving to a control set that we have just
    03654       // created, it is most efficient to just copy
    03655       // the boot control set tree into the new control set.
    03656       //
    03657
    03658       //
    03659       // N.B. We copy the volatile keys only if we are using
    03660       //      a clone and thus our boot control set tree is
    03661       //      composed only of volatile keys.
    03662       //
    03663
    03664       CopyRet = CmpCopyTreeEx(BootKey->KeyControlBlock->KeyHive,
    03665                               BootKey->KeyControlBlock->KeyCell,
    03666                               SavedBootKey->KeyControlBlock->KeyHive,
    03667                               SavedBootKey->KeyControlBlock->KeyCell,
    03668                               CLONE_CONTROL_SET);
    03669
    03670         //
    03671         // Set the max subkey name property for the new target key.
    03672         //
    03673         SavedBootKey->KeyControlBlock->KeyNode->MaxNameLen = BootKey->KeyControlBlock->KeyNode->MaxNameLen;
    03674    } else {
    03675
    03676       //
    03677       // If we are saving to a control set that already exists
    03678       // then its likely that this control set is nearly identical
    03679       // to the boot control set (control sets don't change much
    03680       // between boots).
    03681       //
    03682       // Furthermore, the control set we are saving to must be old
    03683       // and hence has not been modified at all since it ceased
    03684       // being a current control set.
    03685       //
    03686       // Thus, it is most efficient for us to simply synchronize
    03687       // the target control set with the boot control set.
    03688       //
    03689
    03690       //
    03691       // N.B. We sync the volatile keys only if we are using
    03692       //      a clone for the same reasons as stated above.
    03693       //
    03694
    03695       CopyRet = CmpSyncTrees(BootKey->KeyControlBlock->KeyHive,
    03696                              BootKey->KeyControlBlock->KeyCell,
    03697                              SavedBootKey->KeyControlBlock->KeyHive,
    03698                              SavedBootKey->KeyControlBlock->KeyCell,
    03699                              CLONE_CONTROL_SET);
    03700    }
    03701
    03702    //
    03703    // Check if the Copy/Sync succeeded and adjust our return code
    03704    // accordingly.
    03705    //
    03706
    03707    if (CopyRet) {
    03708       Status = STATUS_SUCCESS;
    03709    } else {
    03710       Status = STATUS_REGISTRY_CORRUPT;
    03711    }
    03712
    03713    //
    03714    // All done. Clean up.
    03715    //
    03716
    03717    CmpUnlockRegistry();
    03718
    03719    ObDereferenceObject((PVOID)BootKey);
    03720    ObDereferenceObject((PVOID)SavedBootKey);
    03721
    03722 Exit:
    03723
    03724    NtClose(BootHandle);
    03725    NtClose(SavedBootHandle);
    03726
    03727 #if CLONE_CONTROL_SET
    03728
    03729    //
    03730    // If we have been using a clone, then the clone is no longer
    03731    // needed since we have saved its contents into a non-volatile
    03732    // control set. Thus, we can just erase it.
    03733    //
    03734
    03735    if(NT_SUCCESS(Status))
    03736    {
    03737       CmpDeleteCloneTree();
    03738    }
    03739
    03740 #endif
    03741
    03742    return(Status);
    03743
    03744 }
    03745
    03746 NTSTATUS
    03747 CmpDeleteCloneTree()
    03748 /*++
    03749
    03750 Routine Description:
    03751
    03752    Deletes the cloned CurrentControlSet by unloading the CLONE hive.
    03753
    03754 Arguments:
    03755
    03756    NONE.
    03757
    03758 Return Value:
    03759
    03760    NTSTATUS return from NtUnloadKey.
    03761
    03762 --*/
    03763 {
    03764    OBJECT_ATTRIBUTES   Obja;
    03765
    03766    InitializeObjectAttributes(
    03767        &Obja,
    03768        &CmRegistrySystemCloneName,
    03769        OBJ_CASE_INSENSITIVE,
    03770        (HANDLE)NULL,
    03771        NULL);
    03772
    03773    return NtUnloadKey(&Obja);
    03774 }
    03775
    03776
    03777 VOID
    03778 CmBootLastKnownGood(
    03779     ULONG ErrorLevel
    03780     )
    03781
    03782 /*++
    03783
    03784 Routine Description:
    03785
    03786     This function is called to indicate a failure during the boot process.
    03787     The actual result is based on the value of ErrorLevel:
    03788
    03789         IGNORE - Will return, boot should proceed
    03790         NORMAL - Will return, boot should proceed
    03791
    03792         SEVERE - If not booting LastKnownGood, will switch to LastKnownGood
    03793                  and reboot the system.
    03794
    03795                  If already booting LastKnownGood, will return.  Boot should
    03796                  proceed.
    03797
    03798         CRITICAL - If not booting LastKnownGood, will switch to LastKnownGood
    03799                  and reboot the system.
    03800
    03801                  If already booting LastKnownGood, will bugcheck.
    03802
    03803 Arguments:
    03804
    03805     ErrorLevel - Supplies the severity level of the failure
    03806
    03807 Return Value:
    03808
    03809     None.  If it returns, boot should proceed.  May cause the system to
    03810     reboot.
    03811
    03812 --*/
    03813
    03814 {
    03815     ARC_STATUS Status;
    03816
    03817     PAGED_CODE();
    03818
    03819     if (CmFirstTime != TRUE) {
    03820
    03821         //
    03822         // NtInitializeRegistry has been called, so handling
    03823         // driver errors is not a task for ScReg.
    03824         // Treat all errors as Normal
    03825         //
    03826         return;
    03827     }
    03828
    03829     switch (ErrorLevel) {
    03830         case NormalError:
    03831         case IgnoreError:
    03832             break;
    03833
    03834         case SevereError:
    03835             if (CmpIsLastKnownGoodBoot()) {
    03836                 break;
    03837             } else {
    03838                 Status = HalSetEnvironmentVariable("LastKnownGood", "TRUE");
    03839                 if (Status == ESUCCESS) {
    03840                     HalReturnToFirmware(HalRebootRoutine);
    03841                 }
    03842             }
    03843             break;
    03844
    03845         case CriticalError:
    03846             if (CmpIsLastKnownGoodBoot()) {
    03847                 KeBugCheckEx(CRITICAL_SERVICE_FAILED,5,9,0,0);
    03848             } else {
    03849                 Status = HalSetEnvironmentVariable("LastKnownGood", "TRUE");
    03850                 if (Status == ESUCCESS) {
    03851                     HalReturnToFirmware(HalRebootRoutine);
    03852                 } else {
    03853                     KeBugCheckEx(SET_ENV_VAR_FAILED,5,10,0,0);
    03854                 }
    03855             }
    03856             break;
    03857     }
    03858     return;
    03859 }
    03860
    03861
    03862 BOOLEAN
    03863 CmpIsLastKnownGoodBoot(
    03864     VOID
    03865     )
    03866
    03867 /*++
    03868
    03869 Routine Description:
    03870
    03871     Determines whether the current system boot is a LastKnownGood boot or
    03872     not.  It does this by comparing the following two values:
    03873
    03874         \registry\machine\system\select:Current
    03875         \registry\machine\system\select:LastKnownGood
    03876
    03877     If both of these values refer to the same control set, and this control
    03878     set is different from:
    03879
    03880         \registry\machine\system\select:Default
    03881
    03882     we are booting LastKnownGood.
    03883
    03884 Arguments:
    03885
    03886     None.
    03887
    03888 Return Value:
    03889
    03890     TRUE  - Booting LastKnownGood
    03891     FALSE - Not booting LastKnownGood
    03892
    03893 --*/
    03894
    03895 {
    03896     NTSTATUS Status;
    03897     ULONG Default;
    03898     ULONG Current;
    03899     ULONG LKG;
    03900     RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
    03901         {NULL,      RTL_QUERY_REGISTRY_DIRECT,
    03902          L"Current", &Current,
    03903          REG_DWORD, (PVOID)&Current, 0 },
    03904         {NULL,      RTL_QUERY_REGISTRY_DIRECT,
    03905          L"LastKnownGood", &LKG,
    03906          REG_DWORD, (PVOID)&LKG, 0 },
    03907         {NULL,      RTL_QUERY_REGISTRY_DIRECT,
    03908          L"Default", &Default,
    03909          REG_DWORD, (PVOID)&Default, 0 },
    03910         {NULL,      0,
    03911          NULL, NULL,
    03912          REG_NONE, NULL, 0 }
    03913     };
    03914
    03915     PAGED_CODE();
    03916
    03917     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
    03918                                     L"\\Registry\\Machine\\System\\Select",
    03919                                     QueryTable,
    03920                                     NULL,
    03921                                     NULL);
    03922     //
    03923     // If this failed, something is severely wrong.
    03924     //
    03925
    03926     ASSERT(NT_SUCCESS(Status));
    03927     if (!NT_SUCCESS(Status)) {
    03928         CMLOG(CML_MAJOR, CMS_INIT) {
    03929             KdPrint(("CmpIsLastKnownGoodBoot: RtlQueryRegistryValues "));
    03930             KdPrint(("failed, Status %08lx\n", Status));
    03931         }
    03932         return(FALSE);
    03933     }
    03934
    03935     if ((LKG == Current) && (Current != Default)){
    03936         return(TRUE);
    03937     } else {
    03938         return(FALSE);
    03939     }
    03940 }
    03941
    03942
    03943 VOID
    03944 CmShutdownSystem(
    03945     VOID
    03946     )
    03947 /*++
    03948
    03949 Routine Description:
    03950
    03951     Shuts down the registry.
    03952
    03953     Call to CmpWorkerThread, which will call back
    03954     to CmpDoFlushAll();
    03955
    03956 Arguments:
    03957
    03958     NONE
    03959
    03960 Return Value:
    03961
    03962     NONE
    03963
    03964 --*/
    03965 {
    03966     REGISTRY_COMMAND CommandArea;
    03967
    03968     PAGED_CODE();
    03969     CmpLockRegistryExclusive();
    03970
    03971     CommandArea.Command = REG_CMD_SHUTDOWN;
    03972     CmpWorker(&CommandArea);
    03973
    03974     HvShutdownComplete = TRUE;      // Tell HvSyncHive to ignore all
    03975                                     // further requests
    03976
    03977     CmpUnlockRegistry();
    03978     return;
    03979 }
    03980
    03981
    03982 BOOLEAN
    03983 CmpLinkKeyToHive(
    03984     PWSTR   KeyPath,
    03985     PWSTR   HivePath
    03986     )
    03987
    03988 /*++
    03989
    03990 Routine Description:
    03991
    03992     Creates a symbolic link at KeyPath that points to HivePath.
    03993
    03994 Arguments:
    03995
    03996     KeyPath - pointer to unicode string with name of key
    03997               (e.g. L"\\Registry\\Machine\\Security\\SAM")
    03998
    03999     HivePath - pointer to unicode string with name of hive root
    04000                (e.g. L"\\Registry\\Machine\\SAM\\SAM")
    04001
    04002 Return Value:
    04003
    04004     TRUE if links were successfully created, FALSE otherwise
    04005
    04006 --*/
    04007
    04008 {
    04009     UNICODE_STRING KeyName;
    04010     UNICODE_STRING LinkName;
    04011     OBJECT_ATTRIBUTES Attributes;
    04012     HANDLE LinkHandle;
    04013     ULONG Disposition;
    04014     NTSTATUS Status;
    04015
    04016     PAGED_CODE();
    04017
    04018     //
    04019     // Create link for CLONE hive
    04020     //
    04021
    04022     RtlInitUnicodeString(&KeyName, KeyPath);
    04023     InitializeObjectAttributes(&Attributes,
    04024                                &KeyName,
    04025                                OBJ_CASE_INSENSITIVE,
    04026                                NULL,
    04027                                NULL);
    04028     Status = NtCreateKey(&LinkHandle,
    04029                          KEY_CREATE_LINK,
    04030                          &Attributes,
    04031                          0,
    04032                          NULL,
    04033                          REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
    04034                          &Disposition);
    04035     if (!NT_SUCCESS(Status)) {
    04036         CMLOG(CML_BUGCHECK, CMS_INIT) {
    04037             KdPrint(("CM: CmpLinkKeyToHive: couldn't create %S\n", &KeyName));
    04038             KdPrint(("    Status = %08lx\n",Status));
    04039         }
    04040         return(FALSE);
    04041     }
    04042
    04043     //
    04044     // Check to make sure that the key was created, not just opened.  Since
    04045     // this key is always created volatile, it should never be present in
    04046     // the hive when we boot.
    04047     //
    04048     if (Disposition != REG_CREATED_NEW_KEY) {
    04049         CMLOG(CML_BUGCHECK, CMS_INIT) {
    04050             KdPrint(("CM: CmpLinkKeyToHive: %S already exists!\n", &KeyName));
    04051         }
    04052
    04053         NtClose(LinkHandle);
    04054         return(FALSE);
    04055     }
    04056
    04057     RtlInitUnicodeString(&LinkName, HivePath);
    04058     Status = NtSetValueKey(LinkHandle,
    04059                            &CmSymbolicLinkValueName,
    04060                            0,
    04061                            REG_LINK,
    04062                            LinkName.Buffer,
    04063                            LinkName.Length);
    04064     NtClose(LinkHandle);
    04065     if (!NT_SUCCESS(Status)) {
    04066         CMLOG(CML_BUGCHECK, CMS_INIT) {
    04067             KdPrint(("CM: CmpLinkKeyToHive: couldn't create symbolic link for %S\n", HivePath));
    04068         }
    04069         return(FALSE);
    04070     }
    04071
    04072     return(TRUE);
    04073 }
    04074
    04075
    04076 BOOLEAN
    04077 CmpValidateAlternate(
    04078     IN HANDLE FileHandle,
    04079     IN PCMHIVE PrimaryHive
    04080     )
    04081
    04082 /*++
    04083
    04084 Routine Description:
    04085
    04086     Loads an alternate hive (SYSTEM.ALT) and verifies that it is a
    04087     valid hive file.
    04088
    04089 Arguments:
    04090
    04091     FileHandle - Supplies a handle to the hive file.
    04092
    04093     PrimaryHive - Supplies the CMHIVE structure of the primary hive.
    04094
    04095 Return Value:
    04096
    04097     TRUE - Hive is valid.
    04098
    04099     FALSE - Hive is corrupt or in transition.
    04100
    04101 --*/
    04102
    04103 {
    04104     PCMHIVE CmHive;
    04105     BOOLEAN Status;
    04106     NTSTATUS Status2;
    04107
    04108     Status2 = CmpInitializeHive(&CmHive,
    04109                            HINIT_FILE,
    04110                            0,
    04111                            HFILE_TYPE_PRIMARY,
    04112                            NULL,
    04113                            FileHandle,
    04114                            NULL,
    04115                            NULL,
    04116                            NULL,
    04117                            &CmpSystemFileName    // non system ALT will screw up
    04118                            );
    04119     if (!NT_SUCCESS(Status2)) {
    04120         CMLOG(CML_BUGCHECK, CMS_INIT) {
    04121             KdPrint(("CmpValidateSecondary: SYSTEM.ALT is corrupt\n"));
    04122         }
    04123         return(FALSE);
    04124     }
    04125
    04126     //
    04127     // Compare the timestamps in the baseblock.  These must always be
    04128     // equal to ensure that SYSTEM and SYSTEM.ALT are really the same
    04129     // hive.
    04130     //
    04131     if (CmHive->Hive.BaseBlock->TimeStamp.QuadPart !=
    04132         PrimaryHive->Hive.BaseBlock->TimeStamp.QuadPart) {
    04133         CMLOG(CML_BUGCHECK,CMS_INIT) {
    04134             KdPrint(("CmpValidateSecondary: timestamps don't match"));
    04135         }
    04136         Status = FALSE;
    04137     } else {
    04138         Status = TRUE;
    04139     }
    04140
    04141     //
    04142     // Hive is valid, free up everything we allocated.
    04143     //
    04144     RemoveEntryList(&CmHive->HiveList);
    04145     HvFreeHive(&CmHive->Hive);
    04146     ASSERT( CmHive->HiveLock );
    04147     ExFreePool(CmHive->HiveLock);
    04148     CmpFree(CmHive, sizeof(CMHIVE));
    04149     return(Status);
    04150
    04151 }
    04152
    04153
    04154 VOID
    04155 CmpCreatePerfKeys(
    04156     VOID
    04157     )
    04158
    04159 /*++
    04160
    04161 Routine Description:
    04162
    04163     Creates predefined keys for the performance text to support old apps on 1.0a
    04164
    04165 Arguments:
    04166
    04167     None.
    04168
    04169 Return Value:
    04170
    04171     None.
    04172
    04173 --*/
    04174
    04175 {
    04176     HANDLE Perflib;
    04177     NTSTATUS Status;
    04178     WCHAR LanguageId[4];
    04179     OBJECT_ATTRIBUTES Attributes;
    04180     UNICODE_STRING String;
    04181     USHORT Language;
    04182     LONG i;
    04183     WCHAR c;
    04184     extern PWCHAR CmpRegistryPerflibString;
    04185
    04186     RtlInitUnicodeString(&String, CmpRegistryPerflibString);
    04187
    04188     InitializeObjectAttributes(&Attributes,
    04189                                &String,
    04190                                OBJ_CASE_INSENSITIVE,
    04191                                NULL,
    04192                                NULL);
    04193     Status = NtOpenKey(&Perflib,
    04194                        KEY_WRITE,
    04195                        &Attributes);
    04196     if (!NT_SUCCESS(Status)) {
    04197         return;
    04198     }
    04199
    04200
    04201     //
    04202     // Always create the predefined keys for the english language
    04203     //
    04204     CmpCreatePredefined(Perflib,
    04205                         L"009",
    04206                         HKEY_PERFORMANCE_TEXT);
    04207
    04208     //
    04209     // If the default language is not english, create a predefined key for
    04210     // that, too.
    04211     //
    04212     if (PsDefaultSystemLocaleId != 0x00000409) {
    04213         Language = LANGIDFROMLCID(PsDefaultSystemLocaleId) & 0xff;
    04214         LanguageId[3] = L'\0';
    04215         for (i=2;i>=0;i--) {
    04216             c = Language % 16;
    04217             if (c>9) {
    04218                 LanguageId[i]= c+L'A'-10;
    04219             } else {
    04220                 LanguageId[i]= c+L'0';
    04221             }
    04222             Language = Language >> 4;
    04223         }
    04224         CmpCreatePredefined(Perflib,
    04225                             LanguageId,
    04226                             HKEY_PERFORMANCE_NLSTEXT);
    04227     }
    04228
    04229
    04230 }
    04231
    04232
    04233 VOID
    04234 CmpCreatePredefined(
    04235     IN HANDLE Root,
    04236     IN PWSTR KeyName,
    04237     IN HANDLE PredefinedHandle
    04238     )
    04239
    04240 /*++
    04241
    04242 Routine Description:
    04243
    04244     Creates a special key that will always return the given predefined handle
    04245     instead of a real handle.
    04246
    04247 Arguments:
    04248
    04249     Root - supplies the handle the keyname is relative to
    04250
    04251     KeyName - supplies the name of the key.
    04252
    04253     PredefinedHandle - supplies the predefined handle to be returned when this
    04254         key is opened.
    04255
    04256 Return Value:
    04257
    04258     None.
    04259
    04260 --*/
    04261
    04262 {
    04263     OBJECT_ATTRIBUTES ObjectAttributes;
    04264     CM_PARSE_CONTEXT ParseContext;
    04265     NTSTATUS Status;
    04266     UNICODE_STRING Name;
    04267     HANDLE Handle;
    04268
    04269     ParseContext.Class.Length = 0;
    04270     ParseContext.Class.Buffer = NULL;
    04271
    04272     ParseContext.TitleIndex = 0;
    04273     ParseContext.CreateOptions = REG_OPTION_VOLATILE | REG_OPTION_PREDEF_HANDLE;
    04274     ParseContext.Disposition = 0;
    04275     ParseContext.CreateLink = FALSE;
    04276     ParseContext.PredefinedHandle = PredefinedHandle;
    04277
    04278     RtlInitUnicodeString(&Name, KeyName);
    04279     InitializeObjectAttributes(&ObjectAttributes,
    04280                                &Name,
    04281                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
    04282                                Root,
    04283                                NULL);
    04284
    04285     Status = ObOpenObjectByName(&ObjectAttributes,
    04286                                 CmpKeyObjectType,
    04287                                 KernelMode,
    04288                                 NULL,
    04289                                 KEY_READ,
    04290                                 (PVOID)&ParseContext,
    04291                                 &Handle);
    04292     ASSERT(NT_SUCCESS(Status));
    04293
    04294     ZwClose(Handle);
    04295
    04296 }
    04297
    04298
    04299