alder_lake_bios/Intel/AlderLake/Features/XmlCliFeaturePkg/LibraryPrivate/XmlCliCommonLib/XmlCliComLib.c

656 lines
19 KiB
C

/** @file
Common Lib Functions.
@copyright
INTEL CONFIDENTIAL
Copyright (c) 2021 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by the
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
This file contains a 'Sample Driver' and is licensed as such
under the terms of your license agreement with Intel or your
vendor. This file may be modified by the user, subject to
the additional terms of the license agreement.
@par Specification Reference:
**/
#include <XmlCliComLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BiosIdLib.h>
#include <IndustryStandard/SmBios.h>
#include <Protocol/Smbios.h>
#define CMOS_DRAM_SHARED_MB_ADDR_REG (0xF0)
#define SMBIOS_TYPE4_CPU_SOCKET_POPULATED (BIT6)
/**
Update Front Page Strings such as FirmwareVersion, ProductName,
CpuVersion, CpuSpeed, MemorySize to the XML.
@retval VOID
**/
VOID
UpdateFrontPageStrings (
VOID
);
/**
Convert Unicode String to Ascii
@param[in] Source Character pointer for Unicode string
@param[out] Destination Character pointer for ASCII string
@param[in] DestMax Length of expected ASCII Output string
@retval VOID
**/
VOID
UnicodeToAsciiUnaligned (
IN CHAR16 *Source,
OUT CHAR8 *Destination,
IN UINTN DestMax
);
/**
XmlGenerateSystemInfo function generated the SYSTEM header information in following format
<PLATFORM NAME="UNKNOWN" CPU="UNKNOWN" CHIPSET="UNKNOWN"/>
<BIOS VERSION="ADLSFWI1.R00.1394.A00.2010130909" TSTAMP="10.13.2020 at 09:09 Hrs"/>
<GBT Version="3.0302" TSTAMP="Feb 25 2015" Type="OsInternal" XmlCliVer="5.0.0" XmlCliType="Full"/>
@param[in] XmlCliCommon XmlCliCommon Structure
**/
VOID
XmlGenerateSystemInfo (
IN XML_CLI_COMMON *XmlCliCommon
)
{
XmlCreateChild("PLATFORM",0);
XmlAddAttributes("NAME","%a", "UNKNOWN");
XmlAddAttributes("CPU","%a", "UNKNOWN");
XmlAddAttributes("CHIPSET", "%a", "UNKNOWN");
XmlCloseChild();
XmlCreateChild("BIOS", 0);
XmlAddAttributes("VERSION", "%a", XmlCliCommon->BiosVersion);
XmlAddAttributes("TSTAMP", "%a", XmlCliCommon->BuildTimeStamp);
XmlCloseChild();
XmlCreateChild("GBT", 0);
// <GBT Version="3.0302" TSTAMP="Feb 25 2015" Type="OsInternal" XmlCliVer="5.0.0" XmlCliType="Full"/>
XmlAddAttributes("Version", "%a", "3.0302");
XmlAddAttributes("TSTAMP", "%a", "Feb 25 2015");
if (XmlCliCommon->XmlType == XML_OS_INT) {
XmlAddAttributes("Type", "%a", "OsInternal");
} else if (XmlCliCommon->XmlType == XML_OS_EXT) {
XmlAddAttributes("Type", "%a", "External");
} else {
XmlAddAttributes("Type", "%a", "Unknown");
}
XmlAddAttributes("XmlCliVer", "%a", XML_CLI_VERSION);
if (XmlCliCommon->EnableXmlCliLite) {
XmlAddAttributes("XmlCliType", "%a", "Lite");
} else {
XmlAddAttributes("XmlCliType", "%a", "Full");
}
XmlCloseChild();
UpdateFrontPageStrings();
}
/**
Helper Function to copy Bios Version
@param[in] StrVersion Pointer to Bios Version String
@param[in] StrTime Pointer to Timestamp String
@param[in] StrUnicode Pointer to Unicode String
@retval VOID
**/
VOID
CopyBiosVersion (
IN OUT CHAR8 *StrVersion,
IN OUT CHAR8 *StrTime,
IN CHAR16 *StrUnicode
)
{
UINT8 DotCount=0;
CHAR16 *BiosVersion=NULL;
BiosVersion = StrUnicode;
while (*BiosVersion != 0)
{
*StrVersion = (CHAR8) (*BiosVersion);
++StrVersion;
++BiosVersion;
if (DotCount < 4)
{
++StrUnicode;
}
if ((CHAR8) (*StrUnicode) == 0x2E)
{
DotCount++;
}
}
++StrUnicode;
*(StrTime++) = (CHAR8) *(StrUnicode+2);
*(StrTime++) = (CHAR8) *(StrUnicode+3);
*(StrTime++) = (CHAR8)'.'; // ' '
*(StrTime++) = (CHAR8) *(StrUnicode+4);
*(StrTime++) = (CHAR8) *(StrUnicode+5);
*(StrTime++) = (CHAR8)'.'; // ' '
*(StrTime++) = (CHAR8)'2'; // ' '
*(StrTime++) = (CHAR8)'0'; // ' '
*(StrTime++) = (CHAR8) *(StrUnicode+0);
*(StrTime++) = (CHAR8) *(StrUnicode+1);
*(StrTime++) = 0x20; // ' '
*(StrTime++) = (CHAR8)'a'; // ' '
*(StrTime++) = (CHAR8)'t'; // ' '
*(StrTime++) = 0x20; // ' '
*(StrTime++) = (CHAR8) *(StrUnicode+6);
*(StrTime++) = (CHAR8) *(StrUnicode+7);
*(StrTime++) = (CHAR8)':'; // ' '
*(StrTime++) = (CHAR8) *(StrUnicode+8);
*(StrTime++) = (CHAR8) *(StrUnicode+9);
*(StrTime++) = 0x20; // ' '
*(StrTime++) = 0x48; // 'H'
*(StrTime++) = 0x72; // 'r'
*(StrTime++) = 0x73; // 's'
*StrTime = 0;
}
/**
Helper Function to update Bios Version
Update Bios Version, timestamp details to XmlCliCommon structure from BIOS_ID_IMAGE
@param[in,out] XmlCliCommon XmlCliCommon Structure
@retval VOID
**/
VOID UpdateBiosVersionBiosRepository (
IN OUT XML_CLI_COMMON *XmlCliCommon
)
{
EFI_STATUS Status;
BIOS_ID_IMAGE BiosIdImage;
Status = GetBiosId (&BiosIdImage);
if (EFI_ERROR (Status))
{
DEBUG ((DEBUG_INFO, "XML_CLI: BIOS ID not found \n"));
} else
{
CopyBiosVersion(XmlCliCommon->BiosVersion, XmlCliCommon->BuildTimeStamp, (CHAR16 *)(UINTN)&(BiosIdImage.BiosIdString));
}
DEBUG ((DEBUG_INFO, "XML_CLI: BiosId = '%a'\n", XmlCliCommon->BiosVersion));
DEBUG ((DEBUG_INFO, "XML_CLI: timestamp = '%a'\n", XmlCliCommon->BuildTimeStamp));
}
/**
Convert Processor Frequency Data to a string.
@param[in] ProcessorFrequency The frequency data to process
@param[in] Base10Exponent The exponent based on 10
@param[out] String The string that is created
@retval VOID
**/
VOID
ConvertProcessorToString (
IN UINT16 ProcessorFrequency,
IN UINT16 Base10Exponent,
OUT CHAR16 **String
)
{
UINT32 FreqMhz;
UINTN Index;
CHAR16 *StringBuffer;
if (Base10Exponent >= 6) {
FreqMhz = ProcessorFrequency;
for (Index = 0; Index < ((UINT32)Base10Exponent - 6); Index++) {
FreqMhz *= 10;
}
} else {
FreqMhz = 0;
}
StringBuffer = AllocateZeroPool (0x20);
ASSERT (StringBuffer != NULL);
if (StringBuffer != NULL) {
UnicodeValueToStringS (StringBuffer, 0x20, LEFT_JUSTIFY, FreqMhz / 1000, 3);
Index = StrnLenS (StringBuffer, 0x20 / sizeof (CHAR16));
StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L".");
UnicodeValueToStringS (StringBuffer + Index + 1, 0x20 - sizeof (CHAR16) * (Index + 1), PREFIX_ZERO, (FreqMhz % 1000) / 10, 2);
StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" GHz");
*String = (CHAR16 *) StringBuffer;
}
return ;
}
/**
Convert Memory Size to a string.
@param[in] MemorySize The size of the memory to process
@param[out] String The string that is created
@retval VOID
**/
VOID
ConvertMemorySizeToString (
IN UINT32 MemorySize,
OUT CHAR16 **String
)
{
CHAR16 *StringBuffer;
StringBuffer = AllocateZeroPool (0x20);
ASSERT (StringBuffer != NULL);
if (StringBuffer != NULL) {
UnicodeValueToStringS (StringBuffer, 0x20, LEFT_JUSTIFY, MemorySize, 6);
StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" MB RAM");
*String = (CHAR16 *) StringBuffer;
}
return ;
}
/**
Acquire the string associated with the Index from smbios structure and return it.
The caller is responsible for free the string buffer.
@param[in] OptionalStrStart The start position to search the string
@param[in] Index The index of the string to extract
@param[out] String The string that is extracted
@retval EFI_SUCCESS String Found and copied successfully
@retval !EFI_SUCCESS Failure
**/
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
//
*String = L"Missing String";
} else {
*String = AllocatePool (StrSize * sizeof (CHAR16));
AsciiStrToUnicodeStrS (OptionalStrStart, *String, StrSize);
}
return EFI_SUCCESS;
}
/**
Update Front Page Strings such as FirmwareVersion, ProductName,
CpuVersion, CpuSpeed, MemorySize to the XML.
@retval VOID
**/
VOID
UpdateFrontPageStrings (
VOID
)
{
BOOLEAN Find[5];
CHAR8 AsciiStrBlock[0x100];
UINT8 StrIndex;
CHAR16 *NewString;
UINT64 InstalledMemory;
EFI_STATUS Status;
EFI_SMBIOS_HANDLE SmbiosHandle;
EFI_SMBIOS_PROTOCOL *Smbios;
EFI_SMBIOS_TABLE_HEADER *Record;
SMBIOS_TABLE_TYPE1 *Type1Record;
SMBIOS_TABLE_TYPE4 *Type4Record;
SMBIOS_TABLE_TYPE19 *Type19Record;
InstalledMemory = 0;
ZeroMem (Find, sizeof (Find));
//
// Update Front Page strings
//
Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &Smbios);
if (EFI_ERROR (Status)) {
return ;
}
SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
XmlCreateChild("FrontPage", 0); // <PCH-reference Version="0.7.0-00"/>
do {
Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
if (EFI_ERROR(Status)) {
break;
}
if (Record->Type == EFI_SMBIOS_TYPE_BIOS_INFORMATION) {
BIOS_ID_IMAGE BiosIdImage;
Status = GetBiosId (&BiosIdImage);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "XML_CLI: BIOS ID not found \n"));
XmlAddAttributes("FirmwareVersion", "??");
} else {
UnicodeToAsciiUnaligned((CHAR16*)((UINTN)&BiosIdImage.BiosIdString), AsciiStrBlock, sizeof(AsciiStrBlock));
XmlAddAttributes("FirmwareVersion", "%a", HandleSpecialXmlChars(AsciiStrBlock));
}
Find[0] = TRUE;
}
if (Record->Type == EFI_SMBIOS_TYPE_SYSTEM_INFORMATION) {
Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
StrIndex = Type1Record->ProductName;
GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
if (NewString != NULL) {
UnicodeToAsciiUnaligned(NewString, AsciiStrBlock, sizeof(AsciiStrBlock));
XmlAddAttributes("ProductName", "%a", HandleSpecialXmlChars(AsciiStrBlock));
} else {
DEBUG ((DEBUG_INFO, "XML_CLI: ProductName not found \n"));
XmlAddAttributes("ProductName", "??");
}
FreePool (NewString);
Find[1] = TRUE;
}
if ((Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) && !Find[2]) {
Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
//
// The information in the record should be only valid when the CPU Socket is populated.
//
if ((Type4Record->Status & SMBIOS_TYPE4_CPU_SOCKET_POPULATED) == SMBIOS_TYPE4_CPU_SOCKET_POPULATED) {
StrIndex = Type4Record->ProcessorVersion;
GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
if (NewString != NULL){
UnicodeToAsciiUnaligned(NewString, AsciiStrBlock, sizeof(AsciiStrBlock));
XmlAddAttributes("CpuVersion", "%a", HandleSpecialXmlChars(AsciiStrBlock));
} else {
DEBUG ((DEBUG_INFO, "XML_CLI: CpuVersion not found \n"));
XmlAddAttributes("CpuVersion", "??");
}
FreePool (NewString);
Find[2] = TRUE;
}
}
if ((Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) && !Find[3]) {
Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
//
// The information in the record should be only valid when the CPU Socket is populated.
//
if ((Type4Record->Status & SMBIOS_TYPE4_CPU_SOCKET_POPULATED) == SMBIOS_TYPE4_CPU_SOCKET_POPULATED) {
ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString);
if (NewString != NULL){
UnicodeToAsciiUnaligned(NewString, AsciiStrBlock, sizeof(AsciiStrBlock));
XmlAddAttributes("CpuSpeed", "%a", HandleSpecialXmlChars(AsciiStrBlock));
} else {
DEBUG ((DEBUG_INFO, "XML_CLI: CpuSpeed not found \n"));
XmlAddAttributes("CpuSpeed", "??");
}
FreePool (NewString);
Find[3] = TRUE;
}
}
if (Record->Type == EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS) {
Type19Record = (SMBIOS_TABLE_TYPE19 *) Record;
if (Type19Record->StartingAddress != 0xFFFFFFFF) {
InstalledMemory += RShiftU64(Type19Record->EndingAddress - Type19Record->StartingAddress + 1, 10);
} else {
InstalledMemory += RShiftU64(Type19Record->ExtendedEndingAddress - Type19Record->ExtendedStartingAddress + 1, 20);
}
}
} while (!(Find[0] && Find[1] && Find[2] && Find[3] && Find[4]));
ConvertMemorySizeToString ((UINT32)InstalledMemory, &NewString);
if (NewString != NULL) {
UnicodeToAsciiUnaligned(NewString, AsciiStrBlock, sizeof(AsciiStrBlock));
XmlAddAttributes("MemorySize", "%a", HandleSpecialXmlChars(AsciiStrBlock));
} else {
DEBUG ((DEBUG_INFO, "XML_CLI: MemorySize not found \n"));
XmlAddAttributes("MemorySize", "??");
}
FreePool (NewString);
Find[4] = TRUE;
XmlCloseChild();
}
/**
Helper function to Convert Hex array to ascii values.
Takes input as pointer hex values and start offset to
convert to ascii string
@param[in,out] AsciiStr Pointer to Ascii String to be stored
@param[in] InHexVal Pointer to the hex values
@param[in] VarLength Number of hex values to be converted to ascii string
@retval VOID
**/
VOID
ConvHexArray2asciiVal (
IN OUT CHAR8 *AsciiStr,
IN UINT8 *InHexVal,
IN UINTN VarLength
)
{
UINTN Index=0;
CHAR8 HexStr[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
for (Index = 0; Index < VarLength; Index++) {
AsciiStr[(Index*2)] = HexStr[((InHexVal[(VarLength-1-Index)] >> 4) & 0xF)];
AsciiStr[(Index*2)+1] = HexStr[(InHexVal[(VarLength-1-Index)] & 0xF)];
}
}
/**
Helper function to write Dram Mailbox Address to CMOS
As the mailbox address is reserved area and may change,
hence saving in CMOS for the tool to read
@param[in] DramMbAddress Address of Dram Mailbox
@retval VOID
**/
VOID
WriteDramMbAddr2Cmos (
IN UINT32 DramMbAddress
)
{
IoWrite8(0x72, (UINT8)CMOS_DRAM_SHARED_MB_ADDR_REG); // Save the Mailbox address in CMOS so that the tool can read it
IoWrite8(0x73, (UINT8)(DramMbAddress >> 16)); // save lower byte of higher UINT16
IoWrite8(0x72, (UINT8)CMOS_DRAM_SHARED_MB_ADDR_REG+1);
IoWrite8(0x73, (UINT8)(DramMbAddress >> 24)); // save upper byte of higher UINT16
}
UINT64 AndMask[] = {0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF, 0xFFFFFFFFFF, 0xFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF};
/**
Extracts Byte Size from given BIT size
@param[in] UINT8 Bit Offset within the given Byte (max Value of 7)
@param[in] UINT8 Bit Size (max value of 63)
@retval UINT8 Extracted byte Size
**/
UINT8
BitGetByteSize (
IN UINT8 BitOffset,
IN UINT8 BitSize
)
{
UINT8 ByteSize;
ByteSize = BitOffset + BitSize;
if (ByteSize % 8) {
ByteSize = (ByteSize/8) + 1;
} else {
ByteSize = (ByteSize/8);
}
return ByteSize;
}
/**
Extracts BIT Value from given Bit Offset for given Bit Size
@param[in] UINT64 Input Value
@param[in] UINT8 Offset within the given Byte (max Value of 7)
@param[in] UINT8 Size (max value of 63)
@retval UINT64 Extracted Value
**/
UINT64
BitExtractValue64 (
IN UINT64 InputVal,
IN UINT8 BitOffset,
IN UINT8 BitSize
)
{
UINT8 ByteSize;
ByteSize = BitGetByteSize(BitOffset, BitSize);
return (UINT64)(InputVal >> BitOffset) & (AndMask[ByteSize] >> ((ByteSize*8) - BitSize));
}
/**
BIT wise Compare function
@param[in] VOID Destination Buffer Pointer
@param[in] VOID Source Buffer Pointer
@param[in] UINT8 Bit Offset within the given Byte (max Value of 7)
@param[in] UINT8 Bit Size (max value of 63)
@param[in] UINT8 CompareType (will be 0 if Source is Absolute Value that start at BIT00, else 1)
@retval BOOLEAN (TRUE if Value Matches)
**/
BOOLEAN
BitDataMatch64 (
IN VOID* Destination,
IN VOID* Source,
IN UINT8 BitOffset,
IN UINT8 BitSize,
IN UINT8 CompareType
)
{
UINT8 ByteSize;
UINT64 BitMask;
UINT64 DstVal=0;
UINT64 SrcVal=0;
ByteSize = BitGetByteSize(BitOffset, BitSize);
BitMask = (UINT64)(AndMask[ByteSize] >> ((ByteSize*8) - BitSize));
CopyMem(&DstVal,Destination, ByteSize);
CopyMem(&SrcVal,Source, ByteSize);
if (0 == CompareType) {
SrcVal = (UINT64)(SrcVal & BitMask);
} else {
SrcVal = (UINT64)((SrcVal >> BitOffset) & BitMask);
}
DstVal = (UINT64)((DstVal >> BitOffset) & BitMask);
if (SrcVal == DstVal) {
return TRUE;
} else {
return FALSE;
}
}
/**
BIT wise Copy function
@param[in] VOID Destination Buffer Pointer
@param[in] VOID Source Buffer Pointer
@param[in] UINT8 Bit Offset within the given Byte (max Value of 7)
@param[in] UINT8 Bit Size (max value of 63)
@retval VOID
**/
VOID
BitDataCopy64 (
IN VOID* Destination,
IN VOID* Source,
IN UINT8 BitOffset,
IN UINT8 BitSize
)
{
UINT8 ByteSize;
UINT64 BitMask;
UINT64 DstVal=0;
UINT64 SrcVal=0;
ByteSize = BitGetByteSize(BitOffset, BitSize);
BitMask = ((UINT64)(AndMask[ByteSize] >> ((ByteSize*8) - BitSize)) << BitOffset);
CopyMem(&DstVal,Destination, ByteSize);
CopyMem(&SrcVal,Source, ByteSize);
SrcVal = (UINT64)((SrcVal << BitOffset) & BitMask);
DstVal = (UINT64)((DstVal & (~BitMask)) | SrcVal);
CopyMem(Destination,(VOID*)&DstVal, ByteSize);
}
/**
Fetch the correct index for the given Bitwise knob
If Index not found then 0xFFFF will be returned
@param[in] UINT32 KnobEntryAddress
@param[in] UINT32 KnobValMapAddr
@param[in] UINT16 ParentIndex
@param[in] UINT8 BitField
@retval UINT16 Index Value
**/
UINT16
BitFetchIndex (
UINT32 KnobEntryAddress,
UINT32 KnobValMapAddr,
UINT16 ParentIndex,
UINT8 BitField
)
{
UINT16 Index;
KNOB_ENTRY_TBL_BITWISE *KnobXmlEntryPtr = (KNOB_ENTRY_TBL_BITWISE*)(UINTN)KnobEntryAddress;
BIT_KNOB_INDEX_LOOKUP *BitKnobLookup;
if(KnobXmlEntryPtr[ParentIndex].IsBitWise) {
if(KnobXmlEntryPtr[ParentIndex].StartIndex == KnobXmlEntryPtr[ParentIndex].EndIndex) {
return (UINT16)KnobXmlEntryPtr[ParentIndex].StartIndex;
} else {
for (Index = (UINT16)KnobXmlEntryPtr[ParentIndex].StartIndex; Index <= (UINT16)KnobXmlEntryPtr[ParentIndex].EndIndex; Index++) {
if (KnobXmlEntryPtr[Index].IsBitWise == 0) {
continue;
}
BitKnobLookup = (BIT_KNOB_INDEX_LOOKUP*)(UINTN)(KnobValMapAddr + ((KNOB_ENTRY_TBL*)KnobXmlEntryPtr)[Index].KnobValMapOffset - sizeof(BIT_KNOB_INDEX_LOOKUP));
if ((BitKnobLookup->ByteOffset == ParentIndex) && (BitKnobLookup->BitField == BitField)) {
return Index;
break;
}
}
}
}
return 0xFFFF; // to indicate Index not found
}