/*++

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    cmboot.c

Abstract:

    This provides routines for determining driver load lists from the
    registry.  The relevant drivers are extracted from the registry,
    sorted by groups, and then dependencies are resolved.

    This module is used by IoInitSystem for determining
    the drivers to be loaded in Phase 1 Initialization
    (CmGetSystemDriverList)

--*/

#include "cmp.h"
#include <profiles.h>

#define LOAD_LAST 0xffffffff
#define LOAD_NEXT_TO_LAST (LOAD_LAST-1)

//
// Private function prototypes.
//
BOOLEAN
CmpAddDriverToList(
    IN PHHIVE Hive,
    IN HCELL_INDEX DriverCell,
    IN HCELL_INDEX GroupOrderCell,
    IN PUNICODE_STRING RegistryPath,
    IN PLIST_ENTRY BootDriverListHead
    );

BOOLEAN
CmpDoSort(
    IN PLIST_ENTRY DriverListHead,
    IN PUNICODE_STRING OrderList
    );

ULONG
CmpFindTagIndex(
    IN PHHIVE Hive,
    IN HCELL_INDEX TagCell,
    IN HCELL_INDEX GroupOrderCell,
    IN PUNICODE_STRING GroupName
    );

BOOLEAN
CmpIsLoadType(
    IN PHHIVE Hive,
    IN HCELL_INDEX Cell,
    IN SERVICE_LOAD_TYPE LoadType
    );

BOOLEAN
CmpOrderGroup(
    IN PBOOT_DRIVER_NODE GroupStart,
    IN PBOOT_DRIVER_NODE GroupEnd
    );

VOID
BlPrint(
    PCHAR cp,
    ...
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpFindNLSData)
#pragma alloc_text(INIT,CmpFindDrivers)
#pragma alloc_text(INIT,CmpIsLoadType)
#pragma alloc_text(INIT,CmpAddDriverToList)
#pragma alloc_text(INIT,CmpSortDriverList)
#pragma alloc_text(INIT,CmpDoSort)
#pragma alloc_text(INIT,CmpResolveDriverDependencies)
#pragma alloc_text(INIT,CmpSetCurrentProfile)
#pragma alloc_text(INIT,CmpOrderGroup)
#pragma alloc_text(PAGE,CmpFindControlSet)
#pragma alloc_text(INIT,CmpFindTagIndex)
#pragma alloc_text(INIT,CmpFindProfileOption)
#pragma alloc_text(INIT,CmpValidateSelect)
#ifdef _WANT_MACHINE_IDENTIFICATION
#pragma alloc_text(INIT,CmpGetBiosDateFromRegistry)
#endif
#endif


BOOLEAN
CmpFindNLSData(
    IN PHHIVE Hive,
    IN HCELL_INDEX ControlSet,
    OUT PUNICODE_STRING AnsiFilename,
    OUT PUNICODE_STRING OemFilename,
    OUT PUNICODE_STRING CaseTableFilename,
    OUT PUNICODE_STRING OemHalFont
    )

/*++

Routine Description:

    Traverses a particular control set and determines the filenames for
    the NLS data files that need to be loaded.

Arguments:

    Hive - Supplies the hive control structure for the SYSTEM hive.

    ControlSet - Supplies the HCELL_INDEX of the root of the control set.

    AnsiFileName - Returns the name of the Ansi codepage file (c_1252.nls)

    OemFileName -  Returns the name of the OEM codepage file  (c_437.nls)

    CaseTableFileName - Returns the name of the Unicode upper/lowercase
            table for the language (l_intl.nls)

    OemHalfont - Returns the name of the font file to be used by the HAL.

Return Value:

    TRUE - filenames successfully determined

    FALSE - hive is corrupt

--*/

{
    UNICODE_STRING Name;
    HCELL_INDEX Control;
    HCELL_INDEX Nls;
    HCELL_INDEX CodePage;
    HCELL_INDEX Language;
    HCELL_INDEX ValueCell;
    PCM_KEY_VALUE Value;
    ULONG realsize;
    PCM_KEY_NODE Node;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );
    //
    // Find CONTROL node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,ControlSet);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"Control");
    Control = CmpFindSubKeyByName(Hive,
                                 Node,
                                 &Name);
    if (Control == HCELL_NIL) {
        return(FALSE);
    }

    //
    // Find NLS node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,Control);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"NLS");
    Nls = CmpFindSubKeyByName(Hive,
                             Node,
                             &Name);
    if (Nls == HCELL_NIL) {
        return(FALSE);
    }

    //
    // Find CodePage node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,Nls);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"CodePage");
    CodePage = CmpFindSubKeyByName(Hive,
                                  Node,
                                  &Name);
    if (CodePage == HCELL_NIL) {
        return(FALSE);
    }

    //
    // Find ACP value
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,CodePage);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"ACP");
    ValueCell = CmpFindValueByName(Hive,
                                   Node,
                                   &Name);
    if (ValueCell == HCELL_NIL) {
        return(FALSE);
    }

    Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    Name.Buffer = (PWSTR)CmpValueToData(Hive,Value,&realsize);
    if( Name.Buffer == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }
    Name.MaximumLength=(USHORT)realsize;
    Name.Length = 0;
    while ((Name.Length<Name.MaximumLength) &&
           (Name.Buffer[Name.Length/sizeof(WCHAR)] != UNICODE_NULL)) {
        Name.Length += sizeof(WCHAR);
    }

    //
    // Find ACP filename
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,CodePage);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    ValueCell = CmpFindValueByName(Hive,
                                   Node,
                                   &Name);
    if (ValueCell == HCELL_NIL) {
        return(FALSE);
    }

    Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    AnsiFilename->Buffer = (PWSTR)CmpValueToData(Hive,Value,&realsize);
    if( AnsiFilename->Buffer == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }
    AnsiFilename->Length = AnsiFilename->MaximumLength = (USHORT)realsize;

    //
    // Find OEMCP node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,CodePage);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"OEMCP");
    ValueCell = CmpFindValueByName(Hive,
                                   Node,
                                   &Name);
    if (ValueCell == HCELL_NIL) {
        return(FALSE);
    }

    Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    Name.Buffer = (PWSTR)CmpValueToData(Hive,Value,&realsize);
    if( Name.Buffer == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }
    Name.MaximumLength = (USHORT)realsize;
    Name.Length = 0;
    while ((Name.Length<Name.MaximumLength) &&
           (Name.Buffer[Name.Length/sizeof(WCHAR)] != UNICODE_NULL)) {
        Name.Length += sizeof(WCHAR);
    }

    //
    // Find OEMCP filename
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,CodePage);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    ValueCell = CmpFindValueByName(Hive,
                                   Node,
                                   &Name);
    if (ValueCell == HCELL_NIL) {
        return(FALSE);
    }

    Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    OemFilename->Buffer = (PWSTR)CmpValueToData(Hive, Value,&realsize);
    if( OemFilename->Buffer == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }
    OemFilename->Length = OemFilename->MaximumLength = (USHORT)realsize;

    //
    // Find Language node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,Nls);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"Language");
    Language = CmpFindSubKeyByName(Hive,
                                   Node,
                                   &Name);
    if (Language == HCELL_NIL) {
        return(FALSE);
    }

    //
    // Find Default value
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,Language);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"Default");
    ValueCell = CmpFindValueByName(Hive,
                                   Node,
                                   &Name);
    if (ValueCell == HCELL_NIL) {
            return(FALSE);
    }

    Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    Name.Buffer = (PWSTR)CmpValueToData(Hive, Value,&realsize);
    if( Name.Buffer == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }
    Name.MaximumLength = (USHORT)realsize;
    Name.Length = 0;

    while ((Name.Length<Name.MaximumLength) &&
           (Name.Buffer[Name.Length/sizeof(WCHAR)] != UNICODE_NULL)) {
        Name.Length+=sizeof(WCHAR);
    }

    //
    // Find default filename
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,Language);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    ValueCell = CmpFindValueByName(Hive,
                                   Node,
                                   &Name);
    if (ValueCell == HCELL_NIL) {
        return(FALSE);
    }

    Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    CaseTableFilename->Buffer = (PWSTR)CmpValueToData(Hive, Value,&realsize);
    if( CaseTableFilename->Buffer == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }
    CaseTableFilename->Length = CaseTableFilename->MaximumLength = (USHORT)realsize;

    //
    // Find OEMHAL filename
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,CodePage);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"OEMHAL");
    ValueCell = CmpFindValueByName(Hive,
                                   Node,
                                   &Name);
    if (ValueCell == HCELL_NIL) {
#ifdef i386
        OemHalFont->Buffer = NULL;
        OemHalFont->Length = 0;
        OemHalFont->MaximumLength = 0;
        return TRUE;
#else
        return(FALSE);
#endif
    }

    Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    OemHalFont->Buffer = (PWSTR)CmpValueToData(Hive,Value,&realsize);
    if( OemHalFont->Buffer == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }
    OemHalFont->Length = (USHORT)realsize;
    OemHalFont->MaximumLength = (USHORT)realsize;

    return(TRUE);
}


BOOLEAN
CmpFindDrivers(
    IN PHHIVE Hive,
    IN HCELL_INDEX ControlSet,
    IN SERVICE_LOAD_TYPE LoadType,
    IN PWSTR BootFileSystem OPTIONAL,
    IN PLIST_ENTRY DriverListHead
    )

/*++

Routine Description:

    Traverses a particular control set and creates a list of boot drivers
    to be loaded.  This list is unordered, but complete.

Arguments:

    Hive - Supplies the hive control structure for the SYSTEM hive.

    ControlSet - Supplies the HCELL_INDEX of the root of the control set.

    LoadType - Supplies the type of drivers to be loaded (BootLoad,
            SystemLoad, AutoLoad, etc)

    BootFileSystem - If present, supplies the base name of the boot
        filesystem, which is explicitly added to the driver list.

    DriverListHead - Supplies a pointer to the head of the (empty) list
            of boot drivers to load.

Return Value:

    TRUE - List successfully created.

    FALSE - Hive is corrupt.

--*/

{
    HCELL_INDEX Services;
    HCELL_INDEX Control;
    HCELL_INDEX GroupOrder;
    HCELL_INDEX DriverCell;
    UNICODE_STRING Name;
    int i;
    UNICODE_STRING UnicodeString;
    UNICODE_STRING BasePath;
    WCHAR BaseBuffer[128];
    PBOOT_DRIVER_NODE BootFileSystemNode;
    PCM_KEY_NODE ControlNode;
    PCM_KEY_NODE ServicesNode;
    PCM_KEY_NODE Node;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );
    //
    // Find SERVICES node.
    //
    ControlNode = (PCM_KEY_NODE)HvGetCell(Hive,ControlSet);
    if( ControlNode == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"Services");
    Services = CmpFindSubKeyByName(Hive,
                                   ControlNode,
                                   &Name);
    if (Services == HCELL_NIL) {
        return(FALSE);
    }
    ServicesNode = (PCM_KEY_NODE)HvGetCell(Hive,Services);
    if( ServicesNode == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }

    //
    // Find CONTROL node.
    //
    RtlInitUnicodeString(&Name, L"Control");
    Control = CmpFindSubKeyByName(Hive,
                                  ControlNode,
                                  &Name);
    if (Control == HCELL_NIL) {
        return(FALSE);
    }

    //
    // Find GroupOrderList node.
    //
    RtlInitUnicodeString(&Name, L"GroupOrderList");
    Node = (PCM_KEY_NODE)HvGetCell(Hive,Control);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    GroupOrder = CmpFindSubKeyByName(Hive,
                                     Node,
                                     &Name);
    if (GroupOrder == HCELL_NIL) {
        return(FALSE);
    }

    BasePath.Length = 0;
    BasePath.MaximumLength = sizeof(BaseBuffer);
    BasePath.Buffer = BaseBuffer;
    RtlAppendUnicodeToString(&BasePath, L"\\Registry\\Machine\\System\\");
    RtlAppendUnicodeToString(&BasePath, L"CurrentControlSet\\Services\\");

    i=0;
    do {
        DriverCell = CmpFindSubKeyByNumber(Hive,ServicesNode,i++);
        if (DriverCell != HCELL_NIL) {
            if (CmpIsLoadType(Hive, DriverCell, LoadType)) {
                CmpAddDriverToList(Hive,
                                   DriverCell,
                                   GroupOrder,
                                   &BasePath,
                                   DriverListHead);

            }
        }
    } while ( DriverCell != HCELL_NIL );

    if (ARGUMENT_PRESENT(BootFileSystem)) {
        //
        // Add boot filesystem to boot driver list
        //

        RtlInitUnicodeString(&UnicodeString, BootFileSystem);
        DriverCell = CmpFindSubKeyByName(Hive,
                                         ServicesNode,
                                         &UnicodeString);
        if (DriverCell != HCELL_NIL) {
            CmpAddDriverToList(Hive,
                               DriverCell,
                               GroupOrder,
                               &BasePath,
                               DriverListHead);

            //
            // mark the Boot Filesystem critical
            //
            BootFileSystemNode = CONTAINING_RECORD(DriverListHead->Flink,
                                                   BOOT_DRIVER_NODE,
                                                   ListEntry.Link);
            BootFileSystemNode->ErrorControl = SERVICE_ERROR_CRITICAL;
        }
    }
    return(TRUE);

}


BOOLEAN
CmpIsLoadType(
    IN PHHIVE Hive,
    IN HCELL_INDEX Cell,
    IN SERVICE_LOAD_TYPE LoadType
    )

/*++

Routine Description:

    Determines if the driver is of a specified LoadType, based on its
    node values.

Arguments:

    Hive - Supplies a pointer to the hive control structure for the system
           hive.

    Cell - Supplies the cell index of the driver's node in the system hive.

    LoadType - Supplies the type of drivers to be loaded (BootLoad,
            SystemLoad, AutoLoad, etc)

Return Value:

    TRUE - Driver is the correct type and should be loaded.

    FALSE - Driver is not the correct type and should not be loaded.

--*/

{
    HCELL_INDEX ValueCell;
    PLONG Data;
    UNICODE_STRING Name;
    PCM_KEY_VALUE Value;
    ULONG realsize;
    PCM_KEY_NODE Node;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );
    //
    // Must have a Start=BootLoad value in order to be a boot driver, so
    // look for that first.
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,Cell);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"Start");
    ValueCell = CmpFindValueByName(Hive,
                                   Node,
                                   &Name);
    if (ValueCell == HCELL_NIL) {
        return(FALSE);
    }

    Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }

    Data = (PLONG)CmpValueToData(Hive,Value,&realsize);
    if( Data == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }

    if (*Data != LoadType) {
        return(FALSE);
    }

    return(TRUE);
}


BOOLEAN
CmpAddDriverToList(
    IN PHHIVE Hive,
    IN HCELL_INDEX DriverCell,
    IN HCELL_INDEX GroupOrderCell,
    IN PUNICODE_STRING RegistryPath,
    IN PLIST_ENTRY BootDriverListHead
    )

/*++

Routine Description:

    This routine allocates a list entry node for a particular driver.
    It initializes it with the registry path, filename, group name, and
    dependency list.  Finally, it inserts the new node into the boot
    driver list.

    Note that this routine allocates memory by calling the Hive's
    memory allocation procedure.

Arguments:

    Hive - Supplies a pointer to the hive control structure

    DriverCell - Supplies the HCELL_INDEX of the driver's node in the hive.

    GroupOrderCell - Supplies the HCELL_INDEX of the GroupOrderList key.
        ( \Registry\Machine\System\CurrentControlSet\Control\GroupOrderList )

    RegistryPath - Supplies the full registry path to the SERVICES node
            of the current control set.

    BootDriverListHead - Supplies the head of the boot driver list

Return Value:

    TRUE - Driver successfully added to boot driver list.

    FALSE - Could not add driver to boot driver list.

--*/

{
    PCM_KEY_NODE            Driver;
    USHORT                  DriverNameLength;
    PCM_KEY_VALUE           Value;
    PBOOT_DRIVER_NODE       DriverNode;
    PBOOT_DRIVER_LIST_ENTRY DriverEntry;
    HCELL_INDEX             ValueCell;
    HCELL_INDEX             Tag;
    UNICODE_STRING          UnicodeString;
    PUNICODE_STRING         FileName;
    ULONG                   Length;
    ULONG                   realsize;
    PULONG                  TempULong;
    PWSTR                   TempBuffer;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );

    Driver = (PCM_KEY_NODE)HvGetCell(Hive, DriverCell);
    if( Driver == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    DriverNode = (Hive->Allocate)(sizeof(BOOT_DRIVER_NODE),FALSE,CM_FIND_LEAK_TAG1);
    if (DriverNode == NULL) {
        return(FALSE);
    }
    DriverEntry = &DriverNode->ListEntry;

    DriverEntry->RegistryPath.Buffer = NULL;
    DriverEntry->FilePath.Buffer = NULL;

    if (Driver->Flags & KEY_COMP_NAME) {
        DriverNode->Name.Length = CmpCompressedNameSize(Driver->Name,Driver->NameLength);
        DriverNode->Name.Buffer = (Hive->Allocate)(DriverNode->Name.Length, FALSE,CM_FIND_LEAK_TAG2);
        if (DriverNode->Name.Buffer == NULL) {
            return(FALSE);
        }
        CmpCopyCompressedName(DriverNode->Name.Buffer,
                              DriverNode->Name.Length,
                              Driver->Name,
                              Driver->NameLength);

    } else {
        DriverNode->Name.Length = Driver->NameLength;
        DriverNode->Name.Buffer = (Hive->Allocate)(DriverNode->Name.Length, FALSE,CM_FIND_LEAK_TAG2);
        if (DriverNode->Name.Buffer == NULL) {
            return(FALSE);
        }
        RtlCopyMemory((PVOID)(DriverNode->Name.Buffer), (PVOID)(Driver->Name), Driver->NameLength);
    }
    DriverNode->Name.MaximumLength = DriverNode->Name.Length;
    DriverNameLength = DriverNode->Name.Length;

    //
    // Check for ImagePath value, which will override the default name
    // if it is present.
    //
    RtlInitUnicodeString(&UnicodeString, L"ImagePath");
    ValueCell = CmpFindValueByName(Hive,
                                   Driver,
                                   &UnicodeString);
    if (ValueCell == HCELL_NIL) {

        //
        // No ImagePath, so generate default filename.
        // Build up Unicode filename  ("system32\drivers\<nodename>.sys");
        //

        Length = sizeof(L"System32\\Drivers\\") +
                 DriverNameLength  +
                 sizeof(L".sys");

        FileName = &DriverEntry->FilePath;
        FileName->Length = 0;
        FileName->MaximumLength = (USHORT)Length;
        FileName->Buffer = (PWSTR)(Hive->Allocate)(Length, FALSE,CM_FIND_LEAK_TAG3);
        if (FileName->Buffer == NULL) {
            return(FALSE);
        }
        if (!NT_SUCCESS(RtlAppendUnicodeToString(FileName, L"System32\\"))) {
            return(FALSE);
        }
        if (!NT_SUCCESS(RtlAppendUnicodeToString(FileName, L"Drivers\\"))) {
            return(FALSE);
        }
        if (!NT_SUCCESS(
                RtlAppendUnicodeStringToString(FileName,
                                               &DriverNode->Name))) {
            return(FALSE);
        }
        if (!NT_SUCCESS(RtlAppendUnicodeToString(FileName, L".sys"))) {
            return(FALSE);
        }

    } else {
        Value = (PCM_KEY_VALUE)HvGetCell(Hive,ValueCell);
        if( Value == NULL ) {
            //
            // we couldn't map a view for the bin containing this cell
            //

            return FALSE;
        }
        FileName = &DriverEntry->FilePath;
        TempBuffer = (PWSTR)CmpValueToData(Hive,Value,&realsize);
        FileName->Buffer = (PWSTR)(Hive->Allocate)(realsize, FALSE,CM_FIND_LEAK_TAG3);
        if( (FileName->Buffer == NULL) || (TempBuffer == NULL) ) {
            //
            // HvGetCell inside CmpValueToData failed; bail out safely
            //
            return FALSE;
        }
        RtlCopyMemory((PVOID)(FileName->Buffer), (PVOID)(TempBuffer), realsize);
        FileName->MaximumLength = FileName->Length = (USHORT)realsize;
    }

    FileName = &DriverEntry->RegistryPath;
    FileName->Length = 0;
    FileName->MaximumLength = RegistryPath->Length + DriverNameLength;
    FileName->Buffer = (Hive->Allocate)(FileName->MaximumLength,FALSE,CM_FIND_LEAK_TAG4);
    if (FileName->Buffer == NULL) {
        return(FALSE);
    }
    RtlAppendUnicodeStringToString(FileName, RegistryPath);
    RtlAppendUnicodeStringToString(FileName, &DriverNode->Name);

    InsertHeadList(BootDriverListHead, &DriverEntry->Link);

    //
    // Find "ErrorControl" value
    //

    RtlInitUnicodeString(&UnicodeString, L"ErrorControl");
    ValueCell = CmpFindValueByName(Hive,
                                   Driver,
                                   &UnicodeString);
    if (ValueCell == HCELL_NIL) {
        DriverNode->ErrorControl = NormalError;
    } else {
        Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
        if( Value == NULL ) {
            //
            // we couldn't map a view for the bin containing this cell
            //

            return FALSE;
        }

        TempULong = (PULONG)CmpValueToData(Hive,Value,&realsize);
        if( TempULong == NULL ) {
            //
            // HvGetCell inside CmpValueToData failed; bail out safely
            //
            return FALSE;
        }
        DriverNode->ErrorControl = *TempULong;
    }

    //
    // Find "Group" value
    //
    RtlInitUnicodeString(&UnicodeString, L"group");
    ValueCell = CmpFindValueByName(Hive,
                                   Driver,
                                   &UnicodeString);
    if (ValueCell == HCELL_NIL) {
        DriverNode->Group.Length = 0;
        DriverNode->Group.MaximumLength = 0;
        DriverNode->Group.Buffer = NULL;
    } else {
        Value = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell);
        if( Value == NULL ) {
            //
            // we couldn't map a view for the bin containing this cell
            //

            return FALSE;
        }

        DriverNode->Group.Buffer = (PWSTR)CmpValueToData(Hive,Value,&realsize);
        if( DriverNode->Group.Buffer == NULL ) {
            //
            // HvGetCell inside CmpValueToData failed; bail out safely
            //
            return FALSE;
        }
        DriverNode->Group.Length = (USHORT)realsize - sizeof(WCHAR);
        DriverNode->Group.MaximumLength = (USHORT)DriverNode->Group.Length;
    }

    //
    // Calculate the tag value for the driver.  If the driver has no tag,
    // this defaults to 0xffffffff, so the driver is loaded last in the
    // group.
    //
    RtlInitUnicodeString(&UnicodeString, L"Tag");
    Tag = CmpFindValueByName(Hive,
                             Driver,
                             &UnicodeString);
    if (Tag == HCELL_NIL) {
        DriverNode->Tag = LOAD_LAST;
    } else {
        //
        // Now we have to find this tag in the tag list for the group.
        // If the tag is not in the tag list, then it defaults to 0xfffffffe,
        // so it is loaded after all the drivers in the tag list, but before
        // all the drivers without tags at all.
        //

        DriverNode->Tag = CmpFindTagIndex(Hive,
                                          Tag,
                                          GroupOrderCell,
                                          &DriverNode->Group);
    }

    return(TRUE);

}


BOOLEAN
CmpSortDriverList(
    IN PHHIVE Hive,
    IN HCELL_INDEX ControlSet,
    IN PLIST_ENTRY DriverListHead
    )

/*++

Routine Description:

    Sorts the list of boot drivers by their groups based on the group
    ordering in <control_set>\CONTROL\SERVICE_GROUP_ORDER:list

    Does NOT do dependency ordering.

Arguments:

    Hive - Supplies the hive control structure for the SYSTEM hive.

    ControlSet - Supplies the HCELL_INDEX of the root of the control set.

    DriverListHead - Supplies a pointer to the head of the list of
            boot drivers to be sorted.

Return Value:

    TRUE - List successfully sorted

    FALSE - List is inconsistent and could not be sorted.

--*/

{
    HCELL_INDEX Controls;
    HCELL_INDEX GroupOrder;
    HCELL_INDEX ListCell;
    UNICODE_STRING Name;
    UNICODE_STRING DependList;
    PCM_KEY_VALUE ListNode;
    ULONG realsize;
    PCM_KEY_NODE Node;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );
    //
    // Find "CONTROL" node.
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,ControlSet);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"Control");
    Controls = CmpFindSubKeyByName(Hive,
                                   Node,
                                   &Name);
    if (Controls == HCELL_NIL) {
        return(FALSE);
    }

    //
    // Find "SERVICE_GROUP_ORDER" subkey
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,Controls);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"ServiceGroupOrder");
    GroupOrder = CmpFindSubKeyByName(Hive,
                                     Node,
                                     &Name);
    if (GroupOrder == HCELL_NIL) {
        return(FALSE);
    }

    //
    // Find "list" value
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive,GroupOrder);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"list");
    ListCell = CmpFindValueByName(Hive,
                                  Node,
                                  &Name);
    if (ListCell == HCELL_NIL) {
        return(FALSE);
    }
    ListNode = (PCM_KEY_VALUE)HvGetCell(Hive, ListCell);
    if( ListNode == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    if (ListNode->Type != REG_MULTI_SZ) {
        return(FALSE);
    }

    DependList.Buffer = (PWSTR)CmpValueToData(Hive,ListNode,&realsize);
    if( DependList.Buffer == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return FALSE;
    }
    DependList.Length = DependList.MaximumLength = (USHORT)realsize - sizeof(WCHAR);

    //
    // Dependency list is now pointed to by DependList->Buffer.  We need
    // to sort the driver entry list.
    //

    return (CmpDoSort(DriverListHead, &DependList));

}

BOOLEAN
CmpDoSort(
    IN PLIST_ENTRY DriverListHead,
    IN PUNICODE_STRING OrderList
    )

/*++

Routine Description:

    Sorts the boot driver list based on the order list

    Start with the last entry in the group order list and work towards
    the beginning.  For each group entry, move all driver entries that
    are members of the group to the front of the list.  Driver entries
    with no groups, or with a group that does not match any in the
    group list will be shoved to the end of the list.

Arguments:

    DriverListHead - Supplies a pointer to the head of the list of
            boot drivers to be sorted.

    OrderList - Supplies pointer to the order list

Return Value:

    TRUE - List successfully ordered

    FALSE - List is inconsistent and could not be ordered.

--*/

{
    PWSTR Current;
    PWSTR End = NULL;
    PLIST_ENTRY Next;
    PBOOT_DRIVER_NODE CurrentNode;
    UNICODE_STRING CurrentGroup;


    Current = (PWSTR) ((PUCHAR)(OrderList->Buffer)+OrderList->Length);

    while (Current > OrderList->Buffer) {
        do {
            if (*Current == UNICODE_NULL) {
                End = Current;
            }
            --Current;
        } while ((*(Current-1) != UNICODE_NULL) &&
                 ( Current != OrderList->Buffer));

        ASSERT (End != NULL);
        //
        // Current now points to the beginning of the NULL-terminated
        // Unicode string.
        // End now points to the end of the string
        //
        CurrentGroup.Length = (USHORT) ((PCHAR)End - (PCHAR)Current);
        CurrentGroup.MaximumLength = CurrentGroup.Length;
        CurrentGroup.Buffer = Current;
        Next = DriverListHead->Flink;
        while (Next != DriverListHead) {
            CurrentNode = CONTAINING_RECORD(Next,
                                            BOOT_DRIVER_NODE,
                                            ListEntry.Link);
            Next = CurrentNode->ListEntry.Link.Flink;
            if (CurrentNode->Group.Buffer != NULL) {
                if (RtlEqualUnicodeString(&CurrentGroup, &CurrentNode->Group,TRUE)) {
                    RemoveEntryList(&CurrentNode->ListEntry.Link);
                    InsertHeadList(DriverListHead,
                                   &CurrentNode->ListEntry.Link);
                }
            }
        }
        --Current;

    }

    return(TRUE);

}


BOOLEAN
CmpResolveDriverDependencies(
    IN PLIST_ENTRY DriverListHead
    )

/*++

Routine Description:

    This routine orders driver nodes in a group based on their dependencies
    on one another.  It removes any drivers that have circular dependencies
    from the list.

Arguments:

    DriverListHead - Supplies a pointer to the head of the list of
            boot drivers to be sorted.

Return Value:

    TRUE - Dependencies successfully resolved

    FALSE - Corrupt hive.

--*/

{
    PLIST_ENTRY CurrentEntry;
    PBOOT_DRIVER_NODE GroupStart;
    PBOOT_DRIVER_NODE GroupEnd;
    PBOOT_DRIVER_NODE CurrentNode;

    CurrentEntry = DriverListHead->Flink;

    while (CurrentEntry != DriverListHead) {
        //
        // The list is already ordered by groups.  Find the first and
        // last entry in each group, and order each of these sub-lists
        // based on their dependencies.
        //

        GroupStart = CONTAINING_RECORD(CurrentEntry,
                                       BOOT_DRIVER_NODE,
                                       ListEntry.Link);
        do {
            GroupEnd = CONTAINING_RECORD(CurrentEntry,
                                         BOOT_DRIVER_NODE,
                                         ListEntry.Link);

            CurrentEntry = CurrentEntry->Flink;
            CurrentNode = CONTAINING_RECORD(CurrentEntry,
                                            BOOT_DRIVER_NODE,
                                            ListEntry.Link);

            if (CurrentEntry == DriverListHead) {
                break;
            }

            if (!RtlEqualUnicodeString(&GroupStart->Group,
                                       &CurrentNode->Group,
                                       TRUE)) {
                break;
            }

        } while ( CurrentEntry != DriverListHead );

        //
        // GroupStart now points to the first driver node in the group,
        // and GroupEnd points to the last driver node in the group.
        //
        CmpOrderGroup(GroupStart, GroupEnd);

    }
    return(TRUE);
}


BOOLEAN
CmpOrderGroup(
    IN PBOOT_DRIVER_NODE GroupStart,
    IN PBOOT_DRIVER_NODE GroupEnd
    )

/*++

Routine Description:

    Reorders the nodes in a driver group based on their tag values.

Arguments:

    GroupStart - Supplies the first node in the group.

    GroupEnd - Supplies the last node in the group.

Return Value:

    TRUE - Group successfully reordered

    FALSE - Circular dependencies detected.

--*/

{
    PBOOT_DRIVER_NODE Current;
    PBOOT_DRIVER_NODE Previous;
    PLIST_ENTRY ListEntry;

    if (GroupStart == GroupEnd) {
        return(TRUE);
    }

    Current = GroupStart;

    do {
        //
        // If the driver before the current one has a lower tag, then
        // we do not need to move it.  If not, then remove the driver
        // from the list and scan backwards until we find a driver with
        // a tag that is <= the current tag, or we reach the beginning
        // of the list.
        //
        Previous = Current;
        ListEntry = Current->ListEntry.Link.Flink;
        Current = CONTAINING_RECORD(ListEntry,
                                    BOOT_DRIVER_NODE,
                                    ListEntry.Link);

        if (Previous->Tag > Current->Tag) {
            //
            // Remove the Current driver from the list, and search
            // backwards until we find a tag that is <= the current
            // driver's tag.  Reinsert the current driver there.
            //
            if (Current == GroupEnd) {
                ListEntry = Current->ListEntry.Link.Blink;
                GroupEnd = CONTAINING_RECORD(ListEntry,
                                             BOOT_DRIVER_NODE,
                                             ListEntry.Link);
            }
            RemoveEntryList(&Current->ListEntry.Link);
            while ( (Previous->Tag > Current->Tag) &&
                    (Previous != GroupStart) ) {
                ListEntry = Previous->ListEntry.Link.Blink;
                Previous = CONTAINING_RECORD(ListEntry,
                                             BOOT_DRIVER_NODE,
                                             ListEntry.Link);
            }
            InsertTailList(&Previous->ListEntry.Link,
                           &Current->ListEntry.Link);
            if (Previous == GroupStart) {
                GroupStart = Current;
            }
        }

    } while ( Current != GroupEnd );

    return(TRUE);
}

BOOLEAN
CmpValidateSelect(
     IN PHHIVE SystemHive,
     IN HCELL_INDEX RootCell
     )
/*++

Routine Description:

    This routines parses the SYSTEM hive and "Select" node
    and verifies the following values:

    Current
    Default
    Failed
    LastKnownGood


    If any of these is missing the the loader will put the corrupt
    system hive message

    This routine is to be called by the loader just after it loads the
    system hive. It's purpose is to ensure a uniform and consistent way
    to treat missing values in this area.

Arguments:

    SystemHive - Supplies the hive control structure for the SYSTEM hive.

    RootCell - Supplies the HCELL_INDEX of the root cell of the hive.


Return Value:

    TRUE - all the values are here
    FALSE - some of them are missing

--*/
{
    HCELL_INDEX     Select;
    PCM_KEY_NODE    Node;
    UNICODE_STRING  Name;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( SystemHive->ReleaseCellRoutine == NULL );

    //
    // Find \SYSTEM\SELECT node.
    //
    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,RootCell);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&Name, L"select");
    Select = CmpFindSubKeyByName(SystemHive,
                                Node,
                                &Name);
    if (Select == HCELL_NIL) {
        return FALSE;
    }

    //
    // Find AutoSelect value
    //
    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,Select);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }

    // search for current
    RtlInitUnicodeString(&Name, L"current");
    Select = CmpFindValueByName(SystemHive,
                                Node,
                                &Name);
    if (Select == HCELL_NIL) {
        return FALSE;
    }

    // search for default
    RtlInitUnicodeString(&Name, L"default");
    Select = CmpFindValueByName(SystemHive,
                                Node,
                                &Name);
    if (Select == HCELL_NIL) {
        return FALSE;
    }

    // search for failed
    RtlInitUnicodeString(&Name, L"failed");
    Select = CmpFindValueByName(SystemHive,
                                Node,
                                &Name);
    if (Select == HCELL_NIL) {
        return FALSE;
    }

    // search for LKG
    RtlInitUnicodeString(&Name, L"LastKnownGood");
    Select = CmpFindValueByName(SystemHive,
                                Node,
                                &Name);
    if (Select == HCELL_NIL) {
        return FALSE;
    }

    return TRUE;
}

HCELL_INDEX
CmpFindControlSet(
     IN PHHIVE SystemHive,
     IN HCELL_INDEX RootCell,
     IN PUNICODE_STRING SelectName,
     OUT PBOOLEAN AutoSelect
     )

/*++

Routine Description:

    This routines parses the SYSTEM hive and "Select" node
    to locate the control set to be used for booting.

    Note that this routines also updates the value of Current to reflect
    the control set that was just found.  This is what we want to do
    when this is called during boot.  During I/O initialization, this
    is irrelevant, since we're just changing it to what it already is.

Arguments:

    SystemHive - Supplies the hive control structure for the SYSTEM hive.

    RootCell - Supplies the HCELL_INDEX of the root cell of the hive.

    SelectName - Supplies the name of the Select value to be used in
            determining the control set.  This should be one of "Current"
            "Default" or "LastKnownGood"

    AutoSelect - Returns the value of the AutoSelect value under
            the Select node.

Return Value:

    != HCELL_NIL - Cell Index of the control set to be used for booting.
    == HCELL_NIL - Indicates the hive is corrupt or inconsistent

--*/

{
    HCELL_INDEX     Select;
    HCELL_INDEX     ValueCell;
    HCELL_INDEX     ControlSet;
    HCELL_INDEX     AutoSelectCell;
    NTSTATUS        Status;
    UNICODE_STRING  Name;
    ANSI_STRING     AnsiString;
    PCM_KEY_VALUE   Value;
    PULONG          ControlSetIndex;
    PULONG          CurrentControl;
    CHAR            AsciiBuffer[128];
    WCHAR           UnicodeBuffer[128];
    ULONG           realsize;
    PCM_KEY_NODE    Node;
    PBOOLEAN        TempBoolean;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( SystemHive->ReleaseCellRoutine == NULL );
    //
    // Find \SYSTEM\SELECT node.
    //
    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,RootCell);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }
    RtlInitUnicodeString(&Name, L"select");
    Select = CmpFindSubKeyByName(SystemHive,
                                Node,
                                &Name);
    if (Select == HCELL_NIL) {
        return(HCELL_NIL);
    }

    //
    // Find AutoSelect value
    //
    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,Select);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }
    RtlInitUnicodeString(&Name, L"AutoSelect");
    AutoSelectCell = CmpFindValueByName(SystemHive,
                                        Node,
                                        &Name);
    if (AutoSelectCell == HCELL_NIL) {
        //
        // It's not there, we don't care.  Set autoselect to TRUE
        //
        *AutoSelect = TRUE;
    } else {
        Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell);
        if( Value == NULL ) {
            //
            // we couldn't map a view for the bin containing this cell
            //

            return HCELL_NIL;
        }

        TempBoolean = (PBOOLEAN)(CmpValueToData(SystemHive,Value,&realsize));
        if( TempBoolean == NULL ) {
            //
            // HvGetCell inside CmpValueToData failed; bail out safely
            //
            return HCELL_NIL;
        }

        *AutoSelect = *TempBoolean;
    }

    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,Select);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }
    ValueCell = CmpFindValueByName(SystemHive,
                                   Node,
                                   SelectName);
    if (ValueCell == HCELL_NIL) {
        return(HCELL_NIL);
    }
    Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
    if( Value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }
    if (Value->Type != REG_DWORD) {
        return(HCELL_NIL);
    }

    ControlSetIndex = (PULONG)CmpValueToData(SystemHive, Value,&realsize);
    if( ControlSetIndex == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return HCELL_NIL;
    }

    //
    // Find appropriate control set
    //

    sprintf(AsciiBuffer, "ControlSet%03d", *ControlSetIndex);
    AnsiString.Length = AnsiString.MaximumLength = (USHORT) strlen(&(AsciiBuffer[0]));
    AnsiString.Buffer = AsciiBuffer;
    Name.MaximumLength = 128*sizeof(WCHAR);
    Name.Buffer = UnicodeBuffer;
    Status = RtlAnsiStringToUnicodeString(&Name,
                                          &AnsiString,
                                          FALSE);
    if (!NT_SUCCESS(Status)) {
        return(HCELL_NIL);
    }

    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,RootCell);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }
    ControlSet = CmpFindSubKeyByName(SystemHive,
                                     Node,
                                     &Name);
    if (ControlSet == HCELL_NIL) {
        return(HCELL_NIL);
    }

    //
    // Control set was successfully found, so update the value in "Current"
    // to reflect the control set we are going to use.
    //
    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,Select);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }
    RtlInitUnicodeString(&Name, L"Current");
    ValueCell = CmpFindValueByName(SystemHive,
                                   Node,
                                   &Name);
    if (ValueCell != HCELL_NIL) {
        Value = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
        if( Value == NULL ) {
            //
            // we couldn't map a view for the bin containing this cell
            //

            return HCELL_NIL;
        }
        if (Value->Type == REG_DWORD) {
            CurrentControl = (PULONG)CmpValueToData(SystemHive, Value,&realsize);
            if( CurrentControl == NULL ) {
                //
                // HvGetCell inside CmpValueToData failed; bail out safely
                //
                return HCELL_NIL;
            }
            *CurrentControl = *ControlSetIndex;
        }
    }
    return(ControlSet);

}


VOID
CmpSetCurrentProfile(
    IN PHHIVE Hive,
    IN HCELL_INDEX ControlSet,
    IN PCM_HARDWARE_PROFILE Profile
    )

/*++

Routine Description:

    Edits the in-memory copy of the registry to reflect the hardware
    profile that the system is booting from.

Arguments:

    Hive - Supplies a pointer to the hive control structure

    ControlSet - Supplies the HCELL_INDEX of the current control set.

    Profile - Supplies a pointer to the selected hardware profile

Return Value:

    None.

--*/

{
    HCELL_INDEX IDConfigDB;
    PCM_KEY_NODE IDConfigNode;
    HCELL_INDEX CurrentConfigCell;
    PCM_KEY_VALUE CurrentConfigValue;
    UNICODE_STRING Name;
    PULONG CurrentConfig;
    ULONG realsize;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );

    IDConfigDB = CmpFindProfileOption(Hive,
                                      ControlSet,
                                      NULL,
                                      NULL,
                                      NULL);
    if (IDConfigDB != HCELL_NIL) {
        IDConfigNode = (PCM_KEY_NODE)HvGetCell(Hive, IDConfigDB);
        if( IDConfigNode == NULL ) {
            //
            // we couldn't map a view for the bin containing this cell
            //
            return;
        }

        RtlInitUnicodeString(&Name, L"CurrentConfig");
        CurrentConfigCell = CmpFindValueByName(Hive,
                                               IDConfigNode,
                                               &Name);
        if (CurrentConfigCell != HCELL_NIL) {
            CurrentConfigValue = (PCM_KEY_VALUE)HvGetCell(Hive, CurrentConfigCell);
            if( CurrentConfigValue == NULL ) {
                //
                // we couldn't map a view for the bin containing this cell
                //
                return;
            }
            if (CurrentConfigValue->Type == REG_DWORD) {
                CurrentConfig = (PULONG)CmpValueToData(Hive,
                                                       CurrentConfigValue,
                                                       &realsize);
                if( CurrentConfig == NULL ) {
                    //
                    // HvGetCell inside CmpValueToData failed; bail out safely
                    //
                    return;
                }
                *CurrentConfig = Profile->Id;
            }
        }
    }


}


HCELL_INDEX
CmpFindProfileOption(
     IN PHHIVE SystemHive,
     IN HCELL_INDEX ControlSet,
     OUT OPTIONAL PCM_HARDWARE_PROFILE_LIST *ReturnedProfileList,
     OUT OPTIONAL PCM_HARDWARE_PROFILE_ALIAS_LIST *ReturnedAliasList,
     OUT OPTIONAL PULONG ProfileTimeout
     )

/*++

Routine Description:

    This routines parses the SYSTEM hive and locates the
    "CurrentControlSet\Control\IDConfigDB" node to determine the
    hardware profile configuration settings.

Arguments:

    SystemHive - Supplies the hive control structure for the SYSTEM hive.

    ControlSet - Supplies the HCELL_INDEX of the root cell of the hive.

    ProfileList - Returns the list of available hardware profiles sorted
                  by preference. Will be allocated by this routine if
                  NULL is passed in, or a pointer to a CM_HARDWARE_PROFILE_LIST
                  structure that is too small is passed in.

    ProfileTimeout - Returns the timeout value for the config menu.

Return Value:

    != HCELL_NIL - Cell Index of the IDConfigDB node.
    == HCELL_NIL - Indicates IDConfigDB does not exist

--*/
{
    HCELL_INDEX                     ControlCell;
    HCELL_INDEX                     IDConfigDB;
    HCELL_INDEX                     TimeoutCell;
    HCELL_INDEX                     ProfileCell;
    HCELL_INDEX                     AliasCell;
    HCELL_INDEX                     HWCell;
    PCM_KEY_NODE                    HWNode;
    PCM_KEY_NODE                    ProfileNode;
    PCM_KEY_NODE                    AliasNode;
    PCM_KEY_NODE                    ConfigDBNode;
    PCM_KEY_NODE                    Control;
    PCM_KEY_VALUE                   TimeoutValue;
    UNICODE_STRING                  Name;
    ULONG                           realsize;
    PCM_HARDWARE_PROFILE_LIST       ProfileList;
    PCM_HARDWARE_PROFILE_ALIAS_LIST AliasList;
    ULONG                           ProfileCount;
    ULONG                           AliasCount;
    ULONG                           i,j;
    WCHAR                           NameBuf[20];
    PCM_KEY_NODE                    Node;
    PULONG                          TempULong;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( SystemHive->ReleaseCellRoutine == NULL );

    //
    // Find Control node
    //
    Node = (PCM_KEY_NODE)HvGetCell(SystemHive,ControlSet);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }
    RtlInitUnicodeString(&Name, L"Control");
    ControlCell = CmpFindSubKeyByName(SystemHive,
                                      Node,
                                      &Name);
    if (ControlCell == HCELL_NIL) {
        return(HCELL_NIL);
    }
    Control = (PCM_KEY_NODE)HvGetCell(SystemHive, ControlCell);
    if( Control == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }

    //
    // Find IDConfigDB node
    //
    RtlInitUnicodeString(&Name, L"IDConfigDB");
    IDConfigDB = CmpFindSubKeyByName(SystemHive,
                                     Control,
                                     &Name);
    if (IDConfigDB == HCELL_NIL) {
        return(HCELL_NIL);
    }
    ConfigDBNode = (PCM_KEY_NODE)HvGetCell(SystemHive, IDConfigDB);
    if( ConfigDBNode == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return HCELL_NIL;
    }

    if (ARGUMENT_PRESENT(ProfileTimeout)) {
        //
        // Find UserWaitInterval value. This is the timeout
        //
        RtlInitUnicodeString(&Name, L"UserWaitInterval");
        TimeoutCell = CmpFindValueByName(SystemHive,
                                         ConfigDBNode,
                                         &Name);
        if (TimeoutCell == HCELL_NIL) {
            *ProfileTimeout = 0;
        } else {
            TimeoutValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, TimeoutCell);
            if( TimeoutValue == NULL ) {
                //
                // we couldn't map a view for the bin containing this cell
                //

                return HCELL_NIL;
            }
            if (TimeoutValue->Type != REG_DWORD) {
                *ProfileTimeout = 0;
            } else {
                TempULong = (PULONG)CmpValueToData(SystemHive, TimeoutValue, &realsize);
                if( TempULong == NULL ) {
                    //
                    // HvGetCell inside CmpValueToData failed; bail out safely
                    //
                    return HCELL_NIL;
                }
                *ProfileTimeout = *TempULong;
            }
        }
    }

    if (ARGUMENT_PRESENT(ReturnedProfileList)) {
        ProfileList = *ReturnedProfileList;
        //
        // Enumerate the keys under IDConfigDB\Hardware Profiles
        // and build the list of available hardware profiles.  The list
        // is built sorted by PreferenceOrder.  Therefore, when the
        // list is complete, the default hardware profile is at the
        // head of the list.
        //
        RtlInitUnicodeString(&Name, L"Hardware Profiles");
        ProfileCell = CmpFindSubKeyByName(SystemHive,
                                          ConfigDBNode,
                                          &Name);
        if (ProfileCell == HCELL_NIL) {
            ProfileCount = 0;
            if (ProfileList != NULL) {
                ProfileList->CurrentProfileCount = 0;
            }
        } else {
            ProfileNode = (PCM_KEY_NODE)HvGetCell(SystemHive, ProfileCell);
            if( ProfileNode == NULL ) {
                //
                // we couldn't map a view for the bin containing this cell
                //

                return HCELL_NIL;
            }
            ProfileCount = ProfileNode->SubKeyCounts[Stable];
            if ((ProfileList == NULL) || (ProfileList->MaxProfileCount < ProfileCount)) {
                //
                // Allocate a larger ProfileList
                //
                ProfileList = (SystemHive->Allocate)(sizeof(CM_HARDWARE_PROFILE_LIST)
                                                     + (ProfileCount-1) * sizeof(CM_HARDWARE_PROFILE),
                                                     FALSE
                                                     ,CM_FIND_LEAK_TAG5);
                if (ProfileList == NULL) {
                    return(HCELL_NIL);
                }
                ProfileList->MaxProfileCount = ProfileCount;
            }
            ProfileList->CurrentProfileCount = 0;

            //
            // Enumerate the keys and fill in the profile list.
            //
            for (i=0; i<ProfileCount; i++) {
                CM_HARDWARE_PROFILE TempProfile;
                HCELL_INDEX ValueCell;
                PCM_KEY_VALUE ValueNode;
                UNICODE_STRING KeyName;

                HWCell = CmpFindSubKeyByNumber(SystemHive, ProfileNode, i);
                if (HWCell == HCELL_NIL) {
                    //
                    // This should never happen.
                    //
                    ProfileList->CurrentProfileCount = i;
                    break;
                }
                HWNode = (PCM_KEY_NODE)HvGetCell(SystemHive, HWCell);
                if( HWNode == NULL ) {
                    //
                    // we couldn't map a view for the bin containing this cell
                    //

                    return HCELL_NIL;
                }
                if (HWNode->Flags & KEY_COMP_NAME) {
                    KeyName.Length = CmpCompressedNameSize(HWNode->Name,
                                                           HWNode->NameLength);
                    KeyName.MaximumLength = sizeof(NameBuf);
                    if (KeyName.MaximumLength < KeyName.Length) {
                        KeyName.Length = KeyName.MaximumLength;
                    }
                    KeyName.Buffer = NameBuf;
                    CmpCopyCompressedName(KeyName.Buffer,
                                          KeyName.Length,
                                          HWNode->Name,
                                          HWNode->NameLength);
                } else {
                    KeyName.Length = KeyName.MaximumLength = HWNode->NameLength;
                    KeyName.Buffer = HWNode->Name;
                }

                //
                // Fill in the temporary profile structure with this
                // profile's data.
                //
                RtlUnicodeStringToInteger(&KeyName, 0, &TempProfile.Id);
                RtlInitUnicodeString(&Name, CM_HARDWARE_PROFILE_STR_PREFERENCE_ORDER);
                ValueCell = CmpFindValueByName(SystemHive,
                                               HWNode,
                                               &Name);
                if (ValueCell == HCELL_NIL) {
                    TempProfile.PreferenceOrder = (ULONG)-1;
                } else {
                    ValueNode = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                    if( ValueNode == NULL ) {
                        //
                        // we couldn't map a view for the bin containing this cell
                        //

                        return HCELL_NIL;
                    }

                    TempULong = (PULONG)CmpValueToData(SystemHive,
                                                      ValueNode,
                                                      &realsize);
                    if( TempULong == NULL ) {
                        //
                        // HvGetCell inside CmpValueToData failed; bail out safely
                        //
                        return HCELL_NIL;
                    }
                    TempProfile.PreferenceOrder = *TempULong;
                }
                RtlInitUnicodeString(&Name, CM_HARDWARE_PROFILE_STR_FRIENDLY_NAME);
                ValueCell = CmpFindValueByName(SystemHive,
                                               HWNode,
                                               &Name);
                if (ValueCell == HCELL_NIL) {
                    TempProfile.FriendlyName = L"-------";
                    TempProfile.NameLength = (ULONG)(wcslen(TempProfile.FriendlyName) * sizeof(WCHAR));
                } else {
                    ValueNode = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                    if( ValueNode == NULL ) {
                        //
                        // we couldn't map a view for the bin containing this cell
                        //

                        return HCELL_NIL;
                    }
                    TempProfile.FriendlyName = (PWSTR)CmpValueToData(SystemHive,
                                                                     ValueNode,
                                                                     &realsize);
                    if( TempProfile.FriendlyName == NULL ) {
                        //
                        // HvGetCell inside CmpValueToData failed; bail out safely
                        //
                        return HCELL_NIL;
                    }
                    TempProfile.NameLength = realsize - sizeof(WCHAR);
                }

                TempProfile.Flags = 0;

                RtlInitUnicodeString(&Name, CM_HARDWARE_PROFILE_STR_ALIASABLE);
                ValueCell = CmpFindValueByName(SystemHive,
                                               HWNode,
                                               &Name);
                if (ValueCell == HCELL_NIL) {
                    TempProfile.Flags = CM_HP_FLAGS_ALIASABLE;
                } else {
                    ValueNode = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                    if( ValueNode == NULL ) {
                        //
                        // we couldn't map a view for the bin containing this cell
                        //

                        return HCELL_NIL;
                    }

                    TempULong = (PULONG)CmpValueToData (SystemHive,ValueNode,&realsize);
                    if( TempULong == NULL ) {
                        //
                        // HvGetCell inside CmpValueToData failed; bail out safely
                        //
                        return HCELL_NIL;
                    }
                    if (*TempULong) {
                        TempProfile.Flags = CM_HP_FLAGS_ALIASABLE;
                        // NO other flags set.
                    }
                }

                RtlInitUnicodeString(&Name, CM_HARDWARE_PROFILE_STR_PRISTINE);
                ValueCell = CmpFindValueByName(SystemHive,
                                               HWNode,
                                               &Name);
                if (ValueCell != HCELL_NIL) {

                    ValueNode = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                    if( ValueNode == NULL ) {
                        //
                        // we couldn't map a view for the bin containing this cell
                        //

                        return HCELL_NIL;
                    }

                    TempULong = (PULONG)CmpValueToData (SystemHive,ValueNode,&realsize);
                    if( TempULong == NULL ) {
                        //
                        // HvGetCell inside CmpValueToData failed; bail out safely
                        //
                        return HCELL_NIL;
                    }
                    if (*TempULong) {
                        TempProfile.Flags = CM_HP_FLAGS_PRISTINE;
                        // NO other flags set.
                    }
                }

                //
                // If we see a profile with the ID of zero (AKA an illegal)
                // ID for a hardware profile to possess, then we know that this
                // must be a pristine profile.
                //
                if (0 == TempProfile.Id) {
                    TempProfile.Flags = CM_HP_FLAGS_PRISTINE;
                    // NO other flags set.

                    TempProfile.PreferenceOrder = (ULONG)-1; // move to the end of the list.
                }


                //
                // Insert this new profile into the appropriate spot in the
                // profile array. Entries are sorted by preference order.
                //
                for (j=0; j<ProfileList->CurrentProfileCount; j++) {
                    if (ProfileList->Profile[j].PreferenceOrder >= TempProfile.PreferenceOrder) {
                        //
                        // Insert at position j.
                        //
                        RtlMoveMemory(&ProfileList->Profile[j+1],
                                      &ProfileList->Profile[j],
                                      sizeof(CM_HARDWARE_PROFILE)*(ProfileList->MaxProfileCount-j-1));
                        break;
                    }
                }
                ProfileList->Profile[j] = TempProfile;
                ++ProfileList->CurrentProfileCount;
            }
        }
        *ReturnedProfileList = ProfileList;
    }

    if (ARGUMENT_PRESENT(ReturnedAliasList)) {
        AliasList = *ReturnedAliasList;
        //
        // Enumerate the keys under IDConfigDB\Alias
        // and build the list of available hardware profiles aliases.
        // So that if we know our docking state we can find it in the alias
        // table.
        //
        RtlInitUnicodeString(&Name, L"Alias");
        AliasCell = CmpFindSubKeyByName(SystemHive,
                                        ConfigDBNode,
                                        &Name);
        if (AliasCell == HCELL_NIL) {
            AliasCount = 0;
            if (AliasList != NULL) {
                AliasList->CurrentAliasCount = 0;
            }
        } else {
            AliasNode = (PCM_KEY_NODE)HvGetCell(SystemHive, AliasCell);
            if( AliasNode == NULL ) {
                //
                // we couldn't map a view for the bin containing this cell
                //

                return HCELL_NIL;
            }
            AliasCount = AliasNode->SubKeyCounts[Stable];
            if ((AliasList == NULL) || (AliasList->MaxAliasCount < AliasCount)) {
                //
                // Allocate a larger AliasList
                //
                AliasList = (SystemHive->Allocate)(sizeof(CM_HARDWARE_PROFILE_LIST)
                                                   + (AliasCount-1) * sizeof(CM_HARDWARE_PROFILE),
                                                   FALSE
                                                   ,CM_FIND_LEAK_TAG6);
                if (AliasList == NULL) {
                    return(HCELL_NIL);
                }
                AliasList->MaxAliasCount = AliasCount;
            }
            AliasList->CurrentAliasCount = 0;

            //
            // Enumerate the keys and fill in the profile list.
            //
            for (i=0; i<AliasCount; i++) {
#define TempAlias AliasList->Alias[i]
                HCELL_INDEX ValueCell;
                PCM_KEY_VALUE ValueNode;
                UNICODE_STRING KeyName;

                HWCell = CmpFindSubKeyByNumber(SystemHive, AliasNode, i);
                if (HWCell == HCELL_NIL) {
                    //
                    // This should never happen.
                    //
                    AliasList->CurrentAliasCount = i;
                    break;
                }
                HWNode = (PCM_KEY_NODE)HvGetCell(SystemHive, HWCell);
                if( HWNode == NULL ) {
                    //
                    // we couldn't map a view for the bin containing this cell
                    //

                    return HCELL_NIL;
                }
                if (HWNode->Flags & KEY_COMP_NAME) {
                    KeyName.Length = CmpCompressedNameSize(HWNode->Name,
                                                           HWNode->NameLength);
                    KeyName.MaximumLength = sizeof(NameBuf);
                    if (KeyName.MaximumLength < KeyName.Length) {
                        KeyName.Length = KeyName.MaximumLength;
                    }
                    KeyName.Buffer = NameBuf;
                    CmpCopyCompressedName(KeyName.Buffer,
                                          KeyName.Length,
                                          HWNode->Name,
                                          HWNode->NameLength);
                } else {
                    KeyName.Length = KeyName.MaximumLength = HWNode->NameLength;
                    KeyName.Buffer = HWNode->Name;
                }

                //
                // Fill in the temporary profile structure with this
                // profile's data.
                //
                RtlInitUnicodeString(&Name, L"ProfileNumber");
                ValueCell = CmpFindValueByName(SystemHive,
                                               HWNode,
                                               &Name);
                if (ValueCell == HCELL_NIL) {
                    TempAlias.ProfileNumber = 0;
                } else {
                    ValueNode = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                    if( ValueNode == NULL ) {
                        //
                        // we couldn't map a view for the bin containing this cell
                        //

                        return HCELL_NIL;
                    }

                    TempULong = (PULONG)CmpValueToData(SystemHive,ValueNode,&realsize);
                    if( TempULong == NULL ) {
                        //
                        // HvGetCell inside CmpValueToData failed; bail out safely
                        //
                        return HCELL_NIL;
                    }
                    TempAlias.ProfileNumber = *TempULong;
                }
                RtlInitUnicodeString(&Name, L"DockState");
                ValueCell = CmpFindValueByName(SystemHive,
                                               HWNode,
                                               &Name);
                if (ValueCell == HCELL_NIL) {
                    TempAlias.DockState = 0;
                } else {
                    ValueNode = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                    if( ValueNode == NULL ) {
                        //
                        // we couldn't map a view for the bin containing this cell
                        //

                        return HCELL_NIL;
                    }

                    TempULong = (PULONG)CmpValueToData(SystemHive,ValueNode,&realsize);
                    if( TempULong == NULL ) {
                        //
                        // HvGetCell inside CmpValueToData failed; bail out safely
                        //
                        return HCELL_NIL;
                    }
                    TempAlias.DockState = *TempULong;
                }
                RtlInitUnicodeString(&Name, L"DockID");
                ValueCell = CmpFindValueByName(SystemHive,
                                               HWNode,
                                               &Name);
                if (ValueCell == HCELL_NIL) {
                    TempAlias.DockID = 0;
                } else {
                    ValueNode = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                    if( ValueNode == NULL ) {
                        //
                        // we couldn't map a view for the bin containing this cell
                        //

                        return HCELL_NIL;
                    }

                    TempULong = (PULONG)CmpValueToData(SystemHive,ValueNode,&realsize);
                    if( TempULong == NULL ) {
                        //
                        // HvGetCell inside CmpValueToData failed; bail out safely
                        //
                        return HCELL_NIL;
                    }
                    TempAlias.DockID = *TempULong;
                }
                RtlInitUnicodeString(&Name, L"SerialNumber");
                ValueCell = CmpFindValueByName(SystemHive,
                                               HWNode,
                                               &Name);
                if (ValueCell == HCELL_NIL) {
                    TempAlias.SerialNumber = 0;
                } else {
                    ValueNode = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
                    if( ValueNode == NULL ) {
                        //
                        // we couldn't map a view for the bin containing this cell
                        //

                        return HCELL_NIL;
                    }

                    TempULong = (PULONG)CmpValueToData(SystemHive,ValueNode,&realsize);
                    if( TempULong == NULL ) {
                        //
                        // HvGetCell inside CmpValueToData failed; bail out safely
                        //
                        return HCELL_NIL;
                    }
                    TempAlias.SerialNumber = *TempULong;
                }

                ++AliasList->CurrentAliasCount;
            }
        }
        *ReturnedAliasList = AliasList;
    }

    return(IDConfigDB);
}


ULONG
CmpFindTagIndex(
    IN PHHIVE Hive,
    IN HCELL_INDEX TagCell,
    IN HCELL_INDEX GroupOrderCell,
    IN PUNICODE_STRING GroupName
    )

/*++

Routine Description:

    Calculates the tag index for a driver based on its tag value and
    the GroupOrderList entry for its group.

Arguments:

    Hive - Supplies the hive control structure for the driver.

    TagCell - Supplies the cell index of the driver's tag value cell.

    GroupOrderCell - Supplies the cell index for the control set's
            GroupOrderList:

            \Registry\Machine\System\CurrentControlSet\Control\GroupOrderList

    GroupName - Supplies the name of the group the driver belongs to.
            Note that if a driver's group does not have an entry under
            GroupOrderList, its tags will be ignored.  Also note that if
            a driver belongs to no group (GroupName is NULL) its tags will
            be ignored.

Return Value:

    The index that the driver should be sorted by.

--*/

{
    PCM_KEY_VALUE TagValue;
    PCM_KEY_VALUE DriverTagValue;
    HCELL_INDEX OrderCell;
    PULONG OrderVector;
    PULONG DriverTag;
    ULONG CurrentTag;
    ULONG realsize;
    PCM_KEY_NODE Node;
    BOOLEAN     BufferAllocated;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );

    DriverTagValue = (PCM_KEY_VALUE)HvGetCell(Hive, TagCell);
    if( DriverTagValue == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return LOAD_NEXT_TO_LAST;
    }

    DriverTag = (PULONG)CmpValueToData(Hive, DriverTagValue, &realsize);
    if( DriverTag == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return LOAD_NEXT_TO_LAST;
    }

    Node = (PCM_KEY_NODE)HvGetCell(Hive,GroupOrderCell);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return LOAD_NEXT_TO_LAST;
    }
    OrderCell = CmpFindValueByName(Hive,
                                   Node,
                                   GroupName);
    if (OrderCell == HCELL_NIL) {
        return(LOAD_NEXT_TO_LAST);
    }

    TagValue = (PCM_KEY_VALUE)HvGetCell(Hive, OrderCell);
    if( TagValue == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return LOAD_NEXT_TO_LAST;
    }
    CmpGetValueData(Hive,TagValue,&realsize,&OrderVector,&BufferAllocated,&OrderCell);

    if( OrderVector == NULL ) {
        //
        // HvGetCell inside CmpValueToData failed; bail out safely
        //
        return LOAD_NEXT_TO_LAST;
    }

    for (CurrentTag=1; CurrentTag <= OrderVector[0]; CurrentTag++) {
        if (OrderVector[CurrentTag] == *DriverTag) {
            //
            // We have found a matching tag in the OrderVector, so return
            // its index.
            //
            if( BufferAllocated ) {
                ExFreePool( OrderVector );
            }
            return(CurrentTag);
        }
    }

    if( BufferAllocated ) {
        ExFreePool( OrderVector );
    }
    //
    // There was no matching tag in the OrderVector.
    //
    return(LOAD_NEXT_TO_LAST);

}

#ifdef _WANT_MACHINE_IDENTIFICATION

BOOLEAN
CmpGetBiosDateFromRegistry(
    IN PHHIVE Hive,
    IN HCELL_INDEX ControlSet,
    OUT PUNICODE_STRING Date
    )

/*++

Routine Description:

    Reads and returns the BIOS date from the registry.

Arguments:

    Hive - Supplies the hive control structure for the driver.

    ControlSet - Supplies the HCELL_INDEX of the root cell of the hive.

    Date - Receives the date string in the format "mm/dd/yy".

Return Value:

 	TRUE iff successful, else FALSE.
 	
--*/

{
    UNICODE_STRING  name;
    HCELL_INDEX     control;
    HCELL_INDEX     biosInfo;
    HCELL_INDEX     valueCell;
    PCM_KEY_VALUE   value;
    ULONG           realSize;
    PCM_KEY_NODE    Node;
    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );

    //
    // Find CONTROL node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&name, L"Control");
    control = CmpFindSubKeyByName(  Hive,
                                    Node,
                                    &name);
    if (control == HCELL_NIL) {

        return(FALSE);
    }

    //
    // Find BIOSINFO node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive, control);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&name, L"BIOSINFO");
    biosInfo = CmpFindSubKeyByName( Hive,
                                    Node,
                                    &name);
    if (biosInfo == HCELL_NIL) {

        return(FALSE);
    }

    //
    // Find SystemBiosDate value
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive, biosInfo);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&name, L"SystemBiosDate");
    valueCell = CmpFindValueByName( Hive,
                                    Node,
                                    &name);
    if (valueCell == HCELL_NIL) {

        return(FALSE);
    }

    value = (PCM_KEY_VALUE)HvGetCell(Hive, valueCell);
    if( value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    Date->Buffer = (PWSTR)CmpValueToData(Hive, value, &realSize);
    if( Date->Buffer == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    Date->MaximumLength=(USHORT)realSize;
    Date->Length = 0;
    while ( (Date->Length < Date->MaximumLength) &&
            (Date->Buffer[Date->Length/sizeof(WCHAR)] != UNICODE_NULL)) {

        Date->Length += sizeof(WCHAR);
    }

    return (TRUE);
}

BOOLEAN
CmpGetBiosinfoFileNameFromRegistry(
    IN PHHIVE Hive,
    IN HCELL_INDEX ControlSet,
    OUT PUNICODE_STRING InfName
    )
{
    UNICODE_STRING  name;
    HCELL_INDEX     control;
    HCELL_INDEX     biosInfo;
    HCELL_INDEX     valueCell;
    PCM_KEY_VALUE   value;
    ULONG           realSize;
    PCM_KEY_NODE    Node;

    //
    // no mapped hives at this point. don't bother releasing cells
    //
    ASSERT( Hive->ReleaseCellRoutine == NULL );
    //
    // Find CONTROL node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive, ControlSet);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&name, L"Control");
    control = CmpFindSubKeyByName(  Hive,
                                    Node,
                                    &name);
    if (control == HCELL_NIL) {

        return(FALSE);
    }

    //
    // Find BIOSINFO node
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive, control);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&name, L"BIOSINFO");
    biosInfo = CmpFindSubKeyByName( Hive,
                                    Node,
                                    &name);
    if (biosInfo == HCELL_NIL) {

        return(FALSE);
    }

    //
    // Find InfName value
    //
    Node = (PCM_KEY_NODE)HvGetCell(Hive, biosInfo);
    if( Node == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    RtlInitUnicodeString(&name, L"InfName");
    valueCell = CmpFindValueByName( Hive,
                                    Node,
                                    &name);
    if (valueCell == HCELL_NIL) {

        return(FALSE);
    }

    value = (PCM_KEY_VALUE)HvGetCell(Hive, valueCell);
    if( value == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    InfName->Buffer = (PWSTR)CmpValueToData(Hive, value, &realSize);
    if( InfName->Buffer == NULL ) {
        //
        // we couldn't map a view for the bin containing this cell
        //

        return FALSE;
    }
    InfName->MaximumLength=(USHORT)realSize;
    InfName->Length = 0;
    while ( (InfName->Length < InfName->MaximumLength) &&
            (InfName->Buffer[InfName->Length/sizeof(WCHAR)] != UNICODE_NULL)) {

        InfName->Length += sizeof(WCHAR);
    }

    return (TRUE);
}

#endif
