/** @file

  Copyright (c) 2004  - 2014, Intel Corporation. All rights reserved.<BR>
                                                                                   

  This program and the accompanying materials are licensed and made available under

  the terms and conditions of the BSD License that accompanies this distribution.  

  The full text of the license may be found at                                     

  http://opensource.org/licenses/bsd-license.php.                                  

                                                                                   

  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,            

  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.    

                                                                                   



Module Name:

    SetupInfoRecords.c

Abstract:

    This is the filter driver to retrieve data hub entries.

Revision History:
--*/

#include "PlatformSetupDxe.h"
#include <Protocol/LegacyBios.h>
#include <Protocol/PciRootBridgeIo.h>
#include <Protocol/SimpleNetwork.h>
#include <Protocol/DevicePath.h>
#include <Protocol/DiskInfo.h>
#include <Protocol/IdeControllerInit.h>
#include <Protocol/MpService.h>
#include <Protocol/PchPlatformPolicy.h>
#include <Protocol/CpuIo2.h>
#include <Protocol/Smbios.h>
#include <IndustryStandard/SmBios.h>
#include <Library/IoLib.h>
#include <Library/I2CLib.h>
#include <Guid/GlobalVariable.h>

#include "Valleyview.h"
#include "VlvAccess.h"
#include "PchAccess.h"
#include "SetupMode.h"
#include "PchCommonDefinitions.h"
#include <PlatformBaseAddresses.h>


typedef struct {
  UINT8  ID;
  CHAR8  String[16];
} VLV_REV;

typedef struct {
  UINT8 RevId;
  CHAR8 String[16];
} SB_REV;

//
// Silicon Steppings
//
SB_REV  SBRevisionTable[] = {
  {V_PCH_LPC_RID_0, "(A0 Stepping)"},
  {V_PCH_LPC_RID_1, "(A0 Stepping)"},
  {V_PCH_LPC_RID_2, "(A1 Stepping)"},
  {V_PCH_LPC_RID_3, "(A1 Stepping)"},
  {V_PCH_LPC_RID_4, "(B0 Stepping)"},
  {V_PCH_LPC_RID_5, "(B0 Stepping)"},
  {V_PCH_LPC_RID_6, "(B1 Stepping)"},
  {V_PCH_LPC_RID_7, "(B1 Stepping)"},
  {V_PCH_LPC_RID_8, "(B2 Stepping)"},
  {V_PCH_LPC_RID_9, "(B2 Stepping)"},
  {V_PCH_LPC_RID_A, "(B3 Stepping)"},
  {V_PCH_LPC_RID_B, "(B3 Stepping)"},
  {V_PCH_LPC_RID_C, "(C0 Stepping)"},
  {V_PCH_LPC_RID_D, "(C0 Stepping)"}
};

#define LEFT_JUSTIFY  0x01
#define PREFIX_SIGN   0x02
#define PREFIX_BLANK  0x04
#define COMMA_TYPE    0x08
#define LONG_TYPE     0x10
#define PREFIX_ZERO   0x20

#define ICH_REG_REV                 0x08
#define MSR_IA32_PLATFORM_ID        0x17


BOOLEAN                         mSetupInfoDone = FALSE;
UINT8                           mUseProductKey = 0;
EFI_EXP_BASE10_DATA             mProcessorFrequency;
EFI_EXP_BASE10_DATA             mProcessorFsbFrequency;

EFI_GUID                        mProcessorProducerGuid;
EFI_HII_HANDLE                  mHiiHandle;
EFI_PLATFORM_CPU_INFO           mPlatformCpuInfo;
SYSTEM_CONFIGURATION            mSystemConfiguration;
EFI_PLATFORM_INFO_HOB           *mPlatformInfo;


#define memset SetMem

UINT16                mMemorySpeed         = 0xffff;
EFI_PHYSICAL_ADDRESS  mMemorySizeChannelASlot0  = 0;
UINT16                mMemorySpeedChannelASlot0 = 0xffff;
EFI_PHYSICAL_ADDRESS  mMemorySizeChannelASlot1  = 0;
UINT16                mMemorySpeedChannelASlot1 = 0xffff;
EFI_PHYSICAL_ADDRESS  mMemorySizeChannelBSlot0  = 0;
UINT16                mMemorySpeedChannelBSlot0 = 0xffff;
EFI_PHYSICAL_ADDRESS  mMemorySizeChannelBSlot1  = 0;
UINT16                mMemorySpeedChannelBSlot1 = 0xffff;
EFI_PHYSICAL_ADDRESS  mMemorySizeChannelCSlot0  = 0;
UINT16                mMemorySpeedChannelCSlot0 = 0xffff;
EFI_PHYSICAL_ADDRESS  mMemorySizeChannelCSlot1  = 0;
UINT16                mMemorySpeedChannelCSlot1 = 0xffff;
UINTN                 mMemoryMode          = 0xff;

#define CHARACTER_NUMBER_FOR_VALUE  30
  typedef struct {
  EFI_STRING_TOKEN            MemoryDeviceLocator;
  EFI_STRING_TOKEN            MemoryBankLocator;
  EFI_STRING_TOKEN            MemoryManufacturer;
  EFI_STRING_TOKEN            MemorySerialNumber;
  EFI_STRING_TOKEN            MemoryAssetTag;
  EFI_STRING_TOKEN            MemoryPartNumber;
  EFI_INTER_LINK_DATA         MemoryArrayLink;
  EFI_INTER_LINK_DATA         MemorySubArrayLink;
  UINT16                      MemoryTotalWidth;
  UINT16                      MemoryDataWidth;
  UINT64                      MemoryDeviceSize;
  EFI_MEMORY_FORM_FACTOR      MemoryFormFactor;
  UINT8                       MemoryDeviceSet;
  EFI_MEMORY_ARRAY_TYPE       MemoryType;
  EFI_MEMORY_TYPE_DETAIL      MemoryTypeDetail;
  UINT16                      MemorySpeed;
  EFI_MEMORY_STATE            MemoryState;
} EFI_MEMORY_ARRAY_LINK;


typedef struct {
  EFI_PHYSICAL_ADDRESS        MemoryArrayStartAddress;
  EFI_PHYSICAL_ADDRESS        MemoryArrayEndAddress;
  EFI_INTER_LINK_DATA         PhysicalMemoryArrayLink;
  UINT16                      MemoryArrayPartitionWidth;
} EFI_MEMORY_ARRAY_START_ADDRESS;


typedef enum {
  PCH_SATA_MODE_IDE = 0,
  PCH_SATA_MODE_AHCI,
  PCH_SATA_MODE_RAID,
  PCH_SATA_MODE_MAX
} PCH_SATA_MODE;

/**
  Acquire the string associated with the Index from smbios structure and return it.
  The caller is responsible for free the string buffer.

  @param OptionalStrStart   The start position to search the string
  @param Index              The index of the string to extract
  @param String             The string that is extracted

  @retval EFI_SUCCESS       The function returns EFI_SUCCESS always.

**/
EFI_STATUS
GetOptionalStringByIndex (
  IN      CHAR8                   *OptionalStrStart,
  IN      UINT8                   Index,
  OUT     CHAR16                  **String
  )
{
  UINTN          StrSize;

  if (Index == 0) {
    *String = AllocateZeroPool (sizeof (CHAR16));
    return EFI_SUCCESS;
  }

  StrSize = 0;
  do {
    Index--;
    OptionalStrStart += StrSize;
    StrSize           = AsciiStrSize (OptionalStrStart);
  } while (OptionalStrStart[StrSize] != 0 && Index != 0);

  if ((Index != 0) || (StrSize == 1)) {
    //
    // Meet the end of strings set but Index is non-zero, or
    // Find an empty string
    //
    return EFI_NOT_FOUND;
  } else {
    *String = AllocatePool (StrSize * sizeof (CHAR16));
    AsciiStrToUnicodeStr (OptionalStrStart, *String);
  }

  return EFI_SUCCESS;
}

