/*++

Copyright (c) 1990, 1991  Microsoft Corporation


Module Name:

    init386.c

Abstract:

    This module is responsible to build any x86 specific entries in
    the hardware tree of registry.

Author:

    Ken Reneris (kenr) 04-Aug-1992


Environment:

    Kernel mode.

Revision History:

    shielint - add BIOS date and version detection.

--*/

#include "cmp.h"
#include "stdio.h"
#include "smbios.h"


//
// Title Index is set to 0.
// (from ..\cmconfig.c)
//

#define TITLE_INDEX_VALUE 0

extern PCHAR SearchStrings[];
extern PCHAR BiosBegin;
extern PCHAR Start;
extern PCHAR End;
extern UCHAR CmpID[];
extern WCHAR CmpVendorID[];
extern WCHAR CmpProcessorNameString[];
extern WCHAR CmpFeatureBits[];
extern WCHAR CmpMHz[];
extern WCHAR CmpUpdateSignature[];
extern UCHAR CmpIntelID[];
extern UCHAR CmpItanium[];
extern UCHAR CmpMcKinley[];
extern UCHAR CmpIA64Proc[];

//
// Bios date and version definitions
//

#define BIOS_DATE_LENGTH 64
#define MAXIMUM_BIOS_VERSION_LENGTH 128

WCHAR   SystemBIOSDateString[BIOS_DATE_LENGTH];
WCHAR   SystemBIOSVersionString[MAXIMUM_BIOS_VERSION_LENGTH];
WCHAR   VideoBIOSDateString[BIOS_DATE_LENGTH];
WCHAR   VideoBIOSVersionString[MAXIMUM_BIOS_VERSION_LENGTH];

//
// Extended CPUID function definitions
//

#define CPUID_PROCESSOR_NAME_STRING_SZ  65
#define CPUID_EXTFN_BASE                0x80000000
#define CPUID_EXTFN_PROCESSOR_NAME      0x80000002


extern ULONG CmpConfigurationAreaSize;
extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;


BOOLEAN
CmpGetBiosVersion (
    PCHAR SearchArea,
    ULONG SearchLength,
    PCHAR VersionString
    );

BOOLEAN
CmpGetBiosDate (
    PCHAR SearchArea,
    ULONG SearchLength,
    PCHAR DateString
    );

ULONG
Ke386CyrixId (
    VOID
    );

VOID
InitializeProcessorInformationFromSMBIOS(
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpInitializeMachineDependentConfiguration)
#pragma alloc_text(INIT,InitializeProcessorInformationFromSMBIOS)
#endif


#if 0
//
// Use SMBIOS to gather this information.
//

BOOLEAN
CmpGetBiosDate (
    PCHAR SearchArea,
    ULONG SearchLength,
    PCHAR DateString
    )

/*++

Routine Description:

    This routine finds the most recent date in the computer/video
    card's ROM.  When GetRomDate encounters a datae, it checks the
    previously found date to see if the new date is more recent.

Arguments:

    SearchArea - the area to search for a date.

    SearchLength - Length of search.

    DateString - Supplies a pointer to a fixed length memory to receive
                 the date string.

Return Value:

    NT_SUCCESS if a date is found.

--*/

