465 lines
12 KiB
C
465 lines
12 KiB
C
/** @file
|
|
Get BIOS version, product name and CCB version from BVDT region.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2020, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include <Library/BvdtLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <Library/DebugLib.h>
|
|
|
|
/**
|
|
Converts ASCII characters to Unicode.
|
|
|
|
@param UnicodeStr The Unicode string to be written to.
|
|
The buffer must be large enough.
|
|
@param AsciiStr The ASCII string to be converted.
|
|
|
|
|
|
@return The address to the Unicode string - same as UnicodeStr.
|
|
|
|
**/
|
|
STATIC
|
|
CHAR16 *
|
|
BvdtLibAscii2Unicode (
|
|
OUT CHAR16 *UnicodeStr,
|
|
IN CHAR8 *AsciiStr
|
|
)
|
|
{
|
|
CHAR16 *Str;
|
|
|
|
Str = UnicodeStr;
|
|
|
|
while (TRUE) {
|
|
*(UnicodeStr++) = (CHAR16) *AsciiStr;
|
|
if (*(AsciiStr++) == '\0') {
|
|
return Str;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Compare the ASCII strings in length.
|
|
|
|
@param String - Compare to String2
|
|
@param String2 - Compare to String
|
|
@param Length - Number of ASCII characters to compare
|
|
|
|
@return == 0 - The substring of String and String2 is identical.
|
|
> 0 - The substring of String sorts lexicographically after String2
|
|
< 0 - The substring of String sorts lexicographically before String2
|
|
**/
|
|
STATIC
|
|
INTN
|
|
BvdtLibAsciiStrnCmp (
|
|
IN CHAR8 *String,
|
|
IN CHAR8 *String2,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
if (Length == 0) {
|
|
return 0;
|
|
}
|
|
|
|
while ((*String != '\0') && (*String == *String2) && (Length > 1)) {
|
|
String++;
|
|
String2++;
|
|
Length--;
|
|
}
|
|
|
|
return *String - *String2;
|
|
}
|
|
|
|
/**
|
|
Converts an 8-bit BCD value to an 8-bit value.
|
|
|
|
@param[in] Value The 8-bit BCD value to convert to an 8-bit value.
|
|
|
|
@return The 8-bit value is returned.
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
BcdToDecimal (
|
|
IN UINT8 Value
|
|
)
|
|
{
|
|
ASSERT (Value < 0xa0);
|
|
ASSERT ((Value & 0xf) < 0xa);
|
|
return (UINT8) ((Value >> 4) * 10 + (Value & 0xf));
|
|
}
|
|
|
|
/**
|
|
Check if it is a leap year
|
|
|
|
@param[in] Year Year value
|
|
|
|
@retval TRUE It is a leap year
|
|
@retval FALSE It is NOT a leap year
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsLeapYear (
|
|
IN UINT16 Year
|
|
)
|
|
{
|
|
if (Year % 4 == 0) {
|
|
if (Year % 100 == 0) {
|
|
if (Year % 400 == 0) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Check if Day field of input EFI time is valid
|
|
|
|
@param[in] EfiTime The Day field of input EFI time is to be checked
|
|
|
|
@retval TRUE Day field of input EFI time is valid.
|
|
@retval FALSE Day field of input EFI time is NOT valid.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsDayValid (
|
|
IN EFI_TIME *EfiTime
|
|
)
|
|
{
|
|
UINT8 DayOfMonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
if (EfiTime->Month < 1 ||
|
|
EfiTime->Month > 12) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (EfiTime->Day < 1 ||
|
|
EfiTime->Day > DayOfMonth[EfiTime->Month - 1] ||
|
|
(EfiTime->Month == 2 && (!IsLeapYear (EfiTime->Year) && EfiTime->Day > 28))) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Check if input EFI time is valid
|
|
|
|
@param[in] EfiTime The EFI time is to be checked
|
|
|
|
@retval TRUE Input EFI time is valid.
|
|
@retval FALSE Input EFI time is NOT valid.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
IsEfiTimeValid (
|
|
IN EFI_TIME *EfiTime
|
|
)
|
|
{
|
|
if (EfiTime->Year < 1900 ||
|
|
EfiTime->Year > 9999 ||
|
|
EfiTime->Month < 1 ||
|
|
EfiTime->Month > 12 ||
|
|
(!IsDayValid (EfiTime)) ||
|
|
EfiTime->Hour > 23 ||
|
|
EfiTime->Minute > 59 ||
|
|
EfiTime->Second > 59) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Get BVDT date data
|
|
|
|
@param[in] BvdtDatePtr Pointer to BVDT date data
|
|
@param[out] EfiTime A pointer to storage BVDT date in EFI time structure
|
|
|
|
@retval EFI_SUCCESS Successfully get BVDT date data
|
|
@retval EFI_INVALID_PARAMETER Input parameter is NULL
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetBvdtDate (
|
|
IN UINT8 *BvdtDatePtr,
|
|
OUT EFI_TIME *EfiTime
|
|
)
|
|
{
|
|
if (BvdtDatePtr == NULL || EfiTime == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EfiTime->Year = (UINT16) BcdToDecimal (BvdtDatePtr[0]) + 2000;
|
|
EfiTime->Month = BcdToDecimal (BvdtDatePtr[1]);
|
|
EfiTime->Day = BcdToDecimal (BvdtDatePtr[2]);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get BVDT time data
|
|
|
|
@param[in] BvdtTimePtr Pointer to BVDT time data
|
|
@param[out] EfiTime A pointer to storage BVDT time in EFI time structure
|
|
|
|
@retval EFI_SUCCESS Successfully get BVDT time data
|
|
@retval EFI_INVALID_PARAMETER Input parameter is NULL
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetBvdtTime (
|
|
IN UINT8 *BvdtTimePtr,
|
|
OUT EFI_TIME *EfiTime
|
|
)
|
|
{
|
|
if (BvdtTimePtr == NULL || EfiTime == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EfiTime->Hour = BcdToDecimal (BvdtTimePtr[0]);
|
|
EfiTime->Minute = BcdToDecimal (BvdtTimePtr[1]);
|
|
EfiTime->Second = BcdToDecimal (BvdtTimePtr[2]);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get the pointer of BIOS release date infomation from BVDT
|
|
|
|
@return The pointer of BIOS release date infomation or NULL if not found
|
|
**/
|
|
STATIC
|
|
UINT8 *
|
|
GetBiosReleaseDatePtr (
|
|
VOID
|
|
)
|
|
{
|
|
UINT8 RelaseDateTag[] = RELEASE_DATE_TAG;
|
|
UINT8 *Bvdt;
|
|
UINTN Index;
|
|
UINT64 BvdtSize;
|
|
|
|
BvdtSize = FdmGetNAtSize(&gH2OFlashMapRegionBvdtGuid, 1);
|
|
Bvdt = (UINT8 *)(UINTN)FdmGetNAtAddr(&gH2OFlashMapRegionBvdtGuid, 1);
|
|
if (Bvdt == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Search for "$RDATE" from BVDT dynamic signature start
|
|
//
|
|
for (Index = MULTI_BIOS_VERSION_OFFSET; Index < BvdtSize; Index++) {
|
|
if (CompareMem(Bvdt + Index, RelaseDateTag, sizeof(RelaseDateTag)) == 0) {
|
|
return (Bvdt + Index + sizeof (RelaseDateTag));
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Get BIOS version, product name, CCB version, multiple BIOS version, multiple product name
|
|
or multiple CCB verion from BVDT region.
|
|
|
|
@param[in] Type Information type of BVDT.
|
|
@param[in, out] StrBufferLen Input : string buffer length
|
|
Output: length of BVDT information string.
|
|
@param[out] StrBuffer BVDT information string.
|
|
|
|
@retval EFI_SUCCESS Successly get string.
|
|
@retval EFI_BUFFER_TOO_SMALL Buffer was too small. The current length of information string
|
|
needed to hold the string is returned in BufferSize.
|
|
@retval EFI_INVALID_PARAMETER Input invalid type of BVDT information.
|
|
BufferSize or Buffer is NULL.
|
|
@retval EFI_NOT_FOUND Can not find information of multiple version, multiple product name
|
|
or multiple CCB verion or BVDT build time is invalid
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetBvdtInfo (
|
|
IN BVDT_TYPE Type,
|
|
IN OUT UINTN *StrBufferLen,
|
|
OUT CHAR16 *StrBuffer
|
|
)
|
|
{
|
|
UINTN StrLen;
|
|
UINT64 BvdtAddr;
|
|
CHAR8 *StrPtr;
|
|
CHAR8 MultiBiosVerSignature[] = {'$', 'V', 'E', 'R', 'E', 'X'};
|
|
CHAR8 MultiProductNameSignature[] = {'$', 'P', 'R', 'O', 'D', 'E', 'X'};
|
|
CHAR8 MultiCcbVerSignature[] = {'$', 'C', 'C', 'B', 'V', 'E', 'X'};
|
|
CHAR8 AsciiStrBuffer[BVDT_MAX_STR_SIZE];
|
|
EFI_TIME EfiTime;
|
|
|
|
if ((StrBuffer == NULL) || (StrBufferLen == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
BvdtAddr = FdmGetNAtAddr(&gH2OFlashMapRegionBvdtGuid, 1);
|
|
if (BvdtAddr == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
switch (Type) {
|
|
|
|
case BvdtBuildDate:
|
|
case BvdtBuildTime:
|
|
ZeroMem (&EfiTime, sizeof (EfiTime));
|
|
GetBvdtDate ((UINT8 *) (UINTN) (BvdtAddr + BIOS_BUILD_DATE_OFFSET), &EfiTime);
|
|
GetBvdtTime ((UINT8 *) (UINTN) (BvdtAddr + BIOS_BUILD_TIME_OFFSET), &EfiTime);
|
|
if (!IsEfiTimeValid (&EfiTime)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (Type == BvdtBuildDate) {
|
|
AsciiSPrint (AsciiStrBuffer, sizeof (AsciiStrBuffer), "%02d/%02d/%04d", EfiTime.Month, EfiTime.Day, EfiTime.Year);
|
|
} else {
|
|
AsciiSPrint (AsciiStrBuffer, sizeof (AsciiStrBuffer), "%02d:%02d:%02d", EfiTime.Hour, EfiTime.Minute, EfiTime.Second);
|
|
}
|
|
StrPtr = AsciiStrBuffer;
|
|
break;
|
|
|
|
case BvdtBiosVer:
|
|
StrPtr = (CHAR8 *) (UINTN) (BvdtAddr + BIOS_VERSION_OFFSET);
|
|
break;
|
|
|
|
case BvdtProductName:
|
|
StrPtr = (CHAR8 *) (UINTN) (BvdtAddr + PRODUCT_NAME_OFFSET);
|
|
break;
|
|
|
|
case BvdtCcbVer:
|
|
StrPtr = (CHAR8 *) (UINTN) (BvdtAddr + CCB_VERSION_OFFSET);
|
|
break;
|
|
|
|
case BvdtMultiBiosVer:
|
|
StrPtr = (CHAR8 *) (UINTN) (BvdtAddr + MULTI_BIOS_VERSION_OFFSET);
|
|
if (BvdtLibAsciiStrnCmp (StrPtr, MultiBiosVerSignature, sizeof (MultiBiosVerSignature))) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
StrPtr = (CHAR8 *) ((UINTN) StrPtr + sizeof (MultiBiosVerSignature));
|
|
break;
|
|
|
|
case BvdtMultiProductName:
|
|
StrPtr = (CHAR8 *) (UINTN) (BvdtAddr + MULTI_BIOS_VERSION_OFFSET);
|
|
if (!BvdtLibAsciiStrnCmp (StrPtr, MultiBiosVerSignature, sizeof (MultiBiosVerSignature))) {
|
|
StrPtr = (CHAR8 *) ((UINTN) StrPtr + AsciiStrSize (StrPtr));
|
|
}
|
|
|
|
if (BvdtLibAsciiStrnCmp (StrPtr, MultiProductNameSignature, sizeof (MultiProductNameSignature))) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
StrPtr = (CHAR8 *) ((UINTN) StrPtr + sizeof (MultiProductNameSignature));
|
|
break;
|
|
|
|
case BvdtMultiCcbVer:
|
|
StrPtr = (CHAR8 *) (UINTN) (BvdtAddr + MULTI_BIOS_VERSION_OFFSET);
|
|
if (!BvdtLibAsciiStrnCmp (StrPtr, MultiBiosVerSignature, sizeof (MultiBiosVerSignature))) {
|
|
StrPtr = (CHAR8 *) ((UINTN) StrPtr + AsciiStrSize (StrPtr));
|
|
}
|
|
|
|
if (!BvdtLibAsciiStrnCmp (StrPtr, MultiProductNameSignature, sizeof (MultiProductNameSignature))) {
|
|
StrPtr = (CHAR8 *) ((UINTN) StrPtr + AsciiStrSize (StrPtr));
|
|
}
|
|
|
|
if (BvdtLibAsciiStrnCmp (StrPtr, MultiCcbVerSignature, sizeof (MultiCcbVerSignature))) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
StrPtr = (CHAR8 *) ((UINTN) StrPtr + sizeof (MultiCcbVerSignature));
|
|
break;
|
|
|
|
case BvdtReleaseDate:
|
|
ZeroMem (&EfiTime, sizeof (EfiTime));
|
|
GetBvdtDate (GetBiosReleaseDatePtr (), &EfiTime);
|
|
if (!IsEfiTimeValid (&EfiTime)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
AsciiSPrint (AsciiStrBuffer, sizeof (AsciiStrBuffer), "%02d/%02d/%04d", EfiTime.Month, EfiTime.Day, EfiTime.Year);
|
|
StrPtr = AsciiStrBuffer;
|
|
break;
|
|
|
|
default:
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
StrLen = AsciiStrSize (StrPtr);
|
|
|
|
if (StrLen > *StrBufferLen) {
|
|
*StrBufferLen = StrLen;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
*StrBufferLen = StrLen;
|
|
BvdtLibAscii2Unicode (StrBuffer, StrPtr);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get ESRT System Firmware GUID and Version information from BVDT $ESRT tag
|
|
|
|
@param[out] FirmwareGuid Pointer to the system firmware version GUID
|
|
@param[out] FirmwareVersion Pointer to the system firmware version
|
|
|
|
@retval EFI_SUCCESS System firmware GUID and system firmware version
|
|
are successfully retrieved
|
|
EFI_NOT_FOUND Unable to find system firmware GUID or system firmware
|
|
version in the BVDT table
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetEsrtFirmwareInfo (
|
|
OUT EFI_GUID *FirmwareGuid,
|
|
OUT UINT32 *FirmwareVersion
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT8 *Bvdt;
|
|
UINT8 *EsrtTagPtr;
|
|
UINT8 EsrtTag[] = ESRT_TAG;
|
|
UINT64 BvdtSize;
|
|
|
|
if (FirmwareGuid == NULL || FirmwareVersion == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Bvdt = (UINT8 *)(UINTN) FdmGetNAtAddr (&gH2OFlashMapRegionBvdtGuid, 1);
|
|
if (Bvdt == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
BvdtSize = FdmGetNAtSize (&gH2OFlashMapRegionBvdtGuid, 1);
|
|
|
|
//
|
|
// Search for "$ESRT" from BVDT dynamic signature start
|
|
//
|
|
for (Index = MULTI_BIOS_VERSION_OFFSET; Index < BvdtSize; Index++) {
|
|
if (CompareMem(Bvdt + Index, EsrtTag, sizeof(EsrtTag)) == 0) {
|
|
EsrtTagPtr = Bvdt + Index;
|
|
*FirmwareVersion = *(UINT32 *)(EsrtTagPtr + sizeof(EsrtTag));
|
|
*FirmwareGuid = *(EFI_GUID *)(EsrtTagPtr + sizeof(EsrtTag) + sizeof(UINT32));
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|