/**
  VSPrint worker function that prints a Value as a decimal number in Buffer

  @param Buffer  Location to place ascii decimal number string of Value.
  @param Value   Decimal value to convert to a string in Buffer.
  @param Flags   Flags to use in printing decimal string, see file header for details.
  @param Width   Width of hex value.

  Number of characters printed.

**/
UINTN
EfiValueToString (
  IN  OUT CHAR16  *Buffer,
  IN  INT64       Value,
  IN  UINTN       Flags,
  IN  UINTN       Width
  )
{
  CHAR16    TempBuffer[CHARACTER_NUMBER_FOR_VALUE];
  CHAR16    *TempStr;
  CHAR16    *BufferPtr;
  UINTN     Count;
  UINTN     ValueCharNum;
  UINTN     Remainder;
  CHAR16    Prefix;
  UINTN     Index;
  BOOLEAN   ValueIsNegative;
  UINT64    TempValue;

  TempStr         = TempBuffer;
  BufferPtr       = Buffer;
  Count           = 0;
  ValueCharNum    = 0;
  ValueIsNegative = FALSE;

  if (Width > CHARACTER_NUMBER_FOR_VALUE - 1) {
    Width = CHARACTER_NUMBER_FOR_VALUE - 1;
  }

  if (Value < 0) {
    Value           = -Value;
    ValueIsNegative = TRUE;
  }

  do {
    TempValue = Value;
    Value = (INT64)DivU64x32 ((UINT64)Value, 10);
    Remainder = (UINTN)((UINT64)TempValue - 10 * Value);
    *(TempStr++) = (CHAR16)(Remainder + '0');
    ValueCharNum++;
    Count++;
    if ((Flags & COMMA_TYPE) == COMMA_TYPE) {
      if (ValueCharNum % 3 == 0 && Value != 0) {
        *(TempStr++) = ',';
        Count++;
      }
    }
  } while (Value != 0);

  if (ValueIsNegative) {
    *(TempStr++)    = '-';
    Count++;
  }

  if ((Flags & PREFIX_ZERO) && !ValueIsNegative) {
    Prefix = '0';
  } else {
    Prefix = ' ';
  }

  Index = Count;
  if (!(Flags & LEFT_JUSTIFY)) {
    for (; Index < Width; Index++) {
      *(TempStr++) = Prefix;
    }
  }

  //
  // Reverse temp string into Buffer.
  //
  if (Width > 0 && (UINTN) (TempStr - TempBuffer) > Width) {
    TempStr = TempBuffer + Width;
  }
  Index = 0;
  while (TempStr != TempBuffer) {
    *(BufferPtr++) = *(--TempStr);
    Index++;
  }

  *BufferPtr = 0;
  return Index;
}