{
    BOOLEAN FoundFlag = TRUE;        // Set to TRUE if the item was found
    CHAR PrevDate[BIOS_DATE_LENGTH]; // Date currently being examined
    CHAR CurrDate[BIOS_DATE_LENGTH]; // Date currently being examined
    PCHAR String;
    USHORT i;                        // Looping variable
    USHORT Length;                   // Number of characters to move
    PCHAR Start = SearchArea + 2;
    PCHAR End = SearchArea + SearchLength - 5;

    //
    // Clear out the previous date
    //

    RtlZeroMemory(PrevDate, BIOS_DATE_LENGTH);

    while (FoundFlag) {

        String = NULL;

        //
        // Search for '/' with a digit on either side and another
        // '/' 3 character away.
        //

        while (Start < End) {
            if (*Start == '/' && *(Start+3) == '/' &&
                (*(Start+1) <= '9' && *(Start+1) >= '0') &&
                (*(Start-1) <= '9' && *(Start-1) >= '0') &&
                (*(Start+5) <= '9' && *(Start+5) >= '0') &&
                (*(Start+4) <= '9' && *(Start+4) >= '0') &&
                (*(Start+2) <= '9' && *(Start+2) >= '0')) {

                String = Start;
                break;
            } else {
                Start++;
            }
        }

        if (String) {
            Start = String + 3;
            String -= 2;                 // Move String to the beginning of
                                         //   date.
            //
            // Copy the year into CurrDate
            //

            CurrDate[0] = String[6];
            CurrDate[1] = String[7];
            CurrDate[2] = '/';           // The 1st "/" for YY/MM/DD

            //
            // Copy the month & day into CurrDate
            //   (Process properly if this is a one digit month)
            //

            if (*String > '9' || *String < '0') {
                CurrDate[3] = '0';
                String++;
                i = 4;
                Length = 4;
            } else {
                i = 3;
                Length = 5;
            }

            RtlMoveMemory(&CurrDate[i], String, Length);

            //
            // Compare the dates, to see which is more recent
            //

            if (memcmp (PrevDate, CurrDate, BIOS_DATE_LENGTH - 1) < 0) {
                RtlMoveMemory(PrevDate, CurrDate, BIOS_DATE_LENGTH - 1);
            }
        } else {
            FoundFlag = FALSE;
        }
    }

    //
    // If we did not find a date
    //

    if (PrevDate[0] == '\0') {
        DateString[0] = '\0';
        return (FALSE);
    }

    //
    // Put the date from chPrevDate's YY/MM/DD format
    //   into pchDateString's MM/DD/YY format

    DateString[5] = '/';
    DateString[6] = PrevDate[0];
    DateString[7] = PrevDate[1];
    RtlMoveMemory(DateString, &PrevDate[3], 5);
    DateString[8] = '\0';

    return (TRUE);
}

BOOLEAN
CmpGetBiosVersion (
    PCHAR SearchArea,
    ULONG SearchLength,
    PCHAR VersionString
    )

/*++

Routine Description:

    This routine finds the version number stored in ROM, if any.

Arguments:

    SearchArea - the area to search for the version.

    SearchLength - Length of search

    VersionString - Supplies a pointer to a fixed length memory to receive
                 the version string.

Return Value:

    TRUE if a version number is found.  Else a value of FALSE is returned.

--*/
{
    PCHAR String;
    USHORT Length;
    USHORT i;
    CHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH];
    PCHAR BufferPointer;

        if (SearchArea != NULL) {

        //
        // If caller does not specify the search area, we will search
        // the area left from previous search.
        //

        BiosBegin = SearchArea;
        Start = SearchArea + 1;
        End = SearchArea + SearchLength - 2;
    }

    while (1) {

         //
         // Search for a period with a digit on either side
         //

         String = NULL;
         while (Start <= End) {
             if (*Start == '.' && *(Start+1) >= '0' && *(Start+1) <= '9' &&
                 *(Start-1) >= '0' && *(Start-1) <= '9') {
                 String = Start;
                 break;
             } else {
                 Start++;
             }
         }

         if (Start > End) {
             return(FALSE);
         } else {
             Start += 2;
         }

         Length = 0;
         Buffer[MAXIMUM_BIOS_VERSION_LENGTH - 1] = '\0';
         BufferPointer = &Buffer[MAXIMUM_BIOS_VERSION_LENGTH - 1];

         //
         // Search for the beginning of the string
         //

         String--;
         while (Length < MAXIMUM_BIOS_VERSION_LENGTH - 8 &&
                String >= BiosBegin &&
                *String >= ' ' && *String <= 127 &&
                *String != '$') {
             --BufferPointer;
             *BufferPointer = *String;
             --String, ++Length;
         }
         ++String;

         //
         // Can one of the search strings be found
         //

         for (i = 0; SearchStrings[i]; i++) {
             if (strstr(BufferPointer, SearchStrings[i])) {
                 goto Found;
             }
         }
    }

Found:

    //
    // Skip leading white space
    //

    for (; *String == ' '; ++String)
      ;

    //
    // Copy the string to user supplied buffer
    //

    for (i = 0; i < MAXIMUM_BIOS_VERSION_LENGTH - 1 &&
         String <= (End + 1) &&
         *String >= ' ' && *String <= 127 && *String != '$';
         ++i, ++String) {
         VersionString[i] = *String;
    }
    VersionString[i] = '\0';
    return (TRUE);
}

#endif  // #if 0





