//depot/Lab01_N/base/ntos/config/i386/rules.c#7 - edit change 11499 (text)
/*++

Copyright (c) 1998  Microsoft Corporation


Module Name:

    rules.c

Abstract:

    This module contains routines to implement rules used to describe a machine.
    This is based on the detection code from W9x.

Author:

    Santosh Jodh (santoshj) 08-Aug-1998

Environment:

    Kernel mode.

Revision History:

--*/

#include "cmp.h"
#include "stdlib.h"
#include "parseini.h"
#include "geninst.h"
#include "acpitabl.h"
#include "ntacpi.h"
#include "rules.h"

#define TABLE_ENTRIES_FROM_RSDT_POINTER(p)  (((p)->Header.Length-min((p)->Header.Length, sizeof(DESCRIPTION_HEADER))) / 4)


//
// Size of the ROM BIOS segment.
//

#define SYSTEM_BIOS_LENGTH 0x10000

//
// PnP BIOS structure signature.
//

#define PNPBIOS_SIGNATURE   'PnP$'

typedef
BOOLEAN
(* PFN_RULE)(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

typedef struct _PNP_BIOS_TABLE PNP_BIOS_TABLE, *PPNP_BIOS_TABLE;

#pragma pack(push, 1)

struct _PNP_BIOS_TABLE
{
    ULONG   Signature;
    UCHAR   Version;
    UCHAR   Length;
    USHORT  ControlField;
    UCHAR   CheckSum;
    ULONG   EventNotification;
    USHORT  RMOffset;
    USHORT  RMSegment;
    USHORT  PMOffset;
    ULONG   PMSegment;
    ULONG   Oem;
    USHORT  RMData;
    ULONG   PMData;
};

#pragma pack(pop)

ULONG
CmpComputeChecksum(
    IN PCHAR    Address,
    IN ULONG    Size
    );

NTSTATUS
CmpFindRSDTTable(
    OUT PACPI_BIOS_MULTI_NODE   *Rsdt
    );

NTSTATUS
CmpGetRegistryValue(
    IN  HANDLE                          KeyName,
    IN  PWSTR                           ValueName,
    OUT PKEY_VALUE_PARTIAL_INFORMATION  *Information
    );

BOOLEAN
CmpCheckOperator(
    IN PCHAR Operator,
    IN ULONG Lhs,
    IN ULONG Rhs
    );

PVOID
CmpMapPhysicalAddress(
    IN OUT PVOID *BaseAddress,
    IN ULONG_PTR Address,
    IN ULONG Size
    );

BOOLEAN
CmpGetInfData(
    IN PVOID InfHandle,
    IN PCHAR Section,
    IN ULONG KeyIndex,
    IN ULONG LineIndex,
    IN OUT PCHAR Buffer,
    IN OUT PULONG BufferSize
    );

PVOID
CmpFindPattern(
    IN PCHAR Buffer,
    IN ULONG BufSize,
    IN PCHAR Pattern,
    IN ULONG PatSize,
    IN BOOLEAN IgnoreCase,
    IN ULONG Step
    );

 ULONG
 CmpGetPnPBIOSTableAddress(
    VOID
    );

BOOLEAN
CmpMatchDescription(
    IN PVOID InfHandle,
    IN PCHAR Description
    );

BOOLEAN
CmpMatchDateRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchMemoryRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchSearchRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchNextMatchRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchPointerRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchOemIdRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchPModeRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchRmPmSameRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchInstallRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchAcpiOemIdRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchAcpiOemTableIdRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchAcpiOemRevisionRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchAcpiRevisionRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

BOOLEAN
CmpMatchAcpiCreatorRevisionRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    );

//
// Number of rules currently implemented.
//

#define NUM_OF_RULES    14

//
// Rule table.
//

#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("INITDATA")
#pragma const_seg("INITCONST")
#endif
struct {
    PCHAR       Name;
    PFN_RULE    Action;
} const gRuleTable[NUM_OF_RULES] =
{
    {"Date", CmpMatchDateRule},
    {"Memory", CmpMatchMemoryRule},
    {"Search", CmpMatchSearchRule},
    {"NextMatch", CmpMatchNextMatchRule},
    {"Pointer", CmpMatchPointerRule},
    {"OemId", CmpMatchOemIdRule},
    {"PMode", CmpMatchPModeRule},
    {"RmPmSame", CmpMatchRmPmSameRule},
    {"Install", CmpMatchInstallRule},
    {"ACPIOemId", CmpMatchAcpiOemIdRule},
    {"ACPIOemTableId", CmpMatchAcpiOemTableIdRule},
    {"ACPIOemRevision", CmpMatchAcpiOemRevisionRule},
    {"ACPIRevision", CmpMatchAcpiRevisionRule},
    {"ACPICreatorRevision", CmpMatchAcpiCreatorRevisionRule}
};

PVOID   gSearchAddress = NULL;

static const WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
static const WCHAR rgzAcpiConfigurationData[] = L"Configuration Data";
static const WCHAR rgzAcpiIdentifier[] = L"Identifier";
static const WCHAR rgzBIOSIdentifier[] = L"ACPI BIOS";

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpGetRegistryValue)
#pragma alloc_text(INIT,CmpFindACPITable)
#pragma alloc_text(INIT,CmpFindRSDTTable)
#pragma alloc_text(INIT,CmpComputeChecksum)
#pragma alloc_text(INIT,CmpCheckOperator)
#pragma alloc_text(INIT,CmpMapPhysicalAddress)
#pragma alloc_text(INIT,CmpGetInfData)
#pragma alloc_text(INIT,CmpFindPattern)
#pragma alloc_text(INIT,CmpGetPnPBIOSTableAddress)
#pragma alloc_text(INIT,CmpMatchInfList)
#pragma alloc_text(INIT,CmpMatchDescription)
#pragma alloc_text(INIT,CmpMatchDateRule)
#pragma alloc_text(INIT,CmpMatchMemoryRule)
#pragma alloc_text(INIT,CmpMatchSearchRule)
#pragma alloc_text(INIT,CmpMatchNextMatchRule)
#pragma alloc_text(INIT,CmpMatchPointerRule)
#pragma alloc_text(INIT,CmpMatchOemIdRule)
#pragma alloc_text(INIT,CmpMatchPModeRule)
#pragma alloc_text(INIT,CmpMatchRmPmSameRule)
#pragma alloc_text(INIT,CmpMatchInstallRule)
#pragma alloc_text(INIT,CmpMatchAcpiOemIdRule)
#pragma alloc_text(INIT,CmpMatchAcpiOemTableIdRule)
#pragma alloc_text(INIT,CmpMatchAcpiOemRevisionRule)
#pragma alloc_text(INIT,CmpMatchAcpiRevisionRule)
#pragma alloc_text(INIT,CmpMatchAcpiCreatorRevisionRule)
#endif


BOOLEAN
CmpMatchInfList(
    IN PVOID InfImage,
    IN ULONG ImageSize,
    IN PCHAR Section
    )

/*++

    Routine Description:

    Input Parameters:

        InfImage - Pointer to the inf image in memory.

        ImageSize - Size of the inf image.

        Section - Section name containing the descriptions.

        Description -

    Return Value:

        TRUE if the machine matches any one of the descriptions in the inf.

--*/

{
    PCHAR   computerName;
    ULONG   i = 0;
    PVOID   infHandle;
    BOOLEAN result = FALSE;

    infHandle = CmpOpenInfFile(InfImage, ImageSize);

    if (infHandle)
    {
        //
        // Do any clean-up specified in the inf.
        //

        CmpGenInstall(infHandle, "Cleanup");

        //
        // Go through each description in this section and try to match
        // this machine to it.
        //

        while ((computerName = CmpGetSectionLineIndex(infHandle, Section, i++, 0)))
        {
            //
            // Reset search result from previous description.
            //

            gSearchAddress = NULL;

            //
            // We will process ALL sections even if one or more match.
            //

            if (CmpMatchDescription(infHandle, computerName))
            {
                CmKdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_WARNING_LEVEL, "CmpMatchInfList: Machine matches %s description!\n", computerName));
                result = TRUE;
            }
        }

        CmpCloseInfFile(infHandle);
    }

    //
    // None of the descriptions match.
    //

    return (result);
}

BOOLEAN
CmpMatchDescription(
    IN PVOID InfHandle,
    IN PCHAR Description
    )

/*++

    Routine Description:

        This routine processes all the rules in the specified description.

    Input Parameters:

        InfHandle - Handle to the inf containing the description.

        Description - Section name containing the rules.

    Return Value:

        TRUE iff all the rules in the description succeed.

--*/

{
    ULONG   ruleNumber;
    ULONG   i;
    PCHAR   ruleName;

    //
    // Proceed only if the section does exist.
    //

    if (CmpSearchInfSection(InfHandle, Description))
    {
        //
        // Go through all the rules in the description and try to match
        // each of them.
        //

        ruleNumber = 0;
        while ((ruleName = CmpGetKeyName(InfHandle, Description, ruleNumber)))
        {
            //
            // Search for the rule in our table.
            //

            for (   i = 0;
                    i < NUM_OF_RULES &&
                        _stricmp(ruleName, gRuleTable[i].Name);
                    i++);

            //
            // If we did not find the rule or the rule failed,
            // return failure.
            //

            if (    i >= NUM_OF_RULES ||
                    !(*gRuleTable[i].Action)(InfHandle, Description, ruleNumber++))
            {
                return (FALSE);
            }
        }

        //
        // Description matches if we found at least one rule and all rules
        // succeeded.
        //

        if (ruleNumber)
        {
            return (TRUE);
        }
    }

    //
    // Description did not match.
    //

    return (FALSE);
}

BOOLEAN
CmpMatchDateRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )

/*++

    Routine Description:

        This routine checks if the machine satisfies the DATE rule. The BIOS date
        is stored in a standard location in the BIOS ROM at FFFF:5.

        Syntax -

        DATE=operator,month,day,year
            where operator [=, ==, !=, <>, <, <=, =<, >, >=, =>]

        Examples -

        date="<=",2,1,95
            is TRUE if the BIOS date on this machine is less than or equal to
            02/01/95.

    Input Parameters:

        InfHandle - Handle to the inf to be read.

        Description - Name of the section containing the rule info.

        RuleIndex - Line number for the rule in the description section.

    Return Value:

        TRUE if the BIOS on this machine has the specified relation with the
        date specified in the rule.

--*/

{
    PCHAR   op;
    PCHAR   month;
    PCHAR   day;
    PCHAR   year;
    ULONG   infDate;
    ULONG   yr;
    ULONG   biosDate;
    CHAR    temp[3];
    PVOID   baseAddress;
    PCHAR   address;

    op = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
    month = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
    day = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 2);
    year = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 3);

    if (op && month && day && year)
    {
        yr = strtoul(year, NULL, 16);
        infDate = ((yr < 0x80) ? 0x20000000 : 0x19000000) +
                    (yr << 16) +
                    (strtoul(month, NULL, 16) << 8) +
                    (strtoul(day, NULL, 16));

        address = CmpMapPhysicalAddress(&baseAddress, 0xFFFF5, 8);
        if (address)
        {
            temp[2] = '\0';

            RtlCopyBytes(temp, address + 6, 2);
            yr = strtoul(temp, NULL, 16);
            biosDate = ((yr < 0x80) ? 0x20000000 : 0x19000000) +
                        (yr << 16);

            RtlCopyBytes(temp, address, 2);
            biosDate |= (strtoul(temp, NULL, 16) << 8);

            RtlCopyBytes(temp, address + 3, 2);
            biosDate |= strtoul(temp, NULL, 16);

            ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);

            if (CmpCheckOperator(op, biosDate, infDate))
            {
                return (TRUE);
            }
        }
    }

    return (FALSE);
}

BOOLEAN
CmpMatchMemoryRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )

/*++

    Routine Description:

        This routine checks if the machine satisfies the MEMORY rule.

        Syntax -

        MEMORY=segment,offset,type,data
            where type ["S", "B"]

        Examples -

        memory=f000,e000,S,"TOSHIBA"
            is TRUE if the memory in this machine at physical address f000:e000
            has the string "TOSHIBA".

        memory=ffff,5,B,01,02
            is TRUE if the memory in this machine at physical memory ffff:5
            has the bytes 0x01 and 0x02.

    Input Parameters:

        InfHandle - Handle to the inf to be read.

        Description - Name of the section containing the rule info.

        RuleIndex - Line number for the rule in the description section.

    Return Value:

        TRUE iff the MEMORY in this machine at the specified address
        contains the specified data.

--*/

{
    BOOLEAN             match = FALSE;
    PCHAR               segment;
    PCHAR               offset;
    CHAR                data[MAX_DESCRIPTION_LEN + 1];
    ULONG               cbData;
    PVOID               baseAddress;
    PCHAR               address;
    ULONG               memory;

    //
    // Read in the segment and offset of the address specified.
    //

    segment = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
    offset = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);

    if (segment && offset)
    {
        //
        // Get the data specified in the inf.
        //

        cbData = sizeof(data);
        if (CmpGetInfData(InfHandle, Description, RuleIndex, 2, data, &cbData))
        {
            memory = (strtoul(segment, NULL, 16) << 4) + strtoul(offset, NULL, 16);

            //
            // Map in the physical address.
            //

            address = CmpMapPhysicalAddress(&baseAddress, memory, cbData);
            if (address)
            {

                //
                // Check if the inf data matches data in memory.
                //

                match = (RtlCompareMemory(address, data, cbData) == cbData);

                //
                // Unmap the physical address.
                //

                ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
            }
        }
    }

    return (match);
}

BOOLEAN
CmpMatchSearchRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )

/*++

    Routine Description:

        This routine checks to see if the machine matches the SEARCH rule.

        Syntax -

        SEARCH=segment,offset,length,type,data
            where type ["S", "B"]

        Examples -

        search=f000,e000,7f,S,"SurePath"
            is TRUE if the string "SurePath" is somewhere in memory range
            F000:E000 to F000:E07F (inclusive).

    Input Parameters:

        InfHandle - Handle to the inf to be read.

        Description - Name of the section containing the rule info.

        RuleIndex - Line number for the rule in the description section.

    Return Value:

        TRUE iff the specified pattern is found within the specified address
        range.

--*/

{
    BOOLEAN match = FALSE;
    PCHAR   segment;
    PCHAR   offset;
    PCHAR   size;
    CHAR    data[MAX_DESCRIPTION_LEN + 1];
    ULONG   cbData;
    ULONG   memory;
    ULONG   length;
    PVOID   baseAddress;
    PCHAR   address;

    segment = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
    offset = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
    size = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 2);

    if (segment && offset && size)
    {
        //
        // Get the data specified in the inf.
        //

        cbData = sizeof(data);
        if (CmpGetInfData(InfHandle, Description, RuleIndex, 3, data, &cbData))
        {
            memory = (strtoul(segment, NULL, 16) << 4) + strtoul(offset, NULL, 16);

            //
            // Map in the physical address.
            //

            length = strtoul(size, NULL, 16);
            address = CmpMapPhysicalAddress(&baseAddress, memory, length);
            if (address)
            {
                gSearchAddress = CmpFindPattern(address, length, data, cbData, FALSE, 0);
                if (gSearchAddress)
                {
                    //
                    // If we found the pattern, compute the actual address for it.
                    //

                    (PCHAR)gSearchAddress -= (ULONG_PTR)address;
                    (PCHAR)gSearchAddress += memory;
                    match = TRUE;
                }

                //
                // Unmap the physical address.
                //

                ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
            }
        }
    }

    return (match);
}

BOOLEAN
CmpMatchNextMatchRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )

/*++

    Routine Description:

        This routine checks to see if the machine matches the NEXTMATCH rule.

        Syntax -

        NEXTMATCH=offset,type,data
            where type ["S", "B"]

        Examples -

        nextmatch=f0,S,"Atlanta"
            is TRUE if the string "Atlanta" is at offset 0xF0 from the previous
            successful SEARCH or NEXTMATCH rule.

    Input Parameters:

        InfHandle - Handle to the inf to be read.

        Description - Name of the section containing the rule info.

        RuleIndex - Line number for the rule in the description section.

    Return Value:

        TRUE iff the specified pattern is found at the specified offset
        from the previous successful SEARCH or NEXTMATCH.

--*/

{
    BOOLEAN match = FALSE;
    PCHAR   offset;
    CHAR    data[MAX_DESCRIPTION_LEN + 1];
    ULONG   cbData;
    PVOID   baseAddress;
    PCHAR   address;

    if (gSearchAddress)
    {
        offset = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
        if (offset)
        {
            //
            // Get the data specified in the inf.
            //

            cbData = sizeof(data);

            if (CmpGetInfData(InfHandle, Description, RuleIndex, 1, data, &cbData))
            {
                (PCHAR)gSearchAddress += strtoul(offset, NULL, 16);

                //
                // Map in the physical address.
                //

                address = CmpMapPhysicalAddress(&baseAddress, (ULONG_PTR)gSearchAddress, cbData);
                if (address)
                {

                    //
                    // Check if the inf data matches data in memory.
                    //

                    match = (RtlCompareMemory(address, data, cbData) == cbData);

                    //
                    // Unmap the physical address.
                    //

                    ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
                }
            }
        }
    }

    return (match);
}

BOOLEAN
CmpMatchPointerRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
{
    BOOLEAN match = FALSE;
    PCHAR   segment1;
    PCHAR   offset1;
    PCHAR   segment2;
    PCHAR   offset2;
    PCHAR   index;
    PCHAR   op;
    CHAR    data[MAX_DESCRIPTION_LEN + 1];
    ULONG   cbData;
    ULONG   memory;
    ULONG   pointer;
    PVOID   baseAddress;
    PCHAR   address;

    segment1 = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
    offset1 = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
    segment2 = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 2);
    offset2 = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 3);
    index = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 4);
    op = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 5);

    if (    segment1 && offset1 &&
            segment2 && offset2 &&
            index && op)
    {
        //
        // Get the data specified in the inf.
        //

        cbData = sizeof(data);

        if (CmpGetInfData(InfHandle, Description, RuleIndex, 6, data, &cbData))
        {
            if (strlen(offset2) == 0)
            {
                memory = strtoul(segment2, NULL, 16) << 4;
            }
            else
            {
                memory = (strtoul(segment2, NULL, 16) << 4) + strtoul(offset2, NULL, 16);
            }

            address = CmpMapPhysicalAddress(&baseAddress, memory, 4);
            if (address)
            {
                pointer = *((PUSHORT)address);

                //
                // Unmap the physical address.
                //

                ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);

                if (strlen(offset1) == 0)
                {
                    memory = (strtoul(segment1, NULL, 16) << 4) + pointer;
                }
                else
                {
                    memory = (strtoul(segment1, NULL, 16) << 4) + strtoul(offset1, NULL, 16);
                    address = CmpMapPhysicalAddress(&baseAddress, memory, 2);
                    if (address)
                    {
                        memory = ((*(PUSHORT)address) << 4) + pointer;

                        //
                        // Unmap the physical address.
                        //

                        ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
                    }
                }

                memory += strtoul(index, NULL, 16);

                //
                // Map in the physical address.
                //

                address = CmpMapPhysicalAddress(&baseAddress, memory, cbData);
                if (address)
                {
                    match = CmpCheckOperator(op, (ULONG)RtlCompareMemory(address, data, cbData), cbData);

                    //
                    // Unmap the physical address.
                    //

                    ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
                }
            }
        }
    }

    return (match);
}

BOOLEAN
CmpMatchOemIdRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
{
    BOOLEAN         match = FALSE;
    ULONG           address;
    PCHAR           op;
    PCHAR           oemIdStr;
    ULONG           oemId;
    PCHAR           baseAddress;
    PPNP_BIOS_TABLE biosTable;

    //
    // Search for the PnPBIOS structure in the BIOS ROM.
    //

    address = CmpGetPnPBIOSTableAddress();

    //
    // Proceed if we found the PnP BIOS structure.
    //

    if (address)
    {
        op = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
        oemIdStr = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
        if (op && oemIdStr)
        {

            if (    strlen(oemIdStr) == 7 &&
                    isalpha(oemIdStr[0]) &&
                    isalpha(oemIdStr[1]) &&
                    isalpha(oemIdStr[2]) &&
                    isxdigit(oemIdStr[3]) &&
                    isxdigit(oemIdStr[4]) &&
                    isxdigit(oemIdStr[5]) &&
                    isxdigit(oemIdStr[6]))
            {

                biosTable = (PPNP_BIOS_TABLE)CmpMapPhysicalAddress(&baseAddress, address, sizeof(PNP_BIOS_TABLE));
                if (biosTable)
                {
                    oemId = ((ULONG)(oemIdStr[0] & 0x1F) << 26) +
                            ((ULONG)(oemIdStr[1] & 0x1F) << 21) +
                            ((ULONG)(oemIdStr[2] & 0x1F) << 16) +
                            strtoul(&oemIdStr[3], NULL, 16);

                    //
                    // We only support EQUAL and NOT EQUAL operators.
                    //

                    if (strcmp(op, "=") == 0 || strcmp(op, "==") == 0)
                    {
                        match = (oemId == biosTable->Oem);
                    }
                    else if(    strcmp(op, "<>") == 0 ||
                                strcmp(op, "!=") == 0 ||
                                strcmp(op, "=!") == 0)
                    {
                        match = (oemId != biosTable->Oem);
                    }

                    //
                    // Unmap the physical address.
                    //

                    ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
                }
            }
        }
    }

    return (match);
}

BOOLEAN
CmpMatchPModeRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
{
    BOOLEAN         match = FALSE;
    ULONG           address;
    CHAR            data[MAX_DESCRIPTION_LEN + 1];
    ULONG           cbData;
    PVOID           baseAddress;
    PPNP_BIOS_TABLE biosTable;
    ULONG           pmAddress;
    PCHAR           pmodeEntry;

    //
    // Search for the PnPBIOS structure in the BIOS ROM.
    //

    address = CmpGetPnPBIOSTableAddress();

    //
    // Proceed if we found the PnP BIOS structure.
    //

    if (address)
    {
        //
        // Get the data specified in the inf.
        //

        cbData = sizeof(data);
        if (CmpGetInfData(InfHandle, Description, RuleIndex, 0, data, &cbData))
        {
            biosTable = (PPNP_BIOS_TABLE)CmpMapPhysicalAddress(&baseAddress, address, sizeof(PNP_BIOS_TABLE));
            if (biosTable)
            {
                pmAddress = (biosTable->PMSegment << 4) + biosTable->PMOffset;

                //
                // Unmap the physical address.
                //

                ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);

                pmodeEntry = CmpMapPhysicalAddress(&baseAddress, pmAddress, SYSTEM_BIOS_LENGTH);
                if (pmodeEntry)
                {
                    if (*pmodeEntry == 0xE9)
                    {
                        pmodeEntry += (3 + (*((PUSHORT)&pmodeEntry[1])));
                    }

                    match = (RtlCompareMemory(pmodeEntry, data, cbData) == cbData);

                    //
                    // Unmap the physical address.
                    //

                    ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
                }
            }
        }
    }

    return (match);
}

BOOLEAN
CmpMatchRmPmSameRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
{
    BOOLEAN match = FALSE;
    ULONG           address;
    PCHAR           baseAddress;
    PPNP_BIOS_TABLE biosTable;

    //
    // Search for the PnPBIOS structure in the BIOS ROM.
    //

    address = CmpGetPnPBIOSTableAddress();

    //
    // Proceed if we found the PnP BIOS structure.
    //

    if (address)
    {
        biosTable = CmpMapPhysicalAddress(&baseAddress, address, sizeof(PNP_BIOS_TABLE));
        if (biosTable)
        {
            match = (   biosTable->RMSegment == biosTable->PMSegment &&
                        biosTable->RMOffset == biosTable->PMOffset);

            //
            // Unmap the physical address.
            //

            ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
        }
    }

    return (match);
}

BOOLEAN
CmpMatchInstallRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
{
    BOOLEAN match = FALSE;
    PCHAR   install;

    install = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
    if (install)
    {
        if (CmpGenInstall(InfHandle, install))
        {
            //
            // Successfully installed the specified section.
            //

            match = TRUE;
        }
    }

    return (match);
}

BOOLEAN
CmpMatchAcpiOemIdRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
/*++

Routine Description:

    This function processes a ACPI OEM ID rule from an INF file

    Examples:

        AcpiOemId="RSDT", "123456"

    is true if the RSDT has the OEM ID of 123456.

        AcpiOemId="DSDT", "768000"

    is true if the DSDT has the OEM ID of 768000.

Arguments:

    InfHandle - Handle of the inf containing the rule.

    Description - Specifies the section name the rule is in

    RuleIndex - Specifies the index of the rule in the section

Return Value:

    TRUE - the computer has the specified ACPI OEM ID.

    FALSE - the computer does not have the specified ACPI OEM ID.

--*/

{
    BOOLEAN             anyCase = FALSE;
    BOOLEAN             match = FALSE;
    PCHAR               tableName;
    PCHAR               oemId;
    PCHAR               optionalArgs;
    ULONG               length;
    PDESCRIPTION_HEADER header;
    CHAR                tableOemId[7];
    STRING              acpiString;
    STRING              tableString;

    tableName = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        0
        );
    oemId = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        1
        );
    if (tableName && oemId) {

        //
        // See if we have to do a case insensitive match
        //
        optionalArgs = CmpGetSectionLineIndex(
            InfHandle,
            Description,
            RuleIndex,
            2
            );
        if (optionalArgs) {

            if (_stricmp(optionalArgs,"any") == 0) {

                anyCase = TRUE;

            }

        }

        //
        // Find the specified table in the BIOS ROM.
        //
        header = CmpFindACPITable(*(PULONG)tableName, &length);
        if (header) {

            //
            // Build the OEM id from the table
            //
            RtlZeroMemory(tableOemId, sizeof(tableOemId));
            RtlCopyMemory(tableOemId, header->OEMID, sizeof(header->OEMID));
            RtlInitString( &tableString, tableOemId );

            //
            // And one from the string in the file
            //
            RtlInitString( &acpiString, oemId );

            //
            // Now see if they are equal
            //
            match = RtlEqualString( &acpiString, &tableString, anyCase );

            //
            // Unmap the table
            //
            MmUnmapIoSpace(header, length );

        }

    }
    return (match);
}

BOOLEAN
CmpMatchAcpiOemTableIdRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
/*++

Routine Description:

    This function processes a ACPI OEM Table ID rule from an INF file.

    Examples:

    AcpiOemTableId="RSDT", "12345678"

        is true if the RSDT has the Oem Table ID of 12345678.

    AcpiOemTableId="DSDT", "87654321"

        is true if the DSDT has the Oem Table ID of 87654321.

Arguments:

    InfHandle - Handle of the inf containing the rule.

    Description - Specifies the section name the rule is in

    RuleIndex - Specifies the index of the rule in the section

Return Value:

    TRUE - the computer has the specified ACPI OEM Table ID.

    FALSE - the computer does not have the specified ACPI OEM Table ID.

--*/

{
    BOOLEAN             match = FALSE;
    PCHAR               tableName;
    PCHAR               oemTableId;
    ULONG               length;
    PDESCRIPTION_HEADER header;
    ULONG               idLength;
    CHAR                acpiOemTableId[8];

    tableName = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        0
        );
    oemTableId = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        1
        );
    if (tableName && oemTableId) {

        //
        // Find the specified table in the BIOS ROM.
        //
        header = CmpFindACPITable(*(PULONG)tableName, &length);
        if (header) {

            RtlZeroMemory(acpiOemTableId, sizeof(acpiOemTableId));
            idLength = strlen(oemTableId);
            if (idLength > sizeof(acpiOemTableId)) {

                idLength = sizeof(acpiOemTableId);

            }
            RtlCopyMemory(acpiOemTableId, oemTableId, idLength);
            match = RtlEqualMemory(acpiOemTableId, header->OEMTableID, sizeof(header->OEMTableID));
            MmUnmapIoSpace( header, length );

        }

    }
    return (match);
}

BOOLEAN
CmpMatchAcpiOemRevisionRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
/*++

Routine Description:

    This function processes a ACPI Oem Revision rule from an INF file.

    Examples:

    AcpiOemRevision="=","RSDT", 1234

        is true if the RSDT has the Oem Revision EQUAL to 1234.

    AcpiOemRevision=">","DSDT", 4321

        is true if the DSDT has the Oem Revision GREATER than 4321.

Arguments:

    InfHandle - Handle of the inf containing the rule.

    Description - Specifies the section name the rule is in

    RuleIndex - Specifies the index of the rule in the section

Return Value:

    TRUE - the computer has the specified ACPI Oem Revision.

    FALSE - the computer does not have the specified ACPI Oem Revision.

--*/

{
    BOOLEAN             match = FALSE;
    PCHAR               op;
    PCHAR               tableName;
    PCHAR               oemRevisionStr;
    ULONG               oemRevision;
    ULONG               length;
    PDESCRIPTION_HEADER header;

    op = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        0
        );
    tableName = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        1
        );
    oemRevisionStr = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        2
        );
    if (op && tableName && oemRevisionStr) {

        //
        // Find the specified table.
        //
        header = CmpFindACPITable(*(PULONG)tableName, &length);
        if (header) {

            RtlCharToInteger(oemRevisionStr, 16, &oemRevision);
            match = CmpCheckOperator(op, header->OEMRevision, oemRevision);
            MmUnmapIoSpace(header, length);

        }

    }
    return(match);

}

BOOLEAN
CmpMatchAcpiRevisionRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
/*++

Routine Description:

    This function processes a ACPI Revision rule from an INF file.

    Examples:

        AcpiRevision="=", "RSDT", 1234

    is true if the RSDT ACPI Revision is EQUAL to 1234.

        AcpiRevision=">", "DSDT", 4321

    is true if the DSDT ACPI Revision is GREATER than 4321.

Arguments:

    InfHandle - Handle of the inf containing the rule.

    Description - Specifies the section name the rule is in

    RuleIndex - Specifies the index of the rule in the section

Return Value:

    TRUE - the computer has the specified ACPI Revision.

    FALSE - the computer does not have the specified ACPI Revision.

--*/

{
    BOOLEAN             match = FALSE;
    PCHAR               op;
    PCHAR               tableName;
    PCHAR               revisionStr;
    ULONG               revision;
    ULONG               length;
    PDESCRIPTION_HEADER header;

    op = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        0
        );
    tableName = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        1
        );
    revisionStr = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        2
        );
    if (op && tableName && revisionStr){

        //
        // Find the specified table.
        //
        header = CmpFindACPITable(*(PULONG)tableName, &length);
        if (header) {

            RtlCharToInteger(revisionStr, 16, &revision);
            match = CmpCheckOperator(op, header->Revision, revision);
            MmUnmapIoSpace(header, length);

        }

    }
    return(match);

}

BOOLEAN
CmpMatchAcpiCreatorRevisionRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
/*++

Routine Description:

    This function processes a ACPI Creator Revision rule from an INF file.

    Examples:

        AcpiCreatorRevision="=", "RSDT", 1234

    is true if the RSDT ACPI Creator Revision is EQUAL to 1234.

        AcpiCreatorRevision=">", "DSDT", 4321

    is true if the DSDT ACPI Creator Revision is GREATER than 4321.

Arguments:

    InfHandle - Handle of the inf containing the rule.

    Description - Specifies the section name the rule is in

    RuleIndex - Specifies the index of the rule in the section

Return Value:

    TRUE - the computer has the specified ACPI Creator Revision.

    FALSE - the computer does not have the specified ACPI Creator Revision.

--*/

{
    BOOLEAN             match = FALSE;
    PCHAR               op;
    PCHAR               tableName;
    PCHAR               creatorRevisionStr;
    ULONG               creatorRevision;
    ULONG               length;
    PDESCRIPTION_HEADER header;

    op = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        0
        );
    tableName = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        1
        );
    creatorRevisionStr = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        2
        );
    if (op && tableName && creatorRevisionStr) {

        //
        // Find the specified table.
        //
        header = CmpFindACPITable(*(PULONG)tableName, &length);
        if (header){

            RtlCharToInteger(creatorRevisionStr, 16, &creatorRevision);
            match = CmpCheckOperator(op, header->CreatorRev, creatorRevision);
            MmUnmapIoSpace( header, length );

        }

    }
    return(match);
}

BOOLEAN
CmpMatchAcpiCreatorIdRule(
    IN PVOID InfHandle,
    IN PCHAR Description,
    IN ULONG RuleIndex
    )
/*++

Routine Description:

    This function processes a ACPI Creator ID rule from an INF file.

    Examples:

        AcpiCreatorId="RSDT", "MSFT"

    is true if the RSDT has the Creator ID of MSFT.

Arguments:

    InfHandle - Handle of the inf containing the rule.

    Description - Specifies the section name the rule is in

    RuleIndex - Specifies the index of the rule in the section

Return Value:

    TRUE - the computer has the specified ACPI Creator ID.

    FALSE - the computer does not have the specified ACPI Creator ID.

--*/

{
    BOOLEAN             match = FALSE;
    PCHAR               tableName;
    PCHAR               creatorId;
    ULONG               length;
    PDESCRIPTION_HEADER header;
    ULONG               idLength;
    CHAR                acpiCreatorId[6];

    tableName = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        0
        );
    creatorId = CmpGetSectionLineIndex(
        InfHandle,
        Description,
        RuleIndex,
        1
        );
    if (tableName && creatorId) {

        //
        // Find the specified table.
        //
        header = CmpFindACPITable(*(PULONG)tableName, &length);
        if (header) {

            RtlZeroMemory(acpiCreatorId, sizeof(acpiCreatorId));
            idLength = strlen(creatorId);
            if (idLength > sizeof(acpiCreatorId)) {

                idLength = sizeof(acpiCreatorId);

            }
            RtlCopyMemory(acpiCreatorId, creatorId, idLength);
            match = RtlEqualMemory(acpiCreatorId, header->CreatorID, sizeof(header->CreatorID));
            MmUnmapIoSpace( header, length );

        }

    }
    return(match);
}

BOOLEAN
CmpGetInfData(
    IN PVOID InfHandle,
    IN PCHAR Section,
    IN ULONG LineIndex,
    IN ULONG ValueIndex,
    IN OUT PCHAR Buffer,
    IN OUT PULONG BufferSize
    )

/*++

    Routine Description:

        This routine reads and parses data from the inf. It understands
        two kinds of data 1. String 2. Binary.

        Examples-

        B,02 - byte 0x02
        B,72,0D,FF,0F - sequence of bytes 0x72 0x0D 0xFF 0x0F or the DWORD 0x0FFF0D72
        S,COMPAQ - ASCII string "COMPAQ"

    Input Parameters:

        InfHandle - Handle to the inf to be read.

        Section - Section name to be read.

        LineIndex - Index of the line in the Section to be read.

        ValueIndex - First value to be read on the LineIndex.

        Buffer - Parsed data gets returned in this buffer.

        BufferSize - On entry, contains the size of Buffer.
        The number of bytes parsed in gets returned in this
        variable.

    Return Value:

        TRUE iff data was parsed in successfully. Else FALSE.

--*/

{
    BOOLEAN result = FALSE;
    ULONG   cbData;
    PCHAR   data;
    ULONG   remainingBytes;

    //
    // Validate input parameters.
    //

    if (Buffer && BufferSize && *BufferSize)
    {
        //
        // Read in the data type "S" or "B".
        //

        PCHAR type = CmpGetSectionLineIndex(InfHandle, Section, LineIndex, ValueIndex++);
        if (type)
        {
            //
            // Initialize local data.
            //

            remainingBytes = *BufferSize;

            //
            // Process Binary data.
            //

            if (_stricmp(type, "B") == 0)
            {

                //
                // Parse data as long as there is more data and the buffer is not full.
                //

                for (result = TRUE; result == TRUE && remainingBytes; remainingBytes--)
                {
                    CHAR    value;

                    //
                    // Read in the data.
                    //

                    data = CmpGetSectionLineIndex(InfHandle, Section, LineIndex, ValueIndex++);
                    if (data)
                    {
                        //
                        // Convert the data read in and validate that is indeed a HEX value.
                        //

                        value = (CHAR)strtoul(data, NULL, 16);
                        if (value == 0 && strcmp(data, "00") && strcmp(data, "0"))
                        {
                            result = FALSE;
                        }
                        else
                        {
                            *Buffer++ = value;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                //
                // Return the number of bytes parsed in.
                //

                *BufferSize -= remainingBytes;
            }

            //
            // Process String data.
            //

            else if(_stricmp(type, "S") == 0)
            {
                //
                // Read in the string.
                //

                data = CmpGetSectionLineIndex(InfHandle, Section, LineIndex, ValueIndex);

                //
                // Only copy as much data as the buffer can hold.
                //

                cbData = min(remainingBytes, strlen(data));
                RtlCopyBytes(Buffer, data, cbData);

                //
                // Return the number of bytes actually copied.
                //

                *BufferSize = cbData;
                result = TRUE;
            }
        }
    }

    return (result);
}

PVOID
CmpMapPhysicalAddress(
    IN OUT PVOID *BaseAddress,
    IN ULONG_PTR Address,
    IN ULONG Size
    )

/*++

    Routine Description:

        This routine maps the specified physical segment into the process
        virtual memory.

    Input Parameters:

        Segment - Segment to be mapped.

        Size - Segment size to be mapped.

    Return Value:

        Virtual address for the mapped segment.

--*/

{
    UNICODE_STRING      sectionName;
    OBJECT_ATTRIBUTES   objectAttributes;
    HANDLE              sectionHandle;
    NTSTATUS            status;
    PVOID               baseAddress;
    SIZE_T              viewSize;
    LARGE_INTEGER       viewBase;
    PVOID               ptr = NULL;

    *BaseAddress = NULL;

    RtlInitUnicodeString(&sectionName, L"\\Device\\PhysicalMemory");
    InitializeObjectAttributes( &objectAttributes,
                                &sectionName,
                                OBJ_CASE_INSENSITIVE,
                                (HANDLE)NULL,
                                (PSECURITY_DESCRIPTOR)NULL);
    status = ZwOpenSection( &sectionHandle,
                            SECTION_MAP_READ,
                            &objectAttributes);
    if (NT_SUCCESS(status))
    {
        baseAddress = NULL;
        viewSize = Size;
        viewBase.QuadPart = Address & ~(0xFFF);
        status = ZwMapViewOfSection(    sectionHandle,
                                        NtCurrentProcess(),
                                        &baseAddress,
                                        0,
                                        viewSize,
                                        &viewBase,
                                        &viewSize,
                                        ViewUnmap,
                                        MEM_DOS_LIM,
                                        PAGE_READWRITE);
        if (NT_SUCCESS(status))
        {
            ptr = (PVOID)((PCHAR)baseAddress + (Address & 0xFFF));
            *BaseAddress = baseAddress;
        }
    }

    return (ptr);
}

    BOOLEAN
CmpCheckOperator(
    IN PCHAR Operator,
    IN ULONG Lhs,
    IN ULONG Rhs
    )

/*++

    Routine Description:

        This routine tests condition specified by the operator by
        applying it to the specified LHS and RHS arguments.

    Input Parameters:

        Operator - Is the operator to be tested.

        Lhs - Left Hand Side argument for the Operator.

        Rhs - Right Hand Side argument for the Operator.

    Return Value:

        True iff the condition Lhs Operator Rhs is satisfied.

--*/

{
    BOOLEAN result = FALSE;

    //
    // We are pretty lenient about which operators we support.
    //

    //
    // "=" or "==" for EQUAL.
    //

    if (strcmp(Operator, "=") == 0 || strcmp(Operator, "==") == 0)
    {
        result = (Lhs == Rhs);
    }

    //
    // "!=" or "=!" or "<>" for NOT EQUAL.
    //

    else if(    strcmp(Operator, "!=") == 0 ||
                strcmp(Operator, "<>") == 0 ||
                strcmp(Operator, "=!") == 0)
    {
        result = (Lhs != Rhs);
    }

    //
    // "<" for LESS THAN.
    //

    else if(strcmp(Operator, "<") == 0)
    {
        result = (Lhs < Rhs);
    }

    //
    // "<=" or "=<" for LESS THAN or EQUAL.
    //

    else if(strcmp(Operator, "<=") == 0 || strcmp(Operator, "=<") == 0)
    {
        result = (Lhs <= Rhs);
    }

    //
    // ">" for GREATER THAN.
    //

    else if(strcmp(Operator, ">") == 0)
    {
        result = (Lhs > Rhs);
    }

    //
    // ">=" or "=>" for GREATER THAN or EQUAL.
    //

    else if(strcmp(Operator, ">=") == 0 || strcmp(Operator, "=>") == 0)
    {
        result = (Lhs >= Rhs);
    }
    else
    {
#ifndef _CM_LDR_
        DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Invalid operator %s used!\n", Operator);
#endif //_CM_LDR_
    }

    return (result);
}

PVOID
CmpFindPattern(
    IN PCHAR Buffer,
    IN ULONG BufSize,
    IN PCHAR Pattern,
    IN ULONG PatSize,
    IN BOOLEAN IgnoreCase,
    IN ULONG Step
    )

/*++

    Routine Description:

        This routine searches the buffer for the specified pattern of data.

    Input Parameters:

        Buffer - Buffer to be searched.

        BufSize - Size of this buffer.

        Pattern - Pattern to be searched.

        PatSize - Size of the pattern.

        IgnoreCase - TRUE if the search is to be case insensitive.

    Return Value:

        Returns the pointer into the buffer where the pattern is first found.

--*/

{
    PCHAR   bufEnd;

    if (PatSize > BufSize)
    {
        return (NULL);
    }

    if (PatSize == 0)
    {
        PatSize = strlen(Pattern);
    }

    if (Step == 0)
    {
        Step = 1;
    }

    for (   bufEnd = Buffer + BufSize;
            Buffer + PatSize < bufEnd;
            Buffer += Step)
    {
        if (IgnoreCase)
        {
            if (_strnicmp(Buffer, Pattern, PatSize) == 0)
            {
                return (Buffer);
            }
        }
        else
        {
            if (strncmp(Buffer, Pattern, PatSize) == 0)
            {
                return (Buffer);
            }
        }
    }

    return (NULL);
 }

 ULONG
 CmpGetPnPBIOSTableAddress(
    VOID
    )

/*++

    Routine Description:

        This routine searches the BIOS ROM for the PnP BIOS installation
        structure.

    Input Parameters:

        None.

    Return Value:

        Returns the physical address in the ROM BIOS where the PnP
        BIOS structure is located.

--*/

{
    static ULONG    tableAddress = (ULONG)-1;
    PVOID           baseAddress;
    PPNP_BIOS_TABLE address;
    PPNP_BIOS_TABLE lastAddress;
    ULONG           i;
    ULONG           checksum;

    if (tableAddress == (ULONG)-1)
    {
        //
        // Search for the PnPBIOS structure in the BIOS ROM.
        //

        address = (PPNP_BIOS_TABLE)CmpMapPhysicalAddress(&baseAddress, 0xF0000, SYSTEM_BIOS_LENGTH);
        if (address)
        {
            for (   lastAddress = (PPNP_BIOS_TABLE)((PCHAR)address + SYSTEM_BIOS_LENGTH - 0x10);
                    address < lastAddress;
                    (PCHAR)address += 0x10)
            {
                if (address->Signature == PNPBIOS_SIGNATURE)
                {
                    for (   i = 0, checksum = 0;
                            i < address->Length;
                            i++)
                    {
                        checksum += ((PUCHAR)address)[i];
                    }

                    if (    (checksum & 0xFF) == 0 &&
                            address->Length >= 0x21)
                    {
                        tableAddress = 0xF0000 + (SYSTEM_BIOS_LENGTH - 10) - (ULONG)((PCHAR)lastAddress - (PCHAR)address);
                        break;
                    }
                }
            }

            //
            // Unmap the physical address.
            //

            ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
        }
    }

    return (tableAddress);
}

PDESCRIPTION_HEADER
CmpFindACPITable(
    IN ULONG        Signature,
    IN OUT PULONG   Length
    )
{
    PDESCRIPTION_HEADER     header      = NULL;
    PDESCRIPTION_HEADER     tempHeader  = NULL;
    static PHYSICAL_ADDRESS rsdtAddress = { -1, -1 };
    ULONG                   length      = 0;

    //
    // Use the cached location of RSDT address if available.
    //
    if (rsdtAddress.QuadPart == -1) {

        NTSTATUS                status;
        PACPI_BIOS_MULTI_NODE   rsdpMulti;

        rsdtAddress.QuadPart = 0;
        //
        // Get the multinode
        //
        status = CmpFindRSDTTable( &rsdpMulti );
        if (!NT_SUCCESS(status)) {

            return NULL;

        }

        //
        // Map the address
        //
        rsdtAddress.LowPart = rsdpMulti->RsdtAddress.LowPart;
        rsdtAddress.HighPart = rsdpMulti->RsdtAddress.HighPart;

        //
        // Done with the multinode
        //
        ExFreePool( rsdpMulti );

    }

    //
    // If we have an address
    //
    if (rsdtAddress.QuadPart) {

        //
        // Map in the the rsdt table
        //
        tempHeader = MmMapIoSpace(
            rsdtAddress,
            sizeof(DESCRIPTION_HEADER),
            MmCached
            );
        if (tempHeader == NULL) {

#ifndef _CM_LDR_
            DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpFindACPITable: Cannot map RSDT at %I64x\n", rsdtAddress.QuadPart);
#endif //_CM_LDR_
            return NULL;

        }

        //
        // If what we are looking for is the RSDT, then we are done
        //
        if (Signature == RSDT_SIGNATURE) {

            header = tempHeader;
            length = sizeof(DESCRIPTION_HEADER);

        } else if (Signature == DSDT_SIGNATURE) {

            PFADT               fadt;
            PHYSICAL_ADDRESS    dsdtAddress;
            ULONG               tempLength;

            fadt = (PFADT) CmpFindACPITable( FADT_SIGNATURE, &length );
            if (fadt) {

                dsdtAddress.HighPart = 0;
                dsdtAddress.LowPart = fadt->dsdt;

                //
                // Done with the FADT
                //
                MmUnmapIoSpace( fadt, length );

                //
                // Map in the dsdt table
                //
                header = MmMapIoSpace(
                    dsdtAddress,
                    sizeof(DESCRIPTION_HEADER),
                    MmCached
                    );
                if (header == NULL) {

#ifndef _CM_LDR_
                    DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,
                        "CmpFindACPITable: Cannot map DSDT at %I64x\n",
                        dsdtAddress.QuadPart
                        );
#endif //_CM_LDR_
                    MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
                    return NULL;

                }
                length = sizeof(DESCRIPTION_HEADER);

            } else {

#ifndef _CM_LDR_
                DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpFindACPITable: Cannot find FADT\n");
#endif //_CM_LDR_
                MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
                return NULL;

            }

        } else {

            PHYSICAL_ADDRESS    tableAddress;
            PRSDT               rsdt;
            ULONG               i;
            ULONG               num;
            ULONG               rsdtLength;

            //
            // Map in the entire RSDT
            //
            rsdtLength = tempHeader->Length;
            rsdt = (PRSDT) MmMapIoSpace( rsdtAddress, rsdtLength, MmCached );
            if (rsdt == NULL) {

#ifndef _CM_LDR_
                DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,
                    "CmpFindACPITable: Cannot map RSDT at %I64x\n",
                    rsdtAddress.QuadPart
                    );
#endif //_CM_LDR_
                MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
                return NULL;

            }

            //
            // Done with the temp header
            //
            MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );

            //
            // Look at all the table entries for the header that we care about
            //
            num = TABLE_ENTRIES_FROM_RSDT_POINTER( rsdt );
            for (i = 0; i < num ; i ++) {

                //
                // Get the address of the table
                //
                tableAddress.HighPart = 0;
                tableAddress.LowPart = rsdt->Tables[i];

                //
                // Map in the header
                //
                tempHeader = MmMapIoSpace(
                    tableAddress,
                    sizeof(DESCRIPTION_HEADER),
                    MmCached
                    );
                if (!tempHeader) {

#ifndef _CM_LDR_
                    DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,
                        "CmpFindACPITable: Cannot map header at %I64x\n",
                        tableAddress.QuadPart
                        );
#endif //_CM_LDR_
                    MmUnmapIoSpace( rsdt, rsdtLength );
                    return NULL;

                }

                //
                // Signature check
                //
                if (tempHeader->Signature != Signature) {

                    MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
                    continue;

                }

                //
                // Are we looking at the FADT?
                //
                if (Signature == FADT_SIGNATURE) {

                    //
                    // Map the entire table for this one
                    //
                    length = tempHeader->Length;
                    header = MmMapIoSpace( tableAddress, length, MmCached );

                    //
                    // Unmap the old table
                    //
                    MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );

                    //
                    // Did we successfully map the header?
                    //
                    if (header == NULL ) {

#ifndef _CM_LDR_
                        DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,
                            "CmpFindACPITable: Cannot map FADT at %I64x\n",
                            tableAddress.QuadPart
                            );
#endif //_CM_LDR_
                        MmUnmapIoSpace( rsdt, rsdtLength );
                        return NULL;

                    }

                } else {

                    //
                    // Remember where the table and length are stored
                    //
                    length = sizeof(DESCRIPTION_HEADER);
                    header = tempHeader;

                }

            } // for

            //
            // Done with the rsdt
            //
            MmUnmapIoSpace( rsdt, rsdtLength );

        }

        //
        // If we found the table, return its length.
        //
        if (Length) {

            if (header) {

                *Length = length;

            } else {

                *Length = 0;

            }

        }

    }

    return (header);
}

NTSTATUS
CmpFindRSDTTable(
    OUT PACPI_BIOS_MULTI_NODE   *Rsdt
    )
/*++

Routine Description:

    This function looks into the registry to find the ACPI RSDT,
    which was stored there by ntdetect.com

Arguments:

    RsdtPtr - Pointer to a buffer that contains the ACPI
              Root System Description Pointer Structure.
              The caller is responsible for freeing this
              buffer.  Note:  This is returned in non-paged
              pool.

Return Value:

    A NTSTATUS code to indicate the result of the initialization.

--*/
{
    BOOLEAN                         same;
    HANDLE                          hMFunc;
    HANDLE                          hBus;
    NTSTATUS                        status;
    OBJECT_ATTRIBUTES               objectAttributes;
    PACPI_BIOS_MULTI_NODE           multiNode;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
    PCM_PARTIAL_RESOURCE_LIST       prl;
    PKEY_VALUE_PARTIAL_INFORMATION  valueInfo;
    PWSTR                           p;
    ULONG                           i;
    ULONG                           length;
    ULONG                           multiNodeSize;
    UNICODE_STRING                  unicodeString;
    UNICODE_STRING                  unicodeValueName;
    UNICODE_STRING                  biosId;
    WCHAR                           wbuffer[10];

    PAGED_CODE();

    //
    // Look in the registry for the "ACPI BIOS bus" data
    //
    RtlInitUnicodeString( &unicodeString, rgzMultiFunctionAdapter );
    InitializeObjectAttributes(
        &objectAttributes,
        &unicodeString,
        OBJ_CASE_INSENSITIVE,
        NULL,       // handle
        NULL
        );
    status = ZwOpenKey( &hMFunc, KEY_READ, &objectAttributes );
    if (!NT_SUCCESS(status)) {

#ifndef _CM_LDR_
        DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_WARNING_LEVEL,"CmpFindRSDTTable: Cannot open MultifunctionAdapter registry key.\n");
#endif //_CM_LDR_
        return status;

    }

    //
    // We will need to make a unicode string that we can use to enumerate
    // the subkeys of the MFA key
    //
    unicodeString.Buffer = wbuffer;
    unicodeString.MaximumLength = sizeof(wbuffer);
    RtlInitUnicodeString( &biosId, rgzBIOSIdentifier );

    //
    // Loop over all subkeys
    //
    for (i = 0; TRUE; i++) {

        //
        // Turn the number into a key name
        //
        RtlIntegerToUnicodeString( i, 10, &unicodeString);
        InitializeObjectAttributes(
            &objectAttributes,
            &unicodeString,
            OBJ_CASE_INSENSITIVE,
            hMFunc,
            NULL
            );

        //
        // Open the named subkey
        //
        status = ZwOpenKey( &hBus, KEY_READ, &objectAttributes );
        if (!NT_SUCCESS(status)) {

            //
            // Out of Multifunction adapter entries...
            //
#ifndef _CM_LDR_
            DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_WARNING_LEVEL,"CmpFindRSDTTable: ACPI BIOS MultifunctionAdapter registry key not found.\n");
#endif //_CM_LDR_
            ZwClose (hMFunc);
            return STATUS_UNSUCCESSFUL;

        }

        //
        // Check the Indentifier to see if this is an ACPI BIOS entry
        //
        status = CmpGetRegistryValue( hBus, (PWCHAR)rgzAcpiIdentifier, &valueInfo );
        if (!NT_SUCCESS (status)) {

            ZwClose( hBus );
            continue;

        }

        p = (PWSTR) ((PUCHAR) valueInfo->Data);
        unicodeValueName.Buffer = p;
        unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength;
        length = valueInfo->DataLength;

        //
        // Determine the real length of the ID string
        //
        while (length) {

            if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) {

                length -= 2;

            } else {

                break;
            }

        }

        //
        // Do we have a match the "ACPI BIOS" identifier?
        //
        unicodeValueName.Length = (USHORT)length;
        same = RtlEqualUnicodeString( &biosId, &unicodeValueName, TRUE );
        ExFreePool( valueInfo );
        if (!same) {

            ZwClose( hBus );
            continue;

        }

        //
        // We do, so get the configuration data
        //
        status = CmpGetRegistryValue(
            hBus,
            (PWCHAR)rgzAcpiConfigurationData,
            &valueInfo
            );
        ZwClose( hBus );
        if (!NT_SUCCESS(status)) {

            continue ;

        }

        //
        // The data that we want is at the end of the PARTIAL_RESOURCE_LIST
        // descriptor
        //
        prl = (PCM_PARTIAL_RESOURCE_LIST)(valueInfo->Data);
        prd = &prl->PartialDescriptors[0];
        multiNode = (PACPI_BIOS_MULTI_NODE)
            ( (PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST) );
        break;

    }

    //
    // Calculate the size of the data so that we can make a copy
    //
    multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) +
        ( (ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY) );
    *Rsdt = (PACPI_BIOS_MULTI_NODE) ExAllocatePoolWithTag(
        NonPagedPool,
        multiNodeSize,
        'IPCA'
        );
    if (*Rsdt == NULL) {

        ExFreePool( valueInfo );
        return STATUS_INSUFFICIENT_RESOURCES;

    }
    RtlCopyMemory(*Rsdt, multiNode, multiNodeSize);

    //
    // Done with the key memory
    //
    ExFreePool(valueInfo);

    //
    // Done
    //
    return STATUS_SUCCESS;
}

NTSTATUS
CmpGetRegistryValue(
    IN  HANDLE                          KeyHandle,
    IN  PWSTR                           ValueName,
    OUT PKEY_VALUE_PARTIAL_INFORMATION  *Information
    )
/*++

Routine Description:

    This routine is invoked to retrieve the data for a registry key's value.
    This is done by querying the value of the key with a zero-length buffer
    to determine the size of the value, and then allocating a buffer and
    actually querying the value into the buffer.

    It is the responsibility of the caller to free the buffer.

Arguments:

    KeyHandle - Supplies the key handle whose value is to be queried

    ValueName - Supplies the null-terminated Unicode name of the value.

    Information - Returns a pointer to the allocated data buffer.

Return Value:

    The function value is the final status of the query operation.

--*/

{
    NTSTATUS                        status;
    PKEY_VALUE_PARTIAL_INFORMATION  infoBuffer;
    ULONG                           keyValueLength;
    UNICODE_STRING                  unicodeString;

    PAGED_CODE();

    RtlInitUnicodeString( &unicodeString, ValueName );

    //
    // Figure out how big the data value is so that a buffer of the
    // appropriate size can be allocated.
    //
    status = ZwQueryValueKey(
        KeyHandle,
        &unicodeString,
        KeyValuePartialInformation,
        (PVOID) NULL,
        0,
        &keyValueLength
        );
    if (status != STATUS_BUFFER_OVERFLOW &&
        status != STATUS_BUFFER_TOO_SMALL) {

        return status;

    }

    //
    // Allocate a buffer large enough to contain the entire key data value.
    //
    infoBuffer = ExAllocatePoolWithTag(
        NonPagedPool,
        keyValueLength,
        'IPCA'
        );
    if (!infoBuffer) {

        return STATUS_INSUFFICIENT_RESOURCES;

    }

    //
    // Query the data for the key value.
    //
    status = ZwQueryValueKey(
        KeyHandle,
        &unicodeString,
        KeyValuePartialInformation,
        infoBuffer,
        keyValueLength,
        &keyValueLength
        );
    if (!NT_SUCCESS( status )) {

        ExFreePool( infoBuffer );

        return status;

    }

    //
    // Everything worked, so simply return the address of the allocated
    // buffer to the caller, who is now responsible for freeing it.
    //
    *Information = infoBuffer;
    return STATUS_SUCCESS;

}