static CHAR16 mHexStr[] = { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
                            L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' };

/**
  VSPrint worker function that prints a Value as a hex number in Buffer

  @param  Buffer  Location to place ascii hex string of Value.
  @param  Value   Hex value to convert to a string in Buffer.
  @param  Flags   Flags to use in printing Hex string, see file header for details.
  @param  Width   Width of hex value.

  @retval         Number of characters printed.

**/
UINTN
EfiValueToHexStr (
  IN  OUT CHAR16  *Buffer,
  IN  UINT64      Value,
  IN  UINTN       Flags,
  IN  UINTN       Width
  )
{
  CHAR16  TempBuffer[CHARACTER_NUMBER_FOR_VALUE];
  CHAR16  *TempStr;
  CHAR16  Prefix;
  CHAR16  *BufferPtr;
  UINTN   Count;
  UINTN   Index;

  TempStr   = TempBuffer;
  BufferPtr = Buffer;

  //
  // Count starts at one since we will null terminate. Each iteration of the
  // loop picks off one nibble. Oh yea TempStr ends up backwards
  //
  Count = 0;

  if (Width > CHARACTER_NUMBER_FOR_VALUE - 1) {
    Width = CHARACTER_NUMBER_FOR_VALUE - 1;
  }

  do {
    Index = ((UINTN)Value & 0xf);
    *(TempStr++) = mHexStr[Index];
    Value = RShiftU64 (Value, 4);
    Count++;
  } while (Value != 0);

  if (Flags & PREFIX_ZERO) {
    Prefix = '0';
  } else {
    Prefix = ' ';
  }

  Index = Count;
  if (!(Flags & LEFT_JUSTIFY)) {
    for (; Index < Width; Index++) {
      *(TempStr++) = Prefix;
    }
  }

  //
  // Reverse temp string into Buffer.
  //
  if (Width > 0 && (UINTN) (TempStr - TempBuffer) > Width) {
    TempStr = TempBuffer + Width;
  }
  Index = 0;
  while (TempStr != TempBuffer) {
    *(BufferPtr++) = *(--TempStr);
    Index++;
  }

  *BufferPtr = 0;
  return Index;
}

/*++
  Converts MAC address to Unicode string.
  The value is 64-bit and the resulting string will be 12
  digit hex number in pairs of digits separated by dashes.

  @param  String    string that will contain the value
  @param  MacAddr   add argument and description to function comment
  @param  AddrSize  add argument and description to function comment

**/
CHAR16 *
StrMacToString (
  OUT CHAR16              *String,
  IN  EFI_MAC_ADDRESS     *MacAddr,
  IN  UINT32              AddrSize
  )
{
  UINT32  i;

  for (i = 0; i < AddrSize; i++) {

    EfiValueToHexStr (
      &String[2 * i],
      MacAddr->Addr[i] & 0xFF,
      PREFIX_ZERO,
      2
      );
  }

  //
  // Terminate the string.
  //
  String[2 * AddrSize] = L'\0';

  return String;
}

VOID UpdateLatestBootTime() {
  UINTN                         VarSize;
  EFI_STATUS                   Status;
  UINT64                       TimeValue;
  CHAR16                       Buffer[40];
  if (mSystemConfiguration.LogBootTime != 1) {
    return;
  }
  VarSize = sizeof(TimeValue);
  Status = gRT->GetVariable(
                  BOOT_TIME_NAME,
                  &gEfiNormalSetupGuid,
                  NULL,
                  &VarSize,
                  &TimeValue
				          );
  if (EFI_ERROR(Status)) {
    return;
  }
  UnicodeSPrint (Buffer, sizeof (Buffer), L"%d ms", (UINT32)TimeValue);
  HiiSetString(mHiiHandle,STRING_TOKEN(STR_LOG_BOOT_TIME_VALUE), Buffer, NULL);
}

/**
  Get Cache Type for the specified Cache. This function is invoked when there is data records
  available in the Data Hub.

  Get Cache Type function arguments:

  @param  Instance        The instance number of the subclass with the same ProducerName..
  @param  SubInstance     The instance number of the RecordType for the same Instance.
  @param  CacheType       Cache type, see definition of EFI_CACHE_TYPE_DATA.

  @retval EFI_STATUS

**/
EFI_STATUS
GetCacheType(
  IN  UINT16                            Instance,
  IN  UINT16                            SubInstance,
  IN  EFI_CACHE_TYPE_DATA*              CacheType)
{
  EFI_STATUS                  Status;
  EFI_DATA_HUB_PROTOCOL       *DataHub;
  EFI_DATA_RECORD_HEADER      *Record;
  UINT64                      MonotonicCount;
  EFI_CACHE_VARIABLE_RECORD*  CacheVariableRecord;
  EFI_SUBCLASS_TYPE1_HEADER   *DataHeader;

  Status = gBS->LocateProtocol (
                  &gEfiDataHubProtocolGuid,
                  NULL,
                  (void **)&DataHub
                  );
  ASSERT_EFI_ERROR(Status);

  //
  // Get all available data records from data hub
  //
  MonotonicCount = 0;
  Record = NULL;

  do {
    Status = DataHub->GetNextRecord (
	                    DataHub,
						&MonotonicCount,
						NULL,
						&Record
						);
    if (!EFI_ERROR(Status)) {
      if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {
        DataHeader  = (EFI_SUBCLASS_TYPE1_HEADER *)(Record + 1);

        if(CompareGuid(&Record->DataRecordGuid, &gEfiCacheSubClassGuid) &&
          (DataHeader->RecordType == CacheTypeRecordType) &&
          (DataHeader->Instance == Instance) &&
          (DataHeader->SubInstance == SubInstance)) {
          CacheVariableRecord     = (EFI_CACHE_VARIABLE_RECORD  *)(DataHeader + 1);
          if(CacheType){
            *CacheType = CacheVariableRecord->CacheType;
            return EFI_SUCCESS;
          }
        }
      }
    }
  } while(!EFI_ERROR(Status) && (MonotonicCount != 0));

  return EFI_NOT_FOUND;
}

/**
  Setup data filter function. This function is invoked when there is data records
  available in the Data Hub.


  Standard event notification function arguments:
  @param Event          The event that is signaled.
  @param Context        Not used here.

  @retval EFI_STATUS

**/
VOID
PrepareSetupInformation (
  )
{

  EFI_STATUS                  Status;
  EFI_DATA_HUB_PROTOCOL       *DataHub;
  EFI_DATA_RECORD_HEADER      *Record;
  UINT8                       *SrcData;
  EFI_SUBCLASS_TYPE1_HEADER   *DataHeader;
  CHAR16                      *NewString;
  CHAR16                      *NewString2;
  CHAR16                      *NewStringToken;
  STRING_REF                  TokenToUpdate;
  EFI_PROCESSOR_VERSION_DATA  *ProcessorVersion;
  UINTN                       Index;
  UINTN                       DataOutput;

  EFI_PROCESSOR_MICROCODE_REVISION_DATA   *CpuUcodeRevisionData;
  EFI_MEMORY_ARRAY_START_ADDRESS          *MemoryArray;
  EFI_MEMORY_ARRAY_LINK                   *MemoryArrayLink;
  UINT64                      MonotonicCount;

  CHAR16                      Version[100];         //Assuming that strings are < 100 UCHAR
  CHAR16                      ReleaseDate[100];     //Assuming that strings are < 100 UCHAR
  CHAR16                      ReleaseTime[100];     //Assuming that strings are < 100 UCHAR

  NewString = AllocateZeroPool (0x100);
  NewString2 = AllocateZeroPool (0x100);
  SetMem(Version, sizeof(Version), 0);
  SetMem(ReleaseDate, sizeof(ReleaseDate), 0);
  SetMem(ReleaseTime, sizeof(ReleaseTime), 0);

  //
  // Get the Data Hub Protocol. Assume only one instance
  //
  Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (void **)&DataHub);
  ASSERT_EFI_ERROR(Status);

  //
  // Get all available data records from data hub
  //
  MonotonicCount = 0;
  Record = NULL;

  do {
    Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record);
    if (!EFI_ERROR(Status)) {
      if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {
        DataHeader  = (EFI_SUBCLASS_TYPE1_HEADER *)(Record + 1);
        SrcData     = (UINT8  *)(DataHeader + 1);

        //
        // Processor
        //
        if (CompareGuid(&Record->DataRecordGuid, &gEfiProcessorSubClassGuid)) {
          CopyMem (&mProcessorProducerGuid, &Record->ProducerName, sizeof(EFI_GUID));
          switch (DataHeader->RecordType) {
            case ProcessorCoreFrequencyRecordType:
              CopyMem(&mProcessorFrequency, SrcData, sizeof(EFI_EXP_BASE10_DATA));
              Index = EfiValueToString (
			            NewString,
						ConvertBase10ToRaw ((EFI_EXP_BASE10_DATA *)SrcData)/1000000000,
						PREFIX_ZERO,
						0
						);
              StrCat (NewString, L".");
              EfiValueToString (
			    NewString + Index + 1,
				((ConvertBase10ToRaw ((EFI_EXP_BASE10_DATA *)SrcData)%1000000000)/10000000),
				PREFIX_ZERO,
				0
				);
              StrCat (NewString, L" GHz");
              TokenToUpdate = (STRING_REF)STR_PROCESSOR_SPEED_VALUE;
              HiiSetString(mHiiHandle, TokenToUpdate, NewString, NULL);
              break;

            case ProcessorVersionRecordType:
              ProcessorVersion = (EFI_PROCESSOR_VERSION_DATA *)SrcData;
              NewStringToken = HiiGetPackageString(&mProcessorProducerGuid, *ProcessorVersion, NULL);
              TokenToUpdate = (STRING_REF)STR_PROCESSOR_VERSION_VALUE;
              HiiSetString(mHiiHandle, TokenToUpdate, NewStringToken, NULL);
              break;
            case CpuUcodeRevisionDataRecordType:
              CpuUcodeRevisionData = (EFI_PROCESSOR_MICROCODE_REVISION_DATA *) SrcData;
              if (CpuUcodeRevisionData->ProcessorMicrocodeRevisionNumber != 0) {
                EfiValueToHexStr (
				  NewString,
                  CpuUcodeRevisionData->ProcessorMicrocodeRevisionNumber,
                  PREFIX_ZERO,
                  8
				  );
                TokenToUpdate = (STRING_REF)STR_PROCESSOR_MICROCODE_VALUE;
                HiiSetString(mHiiHandle, TokenToUpdate, NewString, NULL);
              }
              break;
            default:
              break;
          }

        //
        // Cache
        //
        } else if (CompareGuid(&Record->DataRecordGuid, &gEfiCacheSubClassGuid) &&
                   (DataHeader->RecordType == CacheSizeRecordType)) {
          if (DataHeader->SubInstance == EFI_CACHE_L1) {
            EFI_CACHE_TYPE_DATA              CacheType;
            if (EFI_SUCCESS == GetCacheType(DataHeader->Instance, DataHeader->SubInstance,&CacheType)){
              if (CacheType == EfiCacheTypeData) {
                TokenToUpdate = (STRING_REF)STR_PROCESSOR_L1_DATA_CACHE_VALUE;
              } else if (CacheType == EfiCacheTypeInstruction) {
                  TokenToUpdate = (STRING_REF)STR_PROCESSOR_L1_INSTR_CACHE_VALUE;
              } else {
                continue;
              }
            } else {
              continue;
            }
          }
          else if (DataHeader->SubInstance == EFI_CACHE_L2) {
            TokenToUpdate = (STRING_REF)STR_PROCESSOR_L2_CACHE_VALUE;
          } else {
            continue;
          }
          if (ConvertBase2ToRaw((EFI_EXP_BASE2_DATA *)SrcData)) {
            DataOutput = ConvertBase2ToRaw((EFI_EXP_BASE2_DATA *)SrcData) >> 10;
            EfiValueToString (NewString, DataOutput, PREFIX_ZERO, 0);

            StrCat (NewString, L" KB");
            if (DataHeader->SubInstance == EFI_CACHE_L3) {
              HiiSetString(mHiiHandle, TokenToUpdate, NewString, NULL);
            } else if(DataHeader->SubInstance == EFI_CACHE_L2 && mPlatformCpuInfo.CpuPackage.CoresPerPhysicalPackage > 1){
			  //
              // Show XxL2 string
			  //
              EfiValueToString (
			    NewString2,
                mPlatformCpuInfo.CpuPackage.CoresPerPhysicalPackage,
                PREFIX_ZERO,
                0
				);
              StrCat(NewString2, L"x ");
              StrCat(NewString2, NewString);
              HiiSetString(mHiiHandle, TokenToUpdate, NewString2, NULL);
            } else {
              HiiSetString(mHiiHandle, TokenToUpdate, NewString, NULL);
            }
          }

        //
        // Memory
        //
        } else if (CompareGuid(&Record->DataRecordGuid, &gEfiMemorySubClassGuid)) {
          switch (DataHeader->RecordType) {
            case EFI_MEMORY_ARRAY_LINK_RECORD_NUMBER:
              MemoryArrayLink = (EFI_MEMORY_ARRAY_LINK *)SrcData;

              if (MemoryArrayLink->MemorySpeed > 0) {
                //
                // Save the lowest speed memory module
                //
                if (MemoryArrayLink->MemorySpeed < mMemorySpeed) {
                  mMemorySpeed = MemoryArrayLink->MemorySpeed;
                }
                switch (DataHeader->SubInstance) {
                  case 1:
                    mMemorySpeedChannelASlot0 = MemoryArrayLink->MemorySpeed;
                    mMemorySizeChannelASlot0 = MemoryArrayLink->MemoryDeviceSize;
                    break;
                  case 2:
                    mMemorySpeedChannelASlot1 = MemoryArrayLink->MemorySpeed;
                    mMemorySizeChannelASlot1 = MemoryArrayLink->MemoryDeviceSize;
                    break;
                  case 3:
                    mMemorySpeedChannelBSlot0 = MemoryArrayLink->MemorySpeed;
                    mMemorySizeChannelBSlot0 = MemoryArrayLink->MemoryDeviceSize;
                    break;
                  case 4:
                    mMemorySpeedChannelBSlot1 = MemoryArrayLink->MemorySpeed;
                    mMemorySizeChannelBSlot1 = MemoryArrayLink->MemoryDeviceSize;
                    break;
                  case 5:
                    mMemorySpeedChannelCSlot0 = MemoryArrayLink->MemorySpeed;
                    mMemorySizeChannelCSlot0 = MemoryArrayLink->MemoryDeviceSize;
                    break;
                  case 6:
                    mMemorySpeedChannelCSlot1 = MemoryArrayLink->MemorySpeed;
                    mMemorySizeChannelCSlot1 = MemoryArrayLink->MemoryDeviceSize;
                    break;
                  default:
                    break;
                  }
              }
              break;

            case EFI_MEMORY_ARRAY_START_ADDRESS_RECORD_NUMBER:
              MemoryArray = (EFI_MEMORY_ARRAY_START_ADDRESS *)SrcData;
              if (MemoryArray->MemoryArrayEndAddress - MemoryArray->MemoryArrayStartAddress) {
              	DataOutput = (UINTN)RShiftU64((MemoryArray->MemoryArrayEndAddress - MemoryArray->MemoryArrayStartAddress + 1), 20);
              	EfiValueToString (NewString, DataOutput / 1024, PREFIX_ZERO, 0);
              	if(DataOutput % 1024) {
              	  StrCat (NewString, L".");
              	  DataOutput = ((DataOutput % 1024) * 1000) / 1024;
              	  while(!(DataOutput % 10))
              	    DataOutput = DataOutput / 10;
                  EfiValueToString (NewString2, DataOutput, PREFIX_ZERO, 0);
                  StrCat (NewString, NewString2);
                }
                StrCat (NewString, L" GB");
                TokenToUpdate = (STRING_REF)STR_TOTAL_MEMORY_SIZE_VALUE;
                HiiSetString(mHiiHandle, TokenToUpdate, NewString, NULL);
              }
              break;

            default:
              break;
          }
        }
      }
    }
  } while (!EFI_ERROR(Status) && (MonotonicCount != 0));

  Status = GetBiosVersionDateTime (
             Version,
			 ReleaseDate,
			 ReleaseTime
			 );

  DEBUG ((EFI_D_ERROR, "GetBiosVersionDateTime :%s %s %s \n", Version, ReleaseDate, ReleaseTime));
  if (!EFI_ERROR (Status)) {
    UINTN         Length = 0;
    CHAR16        *BuildDateTime;

    Length = StrLen(ReleaseDate) + StrLen(ReleaseTime);

    BuildDateTime = AllocateZeroPool ((Length+2) * sizeof(CHAR16));
    StrCpy (BuildDateTime, ReleaseDate);
    StrCat (BuildDateTime, L" ");
    StrCat (BuildDateTime, ReleaseTime);

    TokenToUpdate = (STRING_REF)STR_BIOS_VERSION_VALUE;
    DEBUG ((EFI_D_ERROR, "update STR_BIOS_VERSION_VALUE\n"));
    HiiSetString(mHiiHandle, TokenToUpdate, Version, NULL);

    TokenToUpdate = (STRING_REF)STR_BIOS_BUILD_TIME_VALUE;
    DEBUG ((EFI_D_ERROR, "update STR_BIOS_BUILD_TIME_VALUE\n"));
    HiiSetString(mHiiHandle, TokenToUpdate, BuildDateTime, NULL);
  }

  //
  // Calculate and update memory speed display in Main Page
  //
  //
  // Update the overall memory speed
  //
  if (mMemorySpeed != 0xffff) {
    EfiValueToString (NewString, mMemorySpeed, PREFIX_ZERO, 0);
    StrCat (NewString, L" MHz");

    TokenToUpdate = (STRING_REF)STR_SYSTEM_MEMORY_SPEED_VALUE;
    HiiSetString(mHiiHandle, TokenToUpdate, NewString, NULL);
  }

  gBS->FreePool(NewString);
  gBS->FreePool(NewString2);

  return;
}

/**

  Routine Description: update the SETUP info for "Additional Information" which is SMBIOS info.

  @retval EFI_STATUS

**/
EFI_STATUS
UpdateAdditionalInformation (
  )
{
  EFI_STATUS                      Status;
  UINT64                          MonotonicCount;
  EFI_DATA_HUB_PROTOCOL           *DataHub;
  EFI_DATA_RECORD_HEADER          *Record;
  EFI_SUBCLASS_TYPE1_HEADER       *DataHeader;
  EFI_SMBIOS_PROTOCOL             *Smbios;
  EFI_SMBIOS_HANDLE               SmbiosHandle;
  EFI_SMBIOS_TABLE_HEADER         *SmbiosRecord;
  SMBIOS_TABLE_TYPE0              *Type0Record;
  UINT8                           StrIndex;
  CHAR16                          *BiosVersion = NULL;
  CHAR16                          *IfwiVersion = NULL;
  UINT16                          SearchIndex;
  EFI_STRING_ID                   TokenToUpdate;
#if defined( RVP_SUPPORT ) && RVP_SUPPORT
  EFI_MISC_SYSTEM_MANUFACTURER    *SystemManufacturer;
#endif

  Status = gBS->LocateProtocol (
                  &gEfiDataHubProtocolGuid,
                  NULL,
                  (void **)&DataHub
                  );

  ASSERT_EFI_ERROR(Status);

  MonotonicCount  = 0;
  Record = NULL;
  do {
    Status = DataHub->GetNextRecord (
                        DataHub,
                        &MonotonicCount,
                        NULL,
                        &Record
                        );
    if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {
      DataHeader  = (EFI_SUBCLASS_TYPE1_HEADER *)(Record + 1);

      if (CompareGuid(&Record->DataRecordGuid, &gEfiMiscSubClassGuid) &&
          (DataHeader->RecordType == EFI_MISC_SYSTEM_MANUFACTURER_RECORD_NUMBER)) {
#if defined( RVP_SUPPORT ) && RVP_SUPPORT
        //
        // System Information
        //
        SystemManufacturer = (EFI_MISC_SYSTEM_MANUFACTURER *)(DataHeader + 1);

        //
        // UUID  (System Information)
        //
        SMBIOSString = EfiLibAllocateZeroPool (0x100);
        GuidToString ( &SystemManufacturer->SystemUuid, SMBIOSString, 0x00 );

        TokenToUpdate = (STRING_REF)STR_SYSTEM_UUID_VALUE;
        HiiSetString(mHiiHandle, TokenToUpdate, SMBIOSString, NULL);

        gBS->FreePool(SMBIOSString);
#endif
      }
    }
  } while (!EFI_ERROR(Status) && (MonotonicCount != 0));

  Status = gBS->LocateProtocol (
                  &gEfiSmbiosProtocolGuid,
                  NULL,
                  (VOID **) &Smbios
                  );
  ASSERT_EFI_ERROR (Status);

  SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
  do {
    Status = Smbios->GetNext (
                       Smbios,
                       &SmbiosHandle,
                       NULL,
                       &SmbiosRecord,
                       NULL
                       );
    if (SmbiosRecord->Type == EFI_SMBIOS_TYPE_BIOS_INFORMATION) {
      Type0Record = (SMBIOS_TABLE_TYPE0 *) SmbiosRecord;
      StrIndex = Type0Record->BiosVersion;
      GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &BiosVersion);
      TokenToUpdate = STRING_TOKEN (STR_BIOS_VERSION_VALUE);
      for (SearchIndex = 0x0; SearchIndex < SMBIOS_STRING_MAX_LENGTH; SearchIndex++) {
        if (BiosVersion[SearchIndex] == 0x0020) {
          BiosVersion[SearchIndex] = 0x0000;
          IfwiVersion = (CHAR16 *)(&BiosVersion[SearchIndex+1]);
          break;
        } else if (BiosVersion[SearchIndex] == 0x0000) {
          break;
        }
      }
      HiiSetString (mHiiHandle, TokenToUpdate, BiosVersion, NULL);

      //
      // Check IfwiVersion, to avoid no IFWI version in SMBIOS Type 0 strucntion
      //
      if(IfwiVersion) {
        TokenToUpdate = STRING_TOKEN (STR_IFWI_VERSION_VALUE);
        HiiSetString (mHiiHandle, TokenToUpdate, IfwiVersion, NULL);
      }
    }
  } while (!EFI_ERROR(Status));

  UpdateLatestBootTime();

  return  EFI_SUCCESS;
}

VOID
UpdateCPUInformation ()
{
  CHAR16								Buffer[40];
  UINT16                                FamilyId;
  UINT8                                 Model;
  UINT8                                 SteppingId;
  UINT8                                 ProcessorType;
  EFI_STATUS                            Status;
  EFI_MP_SERVICES_PROTOCOL              *MpService;
  UINTN                                 MaximumNumberOfCPUs;
  UINTN                                 NumberOfEnabledCPUs;
  UINT32								Buffer32 = 0xFFFFFFFF;   // Keep buffer with unknown device

  EfiCpuVersion (&FamilyId, &Model, &SteppingId, &ProcessorType);

  //
  //we need raw Model data
  //
  Model = Model & 0xf;

  //
  //Family/Model/Step
  //
  UnicodeSPrint (Buffer, sizeof (Buffer), L"%d/%d/%d", FamilyId,  Model, SteppingId);
  HiiSetString(mHiiHandle,STRING_TOKEN(STR_PROCESSOR_ID_VALUE), Buffer, NULL);

  Status = gBS->LocateProtocol (
                  &gEfiMpServiceProtocolGuid,
                  NULL,
                  (void **)&MpService
                  );
  if (!EFI_ERROR (Status)) {
    //
    // Determine the number of processors
    //
    MpService->GetNumberOfProcessors (
                 MpService,
                 &MaximumNumberOfCPUs,
                 &NumberOfEnabledCPUs
                 );
    UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", MaximumNumberOfCPUs);
    HiiSetString(mHiiHandle,STRING_TOKEN(STR_PROCESSOR_CORE_VALUE), Buffer, NULL);
  }
  //
  // Update Mobile / Desktop / Tablet SKU
  //
  Buffer32 =(UINT32) RShiftU64 (EfiReadMsr (MSR_IA32_PLATFORM_ID), 50) & 0x07;

  switch(Buffer32){
      case 0x0:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"(%d) - ISG SKU SOC", Buffer32);
        break;
      case 0x01:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"(%d) - Mobile SKU SOC", Buffer32);
        break;
      case 0x02:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"(%d) - Desktop SKU SOC", Buffer32);
        break;
      case 0x03:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"(%d) - Mobile SKU SOC", Buffer32);
        break;
      default:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"(%d) - Unknown SKU SOC", Buffer32);
        break;
    }
  HiiSetString(mHiiHandle,STRING_TOKEN(STR_PROCESSOR_SKU_VALUE), Buffer, NULL);

}


EFI_STATUS
SearchChildHandle(
  EFI_HANDLE Father,
  EFI_HANDLE *Child
  )
{
  EFI_STATUS                                                 Status;
  UINTN                                                          HandleIndex;
  EFI_GUID                                                     **ProtocolGuidArray = NULL;
  UINTN                                                          ArrayCount;
  UINTN                                                          ProtocolIndex;
  UINTN                                                          OpenInfoCount;
  UINTN                                                          OpenInfoIndex;
  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfo = NULL;
  UINTN                                                          mHandleCount;
  EFI_HANDLE                                                 *mHandleBuffer= NULL;

  //
  // Retrieve the list of all handles from the handle database
  //
  Status = gBS->LocateHandleBuffer (
                  AllHandles,
                  NULL,
                  NULL,
                  &mHandleCount,
                  &mHandleBuffer
                  );

  for (HandleIndex = 0; HandleIndex < mHandleCount; HandleIndex++)
  {
    //
    // Retrieve the list of all the protocols on each handle
    //
    Status = gBS->ProtocolsPerHandle (
                    mHandleBuffer[HandleIndex],
                    &ProtocolGuidArray,
                    &ArrayCount
                    );
    if (!EFI_ERROR (Status))
    {
      for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++)
      {
        Status = gBS->OpenProtocolInformation (
                        mHandleBuffer[HandleIndex],
                        ProtocolGuidArray[ProtocolIndex],
                        &OpenInfo,
                        &OpenInfoCount
                        );
        if (!EFI_ERROR (Status))
        {
          for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++)
          {
            if(OpenInfo[OpenInfoIndex].AgentHandle == Father)
            {
              if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
              {
                *Child = mHandleBuffer[HandleIndex];
		  Status = EFI_SUCCESS;
		  goto TryReturn;
              }
            }
          }
	   Status = EFI_NOT_FOUND;
        }
      }
      if(OpenInfo != NULL)
      {
        FreePool(OpenInfo);
	 OpenInfo = NULL;
      }
    }
    FreePool (ProtocolGuidArray);
    ProtocolGuidArray = NULL;
  }
TryReturn:
  if(OpenInfo != NULL)
  {
    FreePool (OpenInfo);
    OpenInfo = NULL;
  }
  if(ProtocolGuidArray != NULL)
  {
    FreePool(ProtocolGuidArray);
    ProtocolGuidArray = NULL;
  }
  if(mHandleBuffer != NULL)
  {
    FreePool (mHandleBuffer);
    mHandleBuffer = NULL;
  }
  return Status;
}

EFI_STATUS
JudgeHandleIsPCIDevice(
  EFI_HANDLE    Handle,
  UINT8            Device,
  UINT8            Funs
  )
{
  EFI_STATUS  Status;
  EFI_DEVICE_PATH   *DPath;

  Status = gBS->HandleProtocol (
                  Handle,
                  &gEfiDevicePathProtocolGuid,
                  (VOID **) &DPath
                  );
  if(!EFI_ERROR(Status))
  {
    while(!IsDevicePathEnd(DPath))
    {
      if((DPath->Type == HARDWARE_DEVICE_PATH) && (DPath->SubType == HW_PCI_DP))
      {
        PCI_DEVICE_PATH   *PCIPath;

        PCIPath = (PCI_DEVICE_PATH*) DPath;
        DPath = NextDevicePathNode(DPath);
        if(IsDevicePathEnd(DPath) && (PCIPath->Device == Device) && (PCIPath->Function == Funs))
        {
          return EFI_SUCCESS;
        }
      }
      else
      {
        DPath = NextDevicePathNode(DPath);
      }
    }
  }
  return EFI_UNSUPPORTED;
}

EFI_STATUS
GetDriverName(
  EFI_HANDLE   Handle,
  CHAR16         *Name
  )
{
  EFI_DRIVER_BINDING_PROTOCOL        *BindHandle = NULL;
  EFI_STATUS                                        Status;
  UINT32                                               Version;
  UINT16                                               *Ptr;
  Status = gBS->OpenProtocol(
                  Handle,
                  &gEfiDriverBindingProtocolGuid,
                  (VOID**)&BindHandle,
                  NULL,
                  NULL,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );

  if (EFI_ERROR(Status))
  {
    return EFI_NOT_FOUND;
  }

  Version = BindHandle->Version;
  Ptr = (UINT16*)&Version;
  UnicodeSPrint(Name, 40, L"%d.%d.%d", Version >> 24 , (Version >>16)& 0x0f ,*(Ptr));

  return EFI_SUCCESS;
}

EFI_STATUS
GetGOPDriverName(
  CHAR16 *Name
  )
{
  UINTN                         HandleCount;
  EFI_HANDLE                *Handles= NULL;
  UINTN                         Index;
  EFI_STATUS                Status;
  EFI_HANDLE                Child = 0;

  Status = gBS->LocateHandleBuffer(
		              ByProtocol,
		              &gEfiDriverBindingProtocolGuid,
		              NULL,
		              &HandleCount,
		              &Handles
                  );
  for (Index = 0; Index < HandleCount ; Index++)
  {
    Status = SearchChildHandle(Handles[Index], &Child);
    if(!EFI_ERROR(Status))
    {
      Status = JudgeHandleIsPCIDevice(
                 Child,
                 0x02,
                 0x00
                 );
      if(!EFI_ERROR(Status))
      {
        return GetDriverName(Handles[Index], Name);
      }
    }
  }
  return EFI_UNSUPPORTED;
}

EFI_STATUS
UpdatePlatformInformation (
  )
{
  UINT32                   MicroCodeVersion;
  CHAR16                   Buffer[40];
  UINT8                    IgdVBIOSRevH;
  UINT8                    IgdVBIOSRevL;
  UINT16                   EDX;
  EFI_IA32_REGISTER_SET    RegSet;
  EFI_LEGACY_BIOS_PROTOCOL *LegacyBios = NULL;
  EFI_STATUS               Status;
  UINT8                    CpuFlavor=0;
  EFI_PEI_HOB_POINTERS     GuidHob;
  UINTN                    NumHandles;
  EFI_HANDLE                        *HandleBuffer;
  UINTN                             Index;
  DXE_PCH_PLATFORM_POLICY_PROTOCOL  *PchPlatformPolicy;
  UINTN                             PciD31F0RegBase;
  UINT8                             count;
  UINT8                             Data8;
  UINT8                             PIDData8;

  CHAR16                            Name[40];
  UINT32                            MrcVersion;

  //
  // Get the HOB list.  If it is not present, then ASSERT.
  //
  GuidHob.Raw = GetHobList ();
  if (GuidHob.Raw != NULL) {
    if ((GuidHob.Raw = GetNextGuidHob (&gEfiPlatformInfoGuid, GuidHob.Raw)) != NULL) {
      mPlatformInfo = GET_GUID_HOB_DATA (GuidHob.Guid);
    }
  }

  //
  //VBIOS version
  //
  Status = gBS->LocateProtocol(
                  &gEfiLegacyBiosProtocolGuid,
                  NULL,
                  (void **)&LegacyBios
                  );
  if (!EFI_ERROR (Status)) {
  RegSet.X.AX = 0x5f01;
  Status = LegacyBios->Int86 (LegacyBios, 0x10, &RegSet);
  ASSERT_EFI_ERROR(Status);

  //
  // simulate AMI int15 (ax=5f01) handler
  // check NbInt15.asm in AMI code for asm edition
  //
  EDX = (UINT16)((RegSet.E.EBX >> 16) & 0xffff);
  IgdVBIOSRevH = (UINT8)(((EDX & 0x0F00) >> 4) | (EDX & 0x000F));
  IgdVBIOSRevL = (UINT8)(((RegSet.X.BX & 0x0F00) >> 4) | (RegSet.X.BX & 0x000F));

  if (IgdVBIOSRevH==0 && IgdVBIOSRevL==0){
    HiiSetString(mHiiHandle, STRING_TOKEN(STR_CHIP_IGD_VBIOS_REV_VALUE), L"N/A", NULL);
  } else {
    UnicodeSPrint (Buffer, sizeof (Buffer), L"%02X%02X", IgdVBIOSRevH,IgdVBIOSRevL);
    HiiSetString(mHiiHandle, STRING_TOKEN(STR_CHIP_IGD_VBIOS_REV_VALUE), Buffer, NULL);
    }
  }

  Status = GetGOPDriverName(Name);

  if (!EFI_ERROR(Status))
  {
    HiiSetString(mHiiHandle, STRING_TOKEN(STR_GOP_VALUE), Name, NULL);
  }


  //
  // CpuFlavor
  // ISG-DC Tablet        000
  // VLV-QC Tablet        001
  // VLV-QC Desktop       010
  // VLV-QC Notebook      011
  //
  CpuFlavor = RShiftU64 (EfiReadMsr (MSR_IA32_PLATFORM_ID), 50) & 0x07;

  switch(CpuFlavor){
    case 0x0:
      UnicodeSPrint (Buffer, sizeof (Buffer), L"%s (%01x)", L"VLV-DC Tablet", CpuFlavor);
      break;
    case 0x01:
      UnicodeSPrint (Buffer, sizeof (Buffer), L"%s (%01x)", L"VLV-QC Notebook", CpuFlavor);
      break;
    case 0x02:
      UnicodeSPrint (Buffer, sizeof (Buffer), L"%s (%01x)", L"VLV-QC Desktop", CpuFlavor);
      break;
    case 0x03:
      UnicodeSPrint (Buffer, sizeof (Buffer), L"%s (%01x)", L"VLV-QC Notebook", CpuFlavor);
      break;
    default:
      UnicodeSPrint (Buffer, sizeof (Buffer), L"%s (%01x)", L"Unknown CPU", CpuFlavor);
      break;
  }
  HiiSetString(mHiiHandle,STRING_TOKEN(STR_CPU_FLAVOR_VALUE), Buffer, NULL);

  if ( NULL != mPlatformInfo) {
    //
    //BoardId
    //
    switch(mPlatformInfo->BoardId){
      case 0x2:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"BAY LAKE RVP(%02x)", mPlatformInfo->BoardId);
        break;

      case 0x4:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"BAY LAKE FFRD(%02x)", mPlatformInfo->BoardId);
        break;

      case 0x5:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"BAY ROCK RVP DDR3L (%02x)", mPlatformInfo->BoardId);
        break;

      case 0x20:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"BAYLEY BAY (%02x)", mPlatformInfo->BoardId);
        break;

      case 0x30:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"BAKER SPORT (%02x)", mPlatformInfo->BoardId);
        break;

      case 0x0:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"ALPINE VALLEY (%x)", mPlatformInfo->BoardId);
        break;

      case 0x3:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"BAY LAKE FFD8 (%x)", mPlatformInfo->BoardId);
        break;

      default:
        UnicodeSPrint (Buffer, sizeof (Buffer), L"Unknown BOARD (%02x)", mPlatformInfo->BoardId);
        break;
    }
    HiiSetString(mHiiHandle,STRING_TOKEN(STR_BOARD_ID_VALUE), Buffer, NULL);


    //
    // Get Board FAB ID Info from protocol, update into the NVS area.
    // bit0~bit3 are for Fab ID, 0x0F means unknow FAB.
    //
    if(mPlatformInfo->BoardRev == 0x0F) {
      UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", L"Unknown FAB");
      HiiSetString(mHiiHandle,STRING_TOKEN(STR_FAB_ID_VALUE), Buffer, NULL);
    } else {
      UnicodeSPrint (Buffer, sizeof (Buffer), L"%2x", mPlatformInfo->BoardRev);
      HiiSetString(mHiiHandle,STRING_TOKEN(STR_FAB_ID_VALUE), Buffer, NULL);
    }
  }

  //
  //Update MRC Version
  //
  MrcVersion = 0x00000000;
  MrcVersion &= 0xffff;
  Index = EfiValueToString (Buffer, MrcVersion/100, PREFIX_ZERO, 0);
  StrCat (Buffer, L".");
  EfiValueToString (Buffer + Index + 1, (MrcVersion%100)/10, PREFIX_ZERO, 0);
  EfiValueToString (Buffer + Index + 2, (MrcVersion%100)%10, PREFIX_ZERO, 0);
  HiiSetString(mHiiHandle,STRING_TOKEN(STR_MRC_VERSION_VALUE), Buffer, NULL);

  //
  //Update Soc Version
  //

  //
  // Retrieve all instances of PCH Platform Policy protocol
  //
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gDxePchPlatformPolicyProtocolGuid,
                  NULL,
                  &NumHandles,
                  &HandleBuffer
                  );
  if (!EFI_ERROR (Status)) {
    //
    // Find the matching PCH Policy protocol
    //
    for (Index = 0; Index < NumHandles; Index++) {
      Status = gBS->HandleProtocol (
                      HandleBuffer[Index],
                      &gDxePchPlatformPolicyProtocolGuid,
                      (void **)&PchPlatformPolicy
                      );
      if (!EFI_ERROR (Status)) {
        PciD31F0RegBase = MmPciAddress (
                            0,
                            PchPlatformPolicy->BusNumber,
                            PCI_DEVICE_NUMBER_PCH_LPC,
                            PCI_FUNCTION_NUMBER_PCH_LPC,
                            0
                            );

         Data8 = MmioRead8 (PciD31F0RegBase + R_PCH_LPC_RID_CC);
         count = ARRAY_SIZE (SBRevisionTable);
         for (Index = 0; Index < count; Index++) {
           if(Data8 == SBRevisionTable[Index].RevId) {
              UnicodeSPrint (Buffer, sizeof (Buffer), L"%02x %a", Data8, SBRevisionTable[Index].String);
              HiiSetString(mHiiHandle,STRING_TOKEN(STR_SOC_VALUE), Buffer, NULL);
             break;
           }
         }
        break;
      }
    }
  }

  //
  // Microcode Revision
  //
  EfiWriteMsr (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
  EfiCpuid (EFI_CPUID_VERSION_INFO, NULL);
  MicroCodeVersion = (UINT32) RShiftU64 (EfiReadMsr (EFI_MSR_IA32_BIOS_SIGN_ID), 32);
  UnicodeSPrint (Buffer, sizeof (Buffer), L"%x", MicroCodeVersion);
  HiiSetString(mHiiHandle,STRING_TOKEN(STR_PROCESSOR_MICROCODE_VALUE), Buffer, NULL);

  //
  // Punit Version
  //
  Data8 = 0;
  UnicodeSPrint (Buffer, sizeof (Buffer), L"0x%x", Data8);
  HiiSetString(mHiiHandle,STRING_TOKEN(STR_PUNIT_FW_VALUE), Buffer, NULL);

  //
  //  PMC Version
  //
  Data8 = (UINT8)((MmioRead32 (PMC_BASE_ADDRESS + R_PCH_PMC_PRSTS)>>16)&0x00FF);
  PIDData8 = (UINT8)((MmioRead32 (PMC_BASE_ADDRESS + R_PCH_PMC_PRSTS)>>24)&0x00FF);
  UnicodeSPrint (Buffer, sizeof (Buffer), L"0x%X_%X",PIDData8, Data8);
  HiiSetString(mHiiHandle,STRING_TOKEN(STR_PMC_FW_VALUE), Buffer, NULL);

  return EFI_SUCCESS;
}

/**

  Update SATA Drivesize Strings for Setup and Boot order

  @param NewString - pointer to string.
  @param DeviceSpeed - speed of drive.

**/
VOID
GetDeviceSpeedString (
  CHAR16                      *NewString,
  IN UINTN                    DeviceSpeed
  )
{
  if (DeviceSpeed == 0x01) {
    StrCat (NewString, L"1.5Gb/s");
  } else if (DeviceSpeed == 0x02) {
    StrCat (NewString, L"3.0Gb/s");
  } else if (DeviceSpeed == 0x03) {
    StrCat (NewString, L"6.0Gb/s");
  } else if (DeviceSpeed == 0x0) {

  }
}

UINT8
GetChipsetSataPortSpeed (
  UINTN PortNum
  )
{
  UINT32                      DeviceSpeed;
  UINT8                       DeviceConfigStatus;
  UINT32                      IdeAhciBar;
  EFI_PHYSICAL_ADDRESS        MemBaseAddress = 0;
  UINT8                       FunNum;

  DeviceSpeed = 0x01; // generation 1


  //
  // Allocate the AHCI BAR
  //
    FunNum = PCI_FUNCTION_NUMBER_PCH_SATA;
    MemBaseAddress = 0x0ffffffff;
    gDS->AllocateMemorySpace (
           EfiGcdAllocateMaxAddressSearchBottomUp,
           EfiGcdMemoryTypeMemoryMappedIo,
           N_PCH_SATA_ABAR_ALIGNMENT,  // 2^11: 2K Alignment
           V_PCH_SATA_ABAR_LENGTH,     // 2K Length
           &MemBaseAddress,
           mImageHandle,
           NULL
           );
    IdeAhciBar = MmioRead32 (
                   MmPciAddress (
				     0,
                     0,
                     PCI_DEVICE_NUMBER_PCH_SATA,
                     FunNum,
                     R_PCH_SATA_ABAR
                     )
                   );
    IdeAhciBar &= 0xFFFFF800;
    DeviceConfigStatus = 0;
    if (IdeAhciBar == 0) {
      DeviceConfigStatus = 1;
      IdeAhciBar = (UINT32)MemBaseAddress;
      MmioWrite32 (
        MmPciAddress (0, 0, PCI_DEVICE_NUMBER_PCH_SATA, FunNum, R_PCH_SATA_ABAR),
        IdeAhciBar
        );
      MmioOr16 (
        MmPciAddress (0, 0, PCI_DEVICE_NUMBER_PCH_SATA, FunNum, R_PCH_SATA_COMMAND),
        B_PCH_SATA_COMMAND_MSE
        );
    }

    if (mSystemConfiguration.SataType == PCH_SATA_MODE_IDE){
      //
      // Program the "Ports Implemented Register"
      //
      MmioAndThenOr32 (IdeAhciBar + R_PCH_SATA_AHCI_PI, (UINT32)~(B_PCH_SATA_PORT0_IMPLEMENTED + B_PCH_SATA_PORT1_IMPLEMENTED), (UINT32)(B_PCH_SATA_PORT0_IMPLEMENTED + B_PCH_SATA_PORT1_IMPLEMENTED));
    }

    switch (PortNum)
    {
      case 0:
        DeviceSpeed = *(volatile UINT32 *)(UINTN)(IdeAhciBar + R_PCH_SATA_AHCI_P0SSTS);
        break;
      case 1:
        DeviceSpeed = *(volatile UINT32 *)(UINTN)(IdeAhciBar + R_PCH_SATA_AHCI_P1SSTS);
        break;
    }

    if (MemBaseAddress) {
      gDS->FreeMemorySpace (
             MemBaseAddress,
             V_PCH_SATA_ABAR_LENGTH
             );
    }

  if (DeviceConfigStatus) {
    IdeAhciBar = 0;
    MmioWrite32 (
      MmPciAddress (0, 0, PCI_DEVICE_NUMBER_PCH_SATA, FunNum, R_PCH_SATA_ABAR),
      IdeAhciBar
      );
  }

  DeviceSpeed = (UINT8)((DeviceSpeed >> 4) & 0x0F);

  return (UINT8)DeviceSpeed;
}

/**

  IDE data filter function.

**/
void
IdeDataFilter (void)
{
  EFI_STATUS                  Status;
  UINTN                       HandleCount;
  EFI_HANDLE                  *HandleBuffer;
  EFI_DISK_INFO_PROTOCOL      *DiskInfo;
  EFI_DEVICE_PATH_PROTOCOL    *DevicePath, *DevicePathNode;
  PCI_DEVICE_PATH             *PciDevicePath;
  UINTN                       Index;
  UINT8                       Index1;
  UINT32                      BufferSize;
  UINT32                      DriveSize;
  UINT32                      IdeChannel;
  UINT32                      IdeDevice;
  EFI_ATA_IDENTIFY_DATA       *IdentifyDriveInfo;
  CHAR16                      *NewString;
  CHAR16                      SizeString[20];
  STRING_REF                  NameToUpdate;
  CHAR8                       StringBuffer[0x100];
  UINT32                      DeviceSpeed;
  UINTN                       PortNumber;

  //
  // Assume no line strings is longer than 256 bytes.
  //
  NewString = AllocateZeroPool (0x100);
  PciDevicePath = NULL;

  //
  // Fill IDE Infomation
  //
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiDiskInfoProtocolGuid,
                  NULL,
                  &HandleCount,
                  &HandleBuffer
				  );

  if (EFI_ERROR (Status)) {
    return;
  }

  for (Index = 0; Index < HandleCount; Index++) {

    Status = gBS->HandleProtocol (
                    HandleBuffer[Index],
                    &gEfiDevicePathProtocolGuid,
                    (VOID*)&DevicePath
				    );
    ASSERT_EFI_ERROR (Status);

    DevicePathNode = DevicePath;
    while (!IsDevicePathEnd (DevicePathNode) ) {
      if  ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
           ( DevicePathSubType (DevicePathNode) == HW_PCI_DP)) {
        PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;
        break;
      }
      DevicePathNode    = NextDevicePathNode (DevicePathNode);
    }

    if (PciDevicePath == NULL) {
      continue;
    }

    //
    // Check for onboard IDE
    //
    if (PciDevicePath->Device== PCI_DEVICE_NUMBER_PCH_SATA) {
      Status = gBS->HandleProtocol (
	                  HandleBuffer[Index],
					  &gEfiDiskInfoProtocolGuid,
					  (void **)&DiskInfo
					  );
      ASSERT_EFI_ERROR (Status);

      Status = DiskInfo->WhichIde (
	                       DiskInfo,
                           &IdeChannel,
                           &IdeDevice
						   );
      ASSERT_EFI_ERROR (Status);

      IdentifyDriveInfo = AllocatePool (sizeof(EFI_ATA_IDENTIFY_DATA));

      BufferSize = sizeof(EFI_ATA_IDENTIFY_DATA);
      Status = DiskInfo->Identify (
	                       DiskInfo,
                           IdentifyDriveInfo,
                           &BufferSize
                           );
      ASSERT_EFI_ERROR(Status);

      //
      // Onboard SATA Devices
      //
      if (PciDevicePath->Function == PCI_FUNCTION_NUMBER_PCH_SATA) {
        if (IdeChannel == 0 && IdeDevice == 0) {
          NameToUpdate = (STRING_REF)STR_SATA0_NAME;
        } else if (IdeChannel == 1 && IdeDevice == 0) {
          NameToUpdate = (STRING_REF)STR_SATA1_NAME;
        } else {
          continue;
        }
      } else {
        continue;
      }

      ZeroMem(StringBuffer, sizeof(StringBuffer));
      CopyMem(
        StringBuffer,
        (CHAR8 *)&IdentifyDriveInfo->ModelName,
        sizeof(IdentifyDriveInfo->ModelName)
        );
      SwapEntries(StringBuffer);
      AsciiToUnicode(StringBuffer, NewString);

	  //
      // Chap it off after 16 characters
	  //
      NewString[16] = 0;

      //
      // For HardDisk append the size. Otherwise display atapi
      //
      if ((IdentifyDriveInfo->config & 0x8000) == 00) {
        //
        // 48 bit address feature set is supported, get maximum capacity
        //
        if ((IdentifyDriveInfo->command_set_supported_83 & 0x0400) == 0) {
        DriveSize = (((((IdentifyDriveInfo->user_addressable_sectors_hi << 16) +
                      IdentifyDriveInfo->user_addressable_sectors_lo) / 1000) * 512) / 1000);
        } else {
          DriveSize    = IdentifyDriveInfo->maximum_lba_for_48bit_addressing[0];
          for (Index1 = 1; Index1 < 4; Index1++) {
            //
            // Lower byte goes first: word[100] is the lowest word, word[103] is highest
            //
            DriveSize |= LShiftU64(IdentifyDriveInfo->maximum_lba_for_48bit_addressing[Index1], 16 * Index1);
          }
          DriveSize = (UINT32) DivU64x32(MultU64x32(DivU64x32(DriveSize, 1000), 512), 1000);
        }

        StrCat (NewString, L"(");
        EfiValueToString (SizeString, DriveSize/1000, PREFIX_BLANK, 0);
        StrCat (NewString, SizeString);
        StrCat (NewString, L".");
        EfiValueToString (SizeString, (DriveSize%1000)/100, PREFIX_BLANK, 0);
        StrCat (NewString, SizeString);
        StrCat (NewString, L"GB");
      } else {
        StrCat (NewString, L"(ATAPI");
      }

      //
      // Update SPEED.
      //
      PortNumber = (IdeDevice << 1) + IdeChannel;
      DeviceSpeed = GetChipsetSataPortSpeed(PortNumber);

      if (DeviceSpeed) {
        StrCat (NewString, L"-");
        GetDeviceSpeedString( NewString, DeviceSpeed);
      }

      StrCat (NewString, L")");

      HiiSetString(mHiiHandle, NameToUpdate, NewString, NULL);

    }
  }

  if (HandleBuffer != NULL) {
    gBS->FreePool (HandleBuffer);
  }

  gBS->FreePool(NewString);

  return;
}


VOID
EFIAPI
SetupInfo (void)
{
  EFI_STATUS                  Status;
  UINTN                       VarSize;
  EFI_PEI_HOB_POINTERS        GuidHob;

  if (mSetupInfoDone) {
      return;
  }

  VarSize = sizeof(SYSTEM_CONFIGURATION);
  Status = gRT->GetVariable(
                  NORMAL_SETUP_NAME,
                  &gEfiNormalSetupGuid,
                  NULL,
                  &VarSize,
                  &mSystemConfiguration
				  );

  if (EFI_ERROR (Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
    //The setup variable is corrupted
    VarSize = sizeof(SYSTEM_CONFIGURATION);
    Status = gRT->GetVariable(
              L"SetupRecovery",
              &gEfiNormalSetupGuid,
              NULL,
              &VarSize,
              &mSystemConfiguration
              );
    ASSERT_EFI_ERROR (Status);
  }  

  //
  // Update HOB variable for PCI resource information
  // Get the HOB list.  If it is not present, then ASSERT.
  //
  GuidHob.Raw = GetHobList ();
  if (GuidHob.Raw != NULL) {
    if ((GuidHob.Raw = GetNextGuidHob (&gEfiPlatformInfoGuid, GuidHob.Raw)) != NULL) {
      mPlatformInfo = GET_GUID_HOB_DATA (GuidHob.Guid);
    }
  }


  PrepareSetupInformation();
  UpdateAdditionalInformation ();
  UpdatePlatformInformation();
  UpdateCPUInformation();
  IdeDataFilter();
  mSetupInfoDone = TRUE;

  return;
}


#define EFI_SECURE_BOOT_MODE_NAME                   L"SecureBoot"

VOID
CheckSystemConfigLoad(SYSTEM_CONFIGURATION *SystemConfigPtr)
{
  EFI_STATUS              Status;
  UINT8                   SecureBoot;
  UINTN                   DataSize;


  DataSize = sizeof(SecureBoot);
  Status = gRT->GetVariable (
                  EFI_SECURE_BOOT_MODE_NAME,
                  &gEfiGlobalVariableGuid,
                  NULL,
                  &DataSize,
                  &SecureBoot
                  );

  if (EFI_ERROR(Status)) {
    SystemConfigPtr->SecureBoot = 0;
  } else {
    SystemConfigPtr->SecureBoot = SecureBoot;
  }
}


//
// "SecureBootEnable" variable for the Secure boot feature enable/disable.
//
#define EFI_SECURE_BOOT_ENABLE_NAME      L"SecureBootEnable"
extern EFI_GUID gEfiSecureBootEnableDisableGuid;


VOID
CheckSystemConfigSave(SYSTEM_CONFIGURATION *SystemConfigPtr)
{
  EFI_STATUS              Status;
  UINT8                   SecureBootCfg;
  BOOLEAN                 SecureBootNotFound;
  UINTN                   DataSize;


    //
    // Secure Boot configuration changes
	//
    DataSize = sizeof(SecureBootCfg);
    SecureBootNotFound = FALSE;
    Status = gRT->GetVariable (
                    EFI_SECURE_BOOT_ENABLE_NAME,
                    &gEfiSecureBootEnableDisableGuid,
                    NULL,
                    &DataSize,
                    &SecureBootCfg
                    );

    if (EFI_ERROR(Status)) {
      SecureBootNotFound = TRUE;
    }
    if (SecureBootNotFound) {
      Status = gRT->GetVariable (
                      EFI_SECURE_BOOT_ENABLE_NAME,
                      &gEfiSecureBootEnableDisableGuid,
                      NULL,
                      &DataSize,
                      &SecureBootCfg
                      );
      ASSERT_EFI_ERROR(Status);
    }
    if ((SecureBootCfg) != SystemConfigPtr->SecureBoot) {
      SecureBootCfg = !SecureBootCfg;
      Status = gRT->SetVariable (
                      EFI_SECURE_BOOT_ENABLE_NAME,
                      &gEfiSecureBootEnableDisableGuid,
                      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
                      sizeof (UINT8),
                      &SecureBootCfg
                      );
    }

}

VOID
ConfirmSecureBootTest()
{

}