NTSTATUS
CmpInitializeMachineDependentConfiguration(
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    )
/*++

Routine Description:

    This routine creates IA64 specific entries in the registry.

Arguments:

    LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
                  OS Loader.

Returns:

    NTSTATUS code for sucess or reason of failure.

--*/
{
    NTSTATUS Status;
    ULONG VideoBiosStart;
    UNICODE_STRING KeyName;
    UNICODE_STRING ValueName;
    UNICODE_STRING ValueData;
    ANSI_STRING AnsiString;
    OBJECT_ATTRIBUTES ObjectAttributes;
    ULONG Disposition;
    HANDLE ParentHandle;
    HANDLE BaseHandle, NpxHandle;
    HANDLE CurrentControlSet;
    CONFIGURATION_COMPONENT_DATA CurrentEntry;
    PUCHAR VendorID;
    UCHAR  Buffer[MAXIMUM_BIOS_VERSION_LENGTH];
    PKPRCB Prcb;
    ULONG  i, Junk;
    ULONG VersionsLength = 0, Length;
    PCHAR VersionStrings, VersionPointer;
    UNICODE_STRING SectionName;
    ULONG ViewSize;
    LARGE_INTEGER ViewBase;
    PVOID BaseAddress;
    USHORT DeviceIndexTable[NUMBER_TYPES];
    ULONG CpuIdFunction;
    ULONG MaxExtFn;
    PULONG NameString = NULL;
    ULONG ReturnedLength;
    struct {
        union {
            UCHAR   Bytes[CPUID_PROCESSOR_NAME_STRING_SZ];
            ULONG   DWords[1];
        } u;
    } ProcessorNameString;

    for (i = 0; i < NUMBER_TYPES; i++) {
        DeviceIndexTable[i] = 0;
    }


    //
    // Go get a bunch of information out of SMBIOS
    //
    InitializeProcessorInformationFromSMBIOS(LoaderBlock);



    InitializeObjectAttributes( &ObjectAttributes,
                                &CmRegistryMachineHardwareDescriptionSystemName,
                                OBJ_CASE_INSENSITIVE,
                                NULL,
                                NULL
                              );

    Status = NtOpenKey( &ParentHandle,
                        KEY_READ,
                        &ObjectAttributes
                      );

    if (!NT_SUCCESS(Status)) {
        // Something is really wrong...
        return Status;
    }


    //
    // On an ARC machine the processor(s) are included in the hardware
    // configuration passed in from bootup.  Since there's no standard
    // way to get all the ARC information for each processor in an MP
    // machine via pc-ROMs the information will be added here (if it's
    // not already present).
    //

    RtlInitUnicodeString( &KeyName,
                          L"CentralProcessor"
                        );

    InitializeObjectAttributes(
        &ObjectAttributes,
        &KeyName,
        0,
        ParentHandle,
        NULL
        );

    ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;

    Status = NtCreateKey(
                &BaseHandle,
                KEY_READ | KEY_WRITE,
                &ObjectAttributes,
                TITLE_INDEX_VALUE,
                &CmClassName[ProcessorClass],
                0,
                &Disposition
                );

    NtClose (BaseHandle);

    if (Disposition == REG_CREATED_NEW_KEY) {

        //
        // The ARC rom didn't add the processor(s) into the registry.
        // Do it now.
        //

        CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
                                            PagedPool,
                                            CmpConfigurationAreaSize
                                            );

        if (CmpConfigurationData == NULL) {
            // bail out
            NtClose (ParentHandle);
            return(STATUS_INSUFFICIENT_RESOURCES);
        }

        for (i=0; i < (ULONG)KeNumberProcessors; i++) {
            Prcb = KiProcessorBlock[i];

            RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry);
            CurrentEntry.ComponentEntry.Class = ProcessorClass;
            CurrentEntry.ComponentEntry.Type = CentralProcessor;
            CurrentEntry.ComponentEntry.Key = i;
            CurrentEntry.ComponentEntry.AffinityMask = AFFINITY_MASK(i);

            CurrentEntry.ComponentEntry.Identifier = Buffer;

            sprintf( Buffer, CmpID,
                     Prcb->ProcessorFamily,
                     Prcb->ProcessorModel,
                     Prcb->ProcessorRevision
                   );

            CurrentEntry.ComponentEntry.IdentifierLength =
                strlen (Buffer) + 1;

            Status = CmpInitializeRegistryNode(
                &CurrentEntry,
                ParentHandle,
                &BaseHandle,
                -1,
                (ULONG)-1,
                DeviceIndexTable
                );

            if (!NT_SUCCESS(Status)) {
                return(Status);
            }

            VendorID = Prcb->ProcessorVendorString;
            if ( *VendorID == '\0' ) {
               VendorID = NULL;
            }

            if (VendorID) {

                //
                // Add Vendor Indentifier to the registry
                //

                RtlInitUnicodeString(
                    &ValueName,
                    CmpVendorID
                    );

                RtlInitAnsiString(
                    &AnsiString,
                    VendorID
                    );

                RtlAnsiStringToUnicodeString(
                    &ValueData,
                    &AnsiString,
                    TRUE
                    );

                Status = NtSetValueKey(
                            BaseHandle,
                            &ValueName,
                            TITLE_INDEX_VALUE,
                            REG_SZ,
                            ValueData.Buffer,
                            ValueData.Length + sizeof( UNICODE_NULL )
                            );

                RtlFreeUnicodeString(&ValueData);
            }

            if ( VendorID && !strcmp( VendorID, CmpIntelID ) )   {

                ULONG processorModel;
                PUCHAR processorNameString = CmpItanium;

                //
                // Add Processor Name String to the registry
                //

                RtlInitUnicodeString(
                    &ValueName,
                    CmpProcessorNameString
                    );

                //
                // ISSUE-2000/02/10-v-thief - Pseudo cases to be updated when known.
                //

                processorModel = Prcb->ProcessorModel;
                switch( processorModel )  {
                   case 1: // Pseudo-Itanium:
                      break;

                   case 2: // Pseudo-McKinley:
                      processorNameString = CmpMcKinley;
                      break;

                   default:
                      processorNameString = CmpIA64Proc;
                      break;
                }

                RtlInitAnsiString(
                    &AnsiString,
                    processorNameString
                    );

                RtlAnsiStringToUnicodeString(
                    &ValueData,
                    &AnsiString,
                    TRUE
                    );

                Status = NtSetValueKey(
                            BaseHandle,
                            &ValueName,
                            TITLE_INDEX_VALUE,
                            REG_SZ,
                            ValueData.Buffer,
                            ValueData.Length + sizeof( UNICODE_NULL )
                            );

                RtlFreeUnicodeString(&ValueData);

            }


//
// If more processor IDs have to be restored or initialized,
// check non-IA64 implementations of this function.
//


            if ( Prcb->ProcessorFeatureBits ) {

                //
                // Add processor feature bits to the registry
                //

                RtlInitUnicodeString(
                    &ValueName,
                    CmpFeatureBits
                    );

                Status = NtSetValueKey(
                            BaseHandle,
                            &ValueName,
                            TITLE_INDEX_VALUE,
                            REG_QWORD,
                            &Prcb->ProcessorFeatureBits,
                            sizeof( Prcb->ProcessorFeatureBits )
                            );
            }


            if (Prcb->MHz) {
                //
                // Add processor MHz to the registry
                //

                RtlInitUnicodeString(
                    &ValueName,
                    CmpMHz
                    );

                Status = NtSetValueKey(
                            BaseHandle,
                            &ValueName,
                            TITLE_INDEX_VALUE,
                            REG_DWORD,
                            &Prcb->MHz,
                            sizeof (Prcb->MHz)
                            );
            }


#if 0

//
// ISSUE-2000/02/01-v-thief
//

            if ( Prcb->ProcessorUpdateSignature ) {

                //
                // Add processor Update Signature to the registry
                //

                RtlInitUnicodeString(
                    &ValueName,
                    CmpUpdateSignature
                    );

                Status = NtSetValueKey(
                            BaseHandle,
                            &ValueName,
                            TITLE_INDEX_VALUE,
                            REG_BINARY,
                            &Prcb->ProcessorUpdateSignature,
                            sizeof( Prcb->ProcessorUpdateSignature )
                            );
            }

#endif // 0
            //
            // Add ia32 floating point enties for iVE.
            //
            RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry);
            CurrentEntry.ComponentEntry.Class = ProcessorClass;
            CurrentEntry.ComponentEntry.Type = FloatingPointProcessor;
            CurrentEntry.ComponentEntry.Key = i;
            CurrentEntry.ComponentEntry.AffinityMask = AFFINITY_MASK(i);

            CurrentEntry.ComponentEntry.Identifier = Buffer;

            //
            // The iVE is defined to look like the Pentium III FP
            // This is the value returned by the ia32 CPUID instruction
            // on Merced (Itanium)
            //
            strcpy (Buffer, "x86 Family 7 Model 0 Stepping 0");

            CurrentEntry.ComponentEntry.IdentifierLength =
                strlen (Buffer) + 1;

            Status = CmpInitializeRegistryNode(
                &CurrentEntry,
                ParentHandle,
                &NpxHandle,
                -1,
                (ULONG)-1,
                DeviceIndexTable
                );


            //
            // How odd. Some calls check the status return value
            // and others don't. Is this based on required vs. optional
            // keys? For the moment, since it was checked on the i386
            // then do the check here too...
            //
            if (!NT_SUCCESS(Status)) {
                NtClose(BaseHandle);
                return(Status);
            }

            //
            // Only need to close the handle if we succeeded
            //
            NtClose(NpxHandle);

            NtClose(BaseHandle);
        }

        ExFreePool((PVOID)CmpConfigurationData);
    }


    //
    // Next we try to collect System BIOS date and version strings.
    //
    if( SystemBIOSDateString[0] != 0 ) {

        RtlInitUnicodeString(
            &ValueName,
            L"SystemBiosDate"
            );

        Status = NtSetValueKey(
                    ParentHandle,
                    &ValueName,
                    TITLE_INDEX_VALUE,
                    REG_SZ,
                    SystemBIOSDateString,
                    (wcslen(SystemBIOSDateString)+1) * sizeof( WCHAR )
                    );

    }

    if( SystemBIOSVersionString[0] != 0 ) {

        RtlInitUnicodeString(
            &ValueName,
            L"SystemBiosVersion"
            );

        Status = NtSetValueKey(
                    ParentHandle,
                    &ValueName,
                    TITLE_INDEX_VALUE,
                    REG_SZ,
                    SystemBIOSVersionString,
                    (wcslen(SystemBIOSVersionString)+1) * sizeof( WCHAR )
                    );

    }


    //
    // Next we try to collect Video BIOS date and version strings.
    //
    if( VideoBIOSDateString[0] != 0 ) {

        RtlInitUnicodeString(
            &ValueName,
            L"VideoBiosDate"
            );

        Status = NtSetValueKey(
                    ParentHandle,
                    &ValueName,
                    TITLE_INDEX_VALUE,
                    REG_SZ,
                    VideoBIOSDateString,
                    (wcslen(VideoBIOSDateString)+1) * sizeof( WCHAR )
                    );

    }

    if( VideoBIOSVersionString[0] != 0 ) {

        RtlInitUnicodeString(
            &ValueName,
            L"VideoBiosVersion"
            );

        Status = NtSetValueKey(
                    ParentHandle,
                    &ValueName,
                    TITLE_INDEX_VALUE,
                    REG_SZ,
                    VideoBIOSVersionString,
                    (wcslen(VideoBIOSVersionString)+1) * sizeof( WCHAR )
                    );

    }


    NtClose (ParentHandle);

    //
    // Add any other x86 specific code here...
    //

    return STATUS_SUCCESS;
}



VOID
InitializeProcessorInformationFromSMBIOS(
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    )
/*++

Routine Description:

    This function attempts to load processor-specific information
    out of the SMBIOS table.  If present, that information will be
    used to initialize specific global variables.

Arguments:

    LoaderBlock : Pointer to the loaderblock as sent in from the loader.

Return Value:

    NONE.

--*/
{
    PLOADER_PARAMETER_EXTENSION     LoaderExtension;
    NTSTATUS                        Status = STATUS_SUCCESS;
    PSMBIOS_EPS_HEADER              SMBiosEPSHeader;
    PDMIBIOS_EPS_HEADER             DMIBiosEPSHeader;
    BOOLEAN                         Found = FALSE;
    PHYSICAL_ADDRESS                SMBiosTablePhysicalAddress = {0};
    PUCHAR                          StartPtr = NULL;
    PUCHAR                          EndPtr = NULL;
    PUCHAR                          SMBiosDataVirtualAddress = NULL;
    PSMBIOS_STRUCT_HEADER           Header = NULL;
    ULONG                           i = 0;
    PKPRCB                          Prcb;
    UCHAR                           Checksum;


    PAGED_CODE();


    LoaderExtension = LoaderBlock->Extension;

    if (LoaderExtension->Size >= sizeof(LOADER_PARAMETER_EXTENSION)) {


        if (LoaderExtension->SMBiosEPSHeader != NULL) {

            //
            // Load the SMBIOS table address and checksum it just to make sure.
            //
            SMBiosEPSHeader = (PSMBIOS_EPS_HEADER)LoaderExtension->SMBiosEPSHeader;
            DMIBiosEPSHeader = (PDMIBIOS_EPS_HEADER)&SMBiosEPSHeader->Signature2[0];

            SMBiosTablePhysicalAddress.HighPart = 0;
            SMBiosTablePhysicalAddress.LowPart = DMIBiosEPSHeader->StructureTableAddress;

            StartPtr = (PUCHAR)SMBiosEPSHeader;
            Checksum = 0;
            for( i = 0; i < SMBiosEPSHeader->Length; i++ ) {
                Checksum += StartPtr[i];
            }
            if( Checksum != 0 ) {
                CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"InitializeProcessorInformationFromSMBIOS: _SM_ table has an incorrect checksum.\n"));
                return;
            }



            //
            // Map the table into a virtual address and search it.
            //
            SMBiosDataVirtualAddress = MmMapIoSpace( SMBiosTablePhysicalAddress,
                                                     DMIBiosEPSHeader->StructureTableLength,
                                                     MmCached );

            if( SMBiosDataVirtualAddress != NULL ) {

                //
                // Search...
                //
                StartPtr = SMBiosDataVirtualAddress;
                EndPtr = StartPtr + DMIBiosEPSHeader->StructureTableLength;
                Found = FALSE;
                while( (StartPtr < EndPtr) ) {

                    Header = (PSMBIOS_STRUCT_HEADER)StartPtr;


                    if( Header->Type == SMBIOS_BIOS_INFORMATION_TYPE ) {

                        PSMBIOS_BIOS_INFORMATION_STRUCT InfoHeader = (PSMBIOS_BIOS_INFORMATION_STRUCT)StartPtr;
                        PUCHAR      StringPtr = NULL;

                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: SMBIOS_BIOS_INFORMATION\n"));

                        //
                        // Load the System BIOS Version information.
                        //


                        // Now jump to the BiosInfoHeader->BIOSVersion-th string which
                        // is appended onto the end of the formatted section of the table.

                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the version string is at offset: %d\n", (ULONG)InfoHeader->Version));
                        if( (ULONG)InfoHeader->Version > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->Version-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }

                            // StringPtr should be sitting at the BIOSVersion string.  Convert him to
                            // Unicode and save it off.
                            if( StringPtr < EndPtr ) {
                                UNICODE_STRING  UnicodeString;
                                ANSI_STRING     AnsiString;

                                KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I'm about to load the Version string %s\n", StringPtr));
                                UnicodeString.Buffer = SystemBIOSVersionString;
                                UnicodeString.MaximumLength = MAXIMUM_BIOS_VERSION_LENGTH;
                                RtlInitAnsiString(
                                    &AnsiString,
                                    StringPtr
                                    );

                                RtlAnsiStringToUnicodeString(
                                    &UnicodeString,
                                    &AnsiString,
                                    FALSE
                                    );

                            }
                        }



                        //
                        // Load the System BIOS Date information
                        //

                        // Now jump to the BiosInfoHeader->BIOSDate-th string which
                        // is appended onto the end of the formatted section of the table.
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the ReleaseDate string is at offset: %d\n", (ULONG)InfoHeader->ReleaseDate));
                        if( (ULONG)InfoHeader->ReleaseDate > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->ReleaseDate-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }

                            // StringPtr should be sitting at the BIOSDate string.  Convert him to
                            // Unicode and save it off.
                            if( StringPtr < EndPtr ) {
                                UNICODE_STRING  UnicodeString;
                                ANSI_STRING     AnsiString;


                                KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I'm about to load the Date string %s\n", StringPtr));
                                UnicodeString.Buffer = SystemBIOSDateString;
                                UnicodeString.MaximumLength = BIOS_DATE_LENGTH;
                                RtlInitAnsiString(
                                    &AnsiString,
                                    StringPtr
                                    );

                                RtlAnsiStringToUnicodeString(
                                    &UnicodeString,
                                    &AnsiString,
                                    FALSE
                                    );

                            }
                        }


                    } else if( Header->Type == SMBIOS_BASE_BOARD_INFORMATION_TYPE ) {
                        PSMBIOS_BASE_BOARD_INFORMATION_STRUCT InfoHeader = (PSMBIOS_BASE_BOARD_INFORMATION_STRUCT)StartPtr;
                        PUCHAR      StringPtr = NULL;

                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: SMBIOS_BASE_BOARD_INFORMATION\n"));

#if 0
//
// We aren't using any of this information right now.
// -matth 4/2001
//

                        // Manufacturer
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the Manufacturer string is at offset: %d\n", (ULONG)InfoHeader->Manufacturer));
                        if( (ULONG)InfoHeader->Manufacturer > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->Manufacturer-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }
                            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    Manufacturer: %s\n", StringPtr));
                        }


                        // Product
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the Product string is at offset: %d\n", (ULONG)InfoHeader->Product));
                        if( (ULONG)InfoHeader->Product > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->Product-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }
                            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    Product: %s\n", StringPtr));
                        }


                        // Version
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the Version string is at offset: %d\n", (ULONG)InfoHeader->Version));
                        if( (ULONG)InfoHeader->Version > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->Version-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }
                            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    Version: %s\n", StringPtr));
                        }


                        // SerialNumber
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the SerialNumber string is at offset: %d\n", (ULONG)InfoHeader->SerialNumber));
                        if( (ULONG)InfoHeader->SerialNumber > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->SerialNumber-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }
                            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"     SerialNumber: %s\n", StringPtr));
                        }
#endif


                    } else if( Header->Type == SMBIOS_SYSTEM_CHASIS_INFORMATION_TYPE ) {

                        PSMBIOS_SYSTEM_CHASIS_INFORMATION_STRUCT InfoHeader = (PSMBIOS_SYSTEM_CHASIS_INFORMATION_STRUCT)StartPtr;
                        PUCHAR      StringPtr = NULL;

                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: SMBIOS_SYSTEM_CHASIS_INFORMATION\n"));

#if 0
//
// We aren't using any of this information right now.
// -matth 4/2001
//


                        // Manufacturer
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the Manufacturer string is at offset: %d\n", (ULONG)InfoHeader->Manufacturer));
                        if( (ULONG)InfoHeader->Manufacturer > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->Manufacturer-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }
                            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    Manufacturer: %s\n", StringPtr));
                        }


                        // Product
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the Manufacturer string is at offset: %d\n", (ULONG)InfoHeader->ChasisType));
                        if( (ULONG)InfoHeader->ChasisType > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->ChasisType-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }
                            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    ChasisType: %s\n", StringPtr));
                        }


                        // Version
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the Version string is at offset: %d\n", (ULONG)InfoHeader->Version));
                        if( (ULONG)InfoHeader->Version > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->Version-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }
                            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    Version: %s\n", StringPtr));
                        }


                        // SerialNumber
                        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"    I think the SerialNumber string is at offset: %d\n", (ULONG)InfoHeader->SerialNumber));
                        if( (ULONG)InfoHeader->SerialNumber > 0 ) {

                            // Jump to the end of the formatted portion of the SMBIOS table.
                            StringPtr = StartPtr + Header->Length;

                            // Jump over some number of strings to get to our string.
                            for( i = 0; i < ((ULONG)InfoHeader->SerialNumber-1); i++ ) {
                                while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
                                    StringPtr++;
                                }
                                StringPtr++;
                            }
                            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"     SerialNumber: %s\n", StringPtr));
                        }

#endif

                    }


                    //
                    // Go to the next table.
                    //
                    KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: Haven't found the ProcessorInformation block yet.  Just looked at a block of type: %d.\n", Header->Type));

                    StartPtr +=  Header->Length;

                    // jump over any trailing string-list too.
                    while ( (*((USHORT UNALIGNED *)StartPtr) != 0)  &&
                            (StartPtr < EndPtr) )
                    {
                        StartPtr++;
                    }
                    StartPtr += 2;

                }


                MmUnmapIoSpace(SMBiosDataVirtualAddress, DMIBiosEPSHeader->StructureTableLength);

            } else {
                KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: Failed to map the SMBIOS physical address.\n"));
            }

        } else {
            KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: The SMBiosEPSHeader is NULL in the extension block.\n"));
        }

    } else {
        KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: LoaderBlock extension is out of sync with the kernel.\n"));

    }
}