alder_lake_bios/Insyde/InsydeModulePkg/Library/FlashRegionLib/PeiFlashRegionLib/PeiFlashRegionLib.c

1085 lines
30 KiB
C

/** @file
Library for Getting Information of Flash Device Region Layout
;******************************************************************************
;* Copyright (c) 2014 - 2021, 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 <Uefi.h>
#include <Guid/H2OCp.h>
#include <Library/BaseCryptLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PcdLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/FlashRegionLib.h>
#include <Library/BaseLib.h>
#include <Library/H2OFvHashLib.h>
#include <Library/PerformanceLib.h>
#include <Library/H2OCpLib.h>
#include <Library/PostCodeLib.h>
#include <Library/DebugLib.h>
#include <Library/H2OLib.h>
#include <Library/HobLib.h>
#include <Ppi/Pcd.h>
#include <Ppi/PcdInfo.h>
//
// FDM signature, for not having signature in machine code of this library, assign value one by one byte
//
STATIC CHAR8 mSignature[] = {'H', 'F', 'D', 'M'};
STATIC EFI_GUID mFdmAddressHobGuid = { 0xcfae18a2, 0x35e1, 0x4ff1, { 0x8f, 0x98, 0xeb, 0x84, 0xcd, 0x70, 0xff, 0xb0 } };
/**
Get Base Address
@return Base Address
**/
UINT64
EFIAPI
FdmGetBaseAddr (
VOID
){
H2O_FLASH_DEVICE_MAP_HEADER *FdmHeader;
EFI_PEI_HOB_POINTERS Hob;
UINT64 *FdmRegionAddress;
FdmHeader =(H2O_FLASH_DEVICE_MAP_HEADER*)(UINTN) PcdGet64(PcdH2OFlashDeviceMapStart);
if (FdmHeader == NULL){
return 0;
}
if ( CompareMem(FdmHeader, mSignature, sizeof(mSignature))){
return 0;
}
Hob.Raw = GetFirstGuidHob (&mFdmAddressHobGuid);
if (Hob.Raw == NULL) {
FdmRegionAddress = BuildGuidHob (&mFdmAddressHobGuid, sizeof(UINT64));
if (FdmRegionAddress != NULL){
*FdmRegionAddress = PcdGet64(PcdH2OFlashDeviceMapStart);
}
}
return FdmHeader->FdBaseAddr;
}
STATIC
BOOLEAN
EFIAPI
IsFdmHeaderValid (
IN H2O_FLASH_DEVICE_MAP_HEADER *FdmHeader
){
UINT32 Index;
UINT8 Sum;
UINT8 *Data;
Sum = 0;
Data = (UINT8*) FdmHeader;
//
// Verify check sum
//
for (Index = 0; Index < sizeof (H2O_FLASH_DEVICE_MAP_HEADER); Index++, Data++){
Sum += (*Data);
}
return (Sum == 0);
}
/**
SHA256 HASH calculation
@param [in] Message The message data to be calculated
@param [in] MessageSize The size in byte of the message data
@param [out] Digest The caclulated HASH digest
@return EFI_SUCCESS The HASH value is calculated
@return EFI_SECURITY_VIOLATION Failed to calculate the HASH
**/
STATIC
EFI_STATUS
EFIAPI
CalculateSha256Hash (
IN UINT8 *Message,
IN UINTN MessageSize,
OUT UINT8 *Digest
)
{
VOID *HashCtx;
UINTN CtxSize;
EFI_STATUS Status;
SetMem (Digest, SHA256_DIGEST_SIZE, 0);
CtxSize = Sha256GetContextSize ();
HashCtx = NULL;
HashCtx = AllocatePool (CtxSize);
if (HashCtx == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (!Sha256Init (HashCtx)) {
Status = EFI_SECURITY_VIOLATION;
goto Done;
}
if(!Sha256Update (HashCtx, Message, MessageSize)) {
Status = EFI_SECURITY_VIOLATION;
goto Done;
}
if(!Sha256Final (HashCtx, Digest)) {
Status = EFI_SECURITY_VIOLATION;
} else {
Status = EFI_SUCCESS;
}
Done:
FreePool (HashCtx);
return Status;
}
STATIC
EFI_STATUS
EFIAPI
VerifyHash (
IN UINT8 HashMethod,
IN UINT8 *Hash,
IN UINT8 *Message,
IN UINTN MessageSize
){
EFI_STATUS Status;
UINT8 *Digest;
UINT8 *HashBuffer;
UINTN DigestSize;
if (Hash == NULL){
return EFI_INVALID_PARAMETER;
}
if (Message == NULL){
return EFI_INVALID_PARAMETER;
}
switch (HashMethod){
case ENTRY_HASH_SHA256:
Digest = AllocatePool (SHA256_DIGEST_SIZE);
if (Digest == NULL){
return EFI_OUT_OF_RESOURCES;
}
HashBuffer = H2OGetFvHash (H2O_SHA256_FV_HASH, (UINTN) Message, MessageSize);
if (HashBuffer != NULL) {
CopyMem (Digest, HashBuffer, SHA256_DIGEST_SIZE);
} else {
Status = CalculateSha256Hash (Message, MessageSize, Digest);
if (EFI_ERROR(Status)){
return Status;
}
H2OSetFvHash (H2O_SHA256_FV_HASH, (UINTN) Message, MessageSize, Digest);
}
DigestSize = SHA256_DIGEST_SIZE;
break;
default:
return EFI_UNSUPPORTED;
break;
}
if (CompareMem (Digest, Hash, DigestSize)){
Status = EFI_SECURITY_VIOLATION;
goto done;
} else {
Status = EFI_SUCCESS;
goto done;
}
done:
if (Digest != NULL){
FreePool (Digest);
}
return Status;
}
/**
Get count of entries that FDM recorded
@param Count Unsigned integer that specifies the count of entries that FDM recorded.
@return EFI_SUCCESS find region type success.
@return EFI_NOT_FOUND Can't find region type in the FDM.
**/
EFI_STATUS
EFIAPI
FdmGetCount (
OUT UINT8 *Count
)
{
H2O_FLASH_DEVICE_MAP_HEADER *FdmHeader;
UINT8 *Entry;
UINT32 FirstEntryOffset;
UINT32 EntrySize;
UINT32 Size;
UINT8 *Entries;
UINT8 *EndPtr;
UINT8 InstanceNotIgnored;
*Count = 0;
FdmHeader =(H2O_FLASH_DEVICE_MAP_HEADER*)(UINTN) PcdGet64(PcdH2OFlashDeviceMapStart);
if ((FdmHeader == NULL) || CompareMem(FdmHeader, mSignature, sizeof(mSignature))){
return EFI_NOT_FOUND;
}
if (!IsFdmHeaderValid ((H2O_FLASH_DEVICE_MAP_HEADER *) FdmHeader)) {
return EFI_SECURITY_VIOLATION;
}
FirstEntryOffset = FdmHeader->Offset;
Size = FdmHeader->Size;
EntrySize = FdmHeader->EntrySize;
Entries = ((UINT8*) FdmHeader) + FirstEntryOffset;
EndPtr = ((UINT8*) FdmHeader) + Size;
InstanceNotIgnored = 0;
for (Entry = Entries;;){
if (Entry >= EndPtr){
break;
}
if ((((H2O_FLASH_DEVICE_MAP_ENTRY*) Entry)->Attribs & H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_IGNORE) != H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_IGNORE){
InstanceNotIgnored++;
}
Entry += EntrySize;
}
*Count = InstanceNotIgnored;
return EFI_SUCCESS;
}
/**
Get Region type record in FDM by specifying order in the list.
@param RegionType EFI_GUID that specifies the type of region that search for.
@param Instance Unsigned integer that specifies the N-th Region type instance
@param RegionId Identifier that specifies the identifier of this region..
@param RegionOffset Unsigned integer that specifies the offset of this region relative to the
base of the flash device image.
@param RegionSize Unsigned integer that specifies the region size.
@param Attribs Bitmap that specifies the attributes of the flash device map entry.
@return EFI_SUCCESS find region type success.
@return EFI_INVALID_PARAMETER Incorrect parameter.
@return EFI_SECURITY_VIOLATION Region hash is not correct.
@return EFI_NOT_FOUND Can't find region type in the FDM.
**/
EFI_STATUS
EFIAPI
FdmGetNAt (
CONST IN EFI_GUID *RegionType,
CONST IN UINT8 Instance,
OUT UINT8 *RegionId,
OUT UINT64 *RegionOffset,
OUT UINT64 *RegionSize,
OUT UINT32 *Attribs
){
UINT8 *EndPtr;
UINT8 Matched;
UINT32 EntrySize;
H2O_FLASH_DEVICE_MAP_ENTRY *Entry;
UINT8 *Fdm;
*RegionId = 0;
*RegionOffset = 0;
*RegionSize = 0;
*Attribs = 0;
//
// Instance number start from 1
//
if (Instance == 0){
return EFI_INVALID_PARAMETER;
}
Fdm = (UINT8*)(UINTN) PcdGet64(PcdH2OFlashDeviceMapStart);
if ((Fdm == NULL) || CompareMem(Fdm, mSignature, sizeof(mSignature))){
return EFI_NOT_FOUND;
}
if (!IsFdmHeaderValid ((H2O_FLASH_DEVICE_MAP_HEADER *) Fdm)) {
return EFI_SECURITY_VIOLATION;
}
EntrySize = ((H2O_FLASH_DEVICE_MAP_HEADER*)Fdm)->EntrySize;
EndPtr = Fdm + ((H2O_FLASH_DEVICE_MAP_HEADER*)Fdm)->Size;
for (Matched = 0, Entry = (H2O_FLASH_DEVICE_MAP_ENTRY*)(Fdm + ((H2O_FLASH_DEVICE_MAP_HEADER*)Fdm)->Offset);
(UINT8*)Entry < EndPtr;
Entry = (H2O_FLASH_DEVICE_MAP_ENTRY*)(((UINT8*)Entry) + EntrySize)){
if (!CompareMem(&Entry->RegionType, RegionType, sizeof(EFI_GUID)) &&
((Entry->Attribs & H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_IGNORE) != H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_IGNORE)){
Matched++;
if (Matched == Instance){
break;
}
}
}
if (Matched != Instance){
return EFI_NOT_FOUND;
}
CopyMem (RegionId, Entry->RegionId, FDM_ENTRY_REGION_ID_SIZE);
*RegionOffset = Entry->RegionOffset;
*RegionSize = Entry->RegionSize;
*Attribs = Entry->Attribs;
return EFI_SUCCESS;
}
/**
Get entry recorded in FDM
@param RegionType EFI_GUID that specifies the type of region that N-th entry is.
@param Instance Unsigned integer that specifies entry instance of FDM
@param RegionId Identifier that specifies the identifier of this region..
@param RegionOffset Unsigned integer that specifies the offset of this region relative to the
base of the flash device image.
@param RegionSize Unsigned integer that specifies the region size.
@param Attribs Bitmap that specifies the attributes of the flash device map entry.
@return EFI_SUCCESS find region type success.
@return EFI_INVALID_PARAMETER Incorrect parameter.
@return EFI_SECURITY_VIOLATION Region hash is not correct.
@return EFI_NOT_FOUND Can't find region type in the FDM.
**/
EFI_STATUS
EFIAPI
FdmGetAt (
CONST IN UINT8 Instance,
OUT EFI_GUID *RegionType,
OUT UINT8 *RegionId,
OUT UINT64 *RegionOffset,
OUT UINT64 *RegionSize,
OUT UINT32 *Attribs
){
UINT8 *EndPtr;
UINT8 InstanceNotIgnored;
UINT32 EntrySize;
H2O_FLASH_DEVICE_MAP_ENTRY *Entry;
UINT8 *Fdm;
ZeroMem(RegionType, sizeof(EFI_GUID));
*RegionId = 0;
*RegionOffset = 0;
*RegionSize = 0;
*Attribs = 0;
//
// Instance number start from 1
//
if (Instance == 0){
return EFI_INVALID_PARAMETER;
}
Fdm = (UINT8*)(UINTN) PcdGet64(PcdH2OFlashDeviceMapStart);
if ((Fdm == NULL) || CompareMem(Fdm, mSignature, sizeof(mSignature))){
return EFI_NOT_FOUND;
}
if (!IsFdmHeaderValid ((H2O_FLASH_DEVICE_MAP_HEADER *) Fdm)) {
return EFI_SECURITY_VIOLATION;
}
EntrySize = ((H2O_FLASH_DEVICE_MAP_HEADER*)Fdm)->EntrySize;
EndPtr = Fdm + ((H2O_FLASH_DEVICE_MAP_HEADER*)Fdm)->Size;
for (InstanceNotIgnored = 0, Entry = (H2O_FLASH_DEVICE_MAP_ENTRY*) (Fdm + ((H2O_FLASH_DEVICE_MAP_HEADER*)Fdm)->Offset);
;
Entry = (H2O_FLASH_DEVICE_MAP_ENTRY*)(((UINT8*)Entry) + EntrySize)){
if (Entry >= (H2O_FLASH_DEVICE_MAP_ENTRY*)EndPtr){
return EFI_NOT_FOUND;
}
if ((Entry->Attribs & H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_IGNORE) != H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_IGNORE){
InstanceNotIgnored++;
}
if(InstanceNotIgnored == Instance) {
break;
}
}
CopyMem (RegionType, &Entry->RegionType, sizeof(Entry->RegionType));
CopyMem (RegionId, Entry->RegionId, FDM_ENTRY_REGION_ID_SIZE);
*RegionOffset = Entry->RegionOffset;
*RegionSize = Entry->RegionSize;
*Attribs = Entry->Attribs;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
FdmGetNAtWorker (
IN CONST EFI_GUID *RegionType,
IN UINT8 Instance,
OUT UINT64 *Address,
OUT UINT64 *Size
){
UINT8 Id[FDM_ENTRY_REGION_ID_SIZE];
UINT64 Offset;
UINT64 RegionSize;
UINT32 Attr;
if (EFI_ERROR (FdmGetNAt (RegionType, Instance, Id, &Offset, &RegionSize, &Attr))){
return EFI_NOT_FOUND;
}
*Address = Offset + FdmGetBaseAddr ();
*Size = RegionSize;
return EFI_SUCCESS;
}
/**
Get Address of Region recorded in FDM
@param[in] RegionType GUID that specifies the type of region
@param[in] Instance Unsigned integer that specifies entry instance of Region Type in FDM
@return address of the Region.
**/
UINT64
EFIAPI
FdmGetNAtAddr (
IN CONST EFI_GUID *RegionType,
IN UINT8 Instance
){
UINT64 Address;
UINT64 Size;
if ( EFI_ERROR (FdmGetNAtWorker (RegionType, Instance, &Address, &Size))){
return 0;
}
return Address;
}
/**
Get Size of Region recorded in FDM
@param[in] RegionType GUID that specifies the type of region
@param[in] Instance Unsigned integer that specifies entry instance of Region Type in FDM
@return size of the Region.
**/
UINT64
EFIAPI
FdmGetNAtSize (
IN CONST EFI_GUID *RegionType,
IN UINT8 Instance
){
UINT64 Address;
UINT64 Size;
if ( EFI_ERROR (FdmGetNAtWorker (RegionType, Instance, &Address, &Size))){
return 0;
}
return Size;
}
EFI_STATUS
EFIAPI
FdmGetByIdWorker (
IN CONST EFI_GUID *RegionType,
IN CONST EFI_GUID *Id,
IN UINT8 Instance,
OUT UINT64 *Address,
OUT UINT64 *Size
){
UINT8 MaxRegion;
UINT8 Index;
UINT8 Matched;
EFI_STATUS Status;
UINT8 RegionId[FDM_ENTRY_REGION_ID_SIZE];
UINT64 RegionOffset;
UINT64 RegionSize;
UINT32 Attribs;
Status = FdmGetCount (&MaxRegion);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
Matched = 0;
for (Index = 1; Index < MaxRegion + 1; Index++){
Status = FdmGetNAt (
RegionType,
Index,
RegionId,
&RegionOffset,
&RegionSize,
&Attribs
);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
if (!CompareMem(RegionId, Id, sizeof(EFI_GUID))){
Matched++;
}
if (Matched == Instance) {
*Address = RegionOffset + FdmGetBaseAddr ();
*Size = RegionSize;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Get address of Region recorded in FDM by specific Id and region type.
@param[in] RegionType GUID that specifies the type of region.
@param[in] Id Pointer of value that specifies the Id field must matched.
@param[in] Instance Unsigned integer that specifies instance of Region Type in FDM
@return address of the Region.
**/
UINT64
EFIAPI
FdmGetAddressById (
IN CONST EFI_GUID *RegionType,
IN CONST EFI_GUID *Id,
IN UINT8 Instance
){
EFI_STATUS Status;
UINT64 RegionAddress;
UINT64 RegionSize;
Status = FdmGetByIdWorker (
RegionType,
Id,
Instance,
&RegionAddress,
&RegionSize
);
if (EFI_ERROR(Status)){
return 0;
}
return RegionAddress;
}
/**
Get size of Region recorded in FDM by specific Id and region type.
@param[in] RegionType GUID that specifies the type of region.
@param[in] Id Pointer of value that specifies the Id field must matched.
@param[in] Instance Unsigned integer that specifies instance of Region Type in FDM
@return size of the Region.
**/
UINT64
EFIAPI
FdmGetSizeById (
IN CONST EFI_GUID *RegionType,
IN CONST EFI_GUID *Id,
IN UINT8 Instance
){
EFI_STATUS Status;
UINT64 RegionAddress;
UINT64 RegionSize;
Status = FdmGetByIdWorker (
RegionType,
Id,
Instance,
&RegionAddress,
&RegionSize
);
if (EFI_ERROR(Status)){
return 0;
}
return RegionSize;
}
/**
Get Flash Size
@return Flash Size
**/
UINT64
EFIAPI
FdmGetFlashAreaSize (
VOID
){
UINT64 FlashSize;
UINT8 Index;
UINT8 MaxRegion;
EFI_STATUS Status;
UINT8 RegionId[FDM_ENTRY_REGION_ID_SIZE];
UINT64 RegionOffset;
UINT64 RegionSize;
UINT32 Attribs;
EFI_GUID RegionType;
FlashSize = 0;
Status = FdmGetCount (&MaxRegion);
if (EFI_ERROR (Status)) {
return 0;
}
//
// Cumulate all regions size to get flash size
//
for (Index = 1; Index < MaxRegion + 1; Index++){
Status = FdmGetAt (
Index,
&RegionType,
RegionId,
&RegionOffset,
&RegionSize,
&Attribs
);
if (EFI_ERROR (Status)) {
return 0;
}
FlashSize += RegionSize;
}
return FlashSize;
}
/**
Internal function to verify the FV region by checking the hash value in FDM by region type
,ID and instance number.
Also invoke gH2OBaseCpVerifyFvGuid checkpoint after verifying region. It may enter deadloop
if verify failed.
@param[in] RegionType EFI_GUID that specifies the type of region.
@param[in] Id Pointer of value that specifies the Id field must matched.
@param[in] Instance Unsigned integer that specifies entry instance of FDM
@retval EFI_SUCCESS Region verified successfully.
@retval EFI_NOT_FOUND Can't find region type in the FDM.
@retval EFI_SECURITY_VIOLATION Region verified failed.
**/
STATIC
EFI_STATUS
FdmVerifyRegion (
IN CONST EFI_GUID *RegionType, OPTIONAL
IN CONST EFI_GUID *Id, OPTIONAL
IN UINT8 Instance
)
{
UINT8 EntryFormat;
UINT8 *Hash;
UINT8 InstanceNotIgnored;
UINT32 EntrySize;
H2O_FLASH_DEVICE_MAP_ENTRY *Entries;
H2O_FLASH_DEVICE_MAP_ENTRY *Entry;
H2O_FLASH_DEVICE_MAP_ENTRY *EndPtr;
H2O_FLASH_DEVICE_MAP_HEADER *Fdm;
EFI_STATUS Status;
Fdm = (H2O_FLASH_DEVICE_MAP_HEADER*)(UINTN) PcdGet64(PcdH2OFlashDeviceMapStart);
EntrySize = Fdm->EntrySize;
EntryFormat = Fdm->EntryFormat;
Entries = (H2O_FLASH_DEVICE_MAP_ENTRY *)(((UINT8 *)Fdm) + Fdm->Offset);
EndPtr = (H2O_FLASH_DEVICE_MAP_ENTRY *)(((UINT8 *)Fdm) + Fdm->Size);
InstanceNotIgnored = 0;
Status = EFI_NOT_FOUND;
for (Entry = Entries;
Entry < EndPtr;
Entry = (H2O_FLASH_DEVICE_MAP_ENTRY*)(((UINT8*)Entry) + EntrySize)) {
if ((Entry->Attribs & H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_IGNORE) != H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_IGNORE &&
(RegionType == NULL || CompareGuid (RegionType, &Entry->RegionType)) &&
(Id == NULL || !CompareMem (Id, Entry->RegionId, sizeof(EFI_GUID)))) {
InstanceNotIgnored++;
}
if(InstanceNotIgnored == Instance) {
if ((Entry->Attribs & H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_MUTABLE) == H2O_FLASH_DEVICE_MAP_ENTRY_ATTRIB_MUTABLE) {
Status = EFI_SUCCESS;
break;
}
Hash = (UINT8*)(Entry + 1);
PERF_START (0, "CheckRgn", NULL, 0);
Status = VerifyHash (
EntryFormat,
Hash,
(UINT8*)(UINTN)(Fdm->FdBaseAddr + Entry->RegionOffset),
(UINTN)Entry->RegionSize
);
PERF_END (0, "CheckRgn", NULL, 0);
if (EFI_ERROR (Status)) {
Status = EFI_SECURITY_VIOLATION;
}
break;
}
}
if (FeaturePcdGet (PcdH2OBaseCpVerifyFvSupported)) {
H2O_BASE_CP_VERIFY_FV_DATA VerifyFvData;
VerifyFvData.Size = sizeof (H2O_BASE_CP_VERIFY_FV_DATA);
VerifyFvData.Status = H2O_CP_TASK_NORMAL;
VerifyFvData.FvBase = Fdm->FdBaseAddr + Entry->RegionOffset;
VerifyFvData.FvLength = Entry->RegionSize;
VerifyFvData.Trusted = !EFI_ERROR (Status) ? TRUE : FALSE;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBaseCpVerifyFvGuid));
H2OCpTrigger (&gH2OBaseCpVerifyFvGuid, &VerifyFvData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", VerifyFvData.Status));
if (VerifyFvData.Status == H2O_BDS_TASK_SKIP) {
return Status;
} else if (VerifyFvData.Status == H2O_BDS_TASK_UPDATE) {
Status = VerifyFvData.Trusted ? EFI_SUCCESS : EFI_SECURITY_VIOLATION;
}
}
if (Status == EFI_SECURITY_VIOLATION) {
POST_CODE (0xDE);
DEBUG((DEBUG_ERROR, "ERROR!!! Firmware Volume Base Address: 0x%lx, Size: 0x%lx is corrupted.\n", FdmGetNAtAddr (RegionType, Instance), FdmGetNAtSize (RegionType, Instance)));
ASSERT (FALSE);
CpuDeadLoop ();
}
return Status;
}
/**
Verify the FV region by checking the hash value in FDM by instance number.
NOTE: This function will hang if the region has a security issue with the deadloop.
@param[in] Instance Unsigned integer that specifies entry instance of FDM
@retval EFI_SUCCESS Region verified successfully.
@retval EFI_NOT_FOUND Can't find region type in the FDM.
@retval EFI_SECURITY_VIOLATION Region verified failed.
**/
EFI_STATUS
EFIAPI
FdmVerifyAt (
IN CONST UINT8 Instance
)
{
return FdmVerifyRegion (NULL, NULL, Instance);
}
/**
Verify the FV region by checking the hash value in FDM by region type and instance number.
NOTE: This function will hang if the region has a security issue with the deadloop.
@param[in] RegionType EFI_GUID that specifies the type of region.
@param[in] Instance Unsigned integer that specifies entry instance of FDM
@retval EFI_SUCCESS Region verified successfully.
@retval EFI_NOT_FOUND Can't find region type in the FDM.
@retval EFI_SECURITY_VIOLATION Region verified failed.
**/
EFI_STATUS
EFIAPI
FdmVerifyNAt (
IN CONST EFI_GUID *RegionType,
IN CONST UINT8 Instance
)
{
return FdmVerifyRegion (RegionType, NULL, Instance);
}
/**
Verify the FV region by checking the hash value in FDM by region type , ID and instance number.
NOTE: This function will hang if the region has a security issue with the deadloop.
@param[in] RegionType EFI_GUID that specifies the type of region.
@param[in] Id Pointer of value that specifies the Id field must matched.
@param[in] Instance Unsigned integer that specifies entry instance of FDM
@retval EFI_SUCCESS Region verified successfully.
@retval EFI_NOT_FOUND Can't find region type in the FDM.
@retval EFI_SECURITY_VIOLATION Region verified failed.
**/
EFI_STATUS
EFIAPI
FdmVerifyById (
IN CONST EFI_GUID *RegionType,
IN CONST EFI_GUID *Id,
IN UINT8 Instance
)
{
return FdmVerifyRegion (RegionType, Id, Instance);
}
/**
Get the FDM entry by using UINT64 board ID and region type.
@param[in] BoardId Board identifier.
@param[in] RegionType The EFI_GUID that specifies the type of region.
@param[out] DeviceMapEntries Record the actual found entries.
@param[in, out] DeviceEntryCount Unsigned integer that specifies the count of specific Region in FDM.
@retval EFI_SUCCESS Function completed successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory fail.
@retval EFI_UNSUPPORTED FDM version is not 3.
@retval EFI_NOT_FOUND FDM header or FDM entry is not found.
**/
STATIC
EFI_STATUS
GetFdmEntryData (
IN H2O_BOARD_ID BoardId,
IN CONST EFI_GUID *RegionType,
OUT H2O_FLASH_DEVICE_MAP_ENTRY **DeviceMapEntries,
IN OUT UINT8 *DeviceEntryCount
)
{
H2O_FLASH_DEVICE_MAP_HEADER *FdmHeader;
H2O_FLASH_DEVICE_MAP_EXTS *FdmExt;
H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP *Map;
H2O_FLASH_DEVICE_MAP_ENTRY *FirstEntry;
H2O_FLASH_DEVICE_MAP_ENTRY *ThisEntry;
H2O_FLASH_DEVICE_MAP_ENTRY *NewEntryList;
UINT32 ThisEntryIndex;
UINT32 Index;
UINT32 IdIndex;
UINT64 *BoardIds;
UINT32 BoardIdCount;
UINT8 Count;
Count = 0;
BoardIdCount = 0;
NewEntryList = NULL;
FdmHeader = (H2O_FLASH_DEVICE_MAP_HEADER*)(UINTN) PcdGet64(PcdH2OFlashDeviceMapStart);
if ((FdmHeader == NULL) || CompareMem(FdmHeader, mSignature, sizeof(mSignature))){
return EFI_NOT_FOUND;
}
//
// In Revision 3, reserved byte in Fdm header will be ExtensionCount.See BTR 3.17.1.
// The second ext block indicates the location of the first region-to-board-id-map.
//
if (FdmHeader->Revision < 3 || FdmHeader->ExtensionCount <= H2O_FLASH_DEVICE_MAP_EXT_BLOCK_ID_MAP) {
return EFI_UNSUPPORTED;
}
FdmExt = (H2O_FLASH_DEVICE_MAP_EXTS *)((UINT8 *)FdmHeader + sizeof(H2O_FLASH_DEVICE_MAP_HEADER));
//
// Check the FDM extension is bigger than or equal FDM offset.
// If yes, return EFI_UNSUPPORTED.
//
if ((UINT32)((UINT8 *)FdmExt - (UINT8 *)FdmHeader) >= (FdmHeader->Offset)) {
return EFI_UNSUPPORTED;
}
if (*DeviceEntryCount > 0) {
//
// If "Count" is bigger than zero, it means unless one FDM entry is found.
// Then allocate the pool for record the FDM entry.
//
NewEntryList = AllocatePool(sizeof(H2O_FLASH_DEVICE_MAP_ENTRY) * (*DeviceEntryCount));
if (NewEntryList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
}
//
// Jump to second extension block.
//
FdmExt = &FdmExt[H2O_FLASH_DEVICE_MAP_EXT_BLOCK_ID_MAP];
Map = (H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP *)((UINT8 *)FdmHeader + FdmExt->ExtOffset);
FirstEntry = (H2O_FLASH_DEVICE_MAP_ENTRY *)((UINT8 *)FdmHeader + FdmHeader->Offset);
for (Index = 0; Index < FdmExt->ExtCount; Index++) {
// typedef struct _H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP {
// UINT32 RegionIndex; // Index of the region in the Flash Device Map.
// UINT32 BoardIdCount; // Number of board identifiers in BoardIds.
// //H2O_BOARD_ID BoardIds[]; // Board identifiers that are associated with the specified region index.
// } H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP
BoardIds = (UINT64 *)((UINT8 *)Map + sizeof(H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP));
BoardIdCount = Map->BoardIdCount;
for (IdIndex = 0; IdIndex < BoardIdCount; IdIndex++) {
//
// Check the BoardId.
//
if (BoardIds[IdIndex] == BoardId) {
ThisEntryIndex = Map->RegionIndex;
ThisEntry = (H2O_FLASH_DEVICE_MAP_ENTRY *)((UINT8 *)FirstEntry + FdmHeader->EntrySize * ThisEntryIndex);
//
// Check the region type.
//
if (CompareGuid(&ThisEntry->RegionType, RegionType)) {
//
// Record FDM entries.
//
if (*DeviceEntryCount > 0) {
NewEntryList[Count] = *ThisEntry;
}
Count++;
break;
}
}
}
// typedef struct _H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP {
// UINT32 RegionIndex; // Index of the region in the Flash Device Map.
// UINT32 BoardIdCount; // Number of board identifiers in BoardIds.
// //H2O_BOARD_ID BoardIds[]; // Board identifiers that are associated with the specified region index.
// } H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP
//
// Jump one "H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP" structure.
// //UINT32 RegionIndex; // Index of the region in the Flash Device Map.
// //UINT32 BoardIdCount; // Number of board identifiers in BoardIds.
//
Map = Map + 1;
//
// Add "H2O_BOARD_ID BoardIds[]" to next MAP header.
//
Map = (H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP *)((UINT64 *)Map + BoardIdCount);
}
if (Count == 0) {
return EFI_NOT_FOUND;
}
//
// Provide calculated result and data to caller.
//
*DeviceEntryCount = Count;
*DeviceMapEntries = NewEntryList;
return EFI_SUCCESS;
}
/**
Find the FDM entry by using UINT64 board ID and region type.
@param[in] BoardId Board identifier.
@param[in] RegionType The EFI_GUID that specifies the type of region.
@param[out] DeviceMapEntries Record the actual found entries.
@param[out] DeviceEntryCount Unsigned integer that specifies the count of specific Region in FDM.
@retval EFI_SUCCESS Function completed successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory fail.
@retval EFI_UNSUPPORTED FDM version is not 3.
@retval EFI_NOT_FOUND FDM header or FDM entry is not found.
**/
EFI_STATUS
EFIAPI
FindRegionsByBoardId (
IN H2O_BOARD_ID BoardId,
IN CONST EFI_GUID *RegionType,
OUT H2O_FLASH_DEVICE_MAP_ENTRY **DeviceMapEntries,
OUT UINT8 *DeviceEntryCount
)
{
EFI_STATUS Status;
UINT8 Count;
H2O_FLASH_DEVICE_MAP_ENTRY *Entries;
UINT8 Index;
Entries = NULL;
Count = 0;
Index = 0;
Status = EFI_NOT_FOUND;
if (DeviceMapEntries == NULL || DeviceEntryCount == NULL){
return EFI_INVALID_PARAMETER;
}
//
// First Loop
// When the correct entries are found, then calculate and allocate buffer.
//
// Second Loop
// Get and put the entries into allocated buffer.
// When the "Count" is bigger than zero from Part I result.
// GetFdmEntryData() will be run second time to get FDM entries.
//
for (Index = 0; Index < 2; Index++) {
Status = GetFdmEntryData (BoardId, RegionType, &Entries, &Count);
if (EFI_ERROR(Status)) {
return Status;
}
}
*DeviceEntryCount = Count;
*DeviceMapEntries = Entries;
return Status;
}