blob: 562f5a02f6021cc7c6d4498861bcd62fb3ac139f [file] [log] [blame]
/** @file
Var Check Hii generation from FV.
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "VarCheckHiiGen.h"
// {d0bc7cb4-6a47-495f-aa11-710746da06a2}
#define EFI_VFR_ATTRACT_GUID \
{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }
EFI_GUID gVfrArrayAttractGuid = EFI_VFR_ATTRACT_GUID;
#define ALL_FF_GUID \
{ 0xFFFFFFFF, 0xFFFF, 0xFFFF, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }
EFI_GUID mAllFfGuid = ALL_FF_GUID;
#define VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE SIGNATURE_32 ('V', 'D', 'R', 'I')
typedef struct {
UINTN Signature;
LIST_ENTRY Link;
EFI_GUID *DriverGuid;
} VAR_CHECK_VFR_DRIVER_INFO;
LIST_ENTRY mVfrDriverList = INITIALIZE_LIST_HEAD_VARIABLE (mVfrDriverList);
#define VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK(a) CR (a, VAR_CHECK_VFR_DRIVER_INFO, Link, VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE)
#define MAX_MATCH_GUID_NUM 100
/**
Get the address by Guid.
Parse the FFS and find the GUID address.
There may be multiple Guids matching the searched Guid.
@param Ffs Pointer to the FFS.
@param Guid Guid to find.
@param Length The length of FFS.
@param Offset Pointer to pointer to the offset.
@param NumOfMatchingGuid The number of matching Guid.
@retval EFI_SUCCESS One or multiple Guids matching the searched Guid.
@retval EFI_NOT_FOUND No Guid matching the searched Guid.
**/
EFI_STATUS
GetAddressByGuid (
IN VOID *Ffs,
IN EFI_GUID *Guid,
IN UINTN Length,
OUT UINTN **Offset,
OUT UINT8 *NumOfMatchingGuid
)
{
UINTN LoopControl;
BOOLEAN Found;
if ((Ffs == NULL) || (Guid == NULL) || (Length == 0)) {
return EFI_NOT_FOUND;
}
if (NumOfMatchingGuid != NULL) {
*NumOfMatchingGuid = 0;
}
Found = FALSE;
for (LoopControl = 0; LoopControl < Length; LoopControl++) {
if (CompareGuid (Guid, (EFI_GUID *)((UINT8 *)Ffs + LoopControl))) {
Found = TRUE;
//
// If NumOfMatchGuid or Offset are NULL, means user only want
// to check whether current FFS includes this Guid or not.
//
if ((NumOfMatchingGuid != NULL) && (Offset != NULL)) {
if (*NumOfMatchingGuid == 0) {
*Offset = InternalVarCheckAllocateZeroPool (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
ASSERT (*Offset != NULL);
}
*(*Offset + *NumOfMatchingGuid) = LoopControl + sizeof (EFI_GUID);
(*NumOfMatchingGuid)++;
} else {
break;
}
}
}
return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
}
/**
Search the VfrBin Base address.
According to the known GUID gVfrArrayAttractGuid to get the base address from FFS.
@param Ffs Pointer to the FFS.
@param EfiAddr Pointer to the EFI in FFS
@param Length The length of FFS.
@param Offset Pointer to pointer to the Addr (Offset).
@param NumOfMatchingOffset The number of Addr (Offset).
@retval EFI_SUCCESS Get the address successfully.
@retval EFI_NOT_FOUND No VfrBin found.
**/
EFI_STATUS
SearchVfrBinInFfs (
IN VOID *Ffs,
IN VOID *EfiAddr,
IN UINTN Length,
OUT UINTN **Offset,
OUT UINT8 *NumOfMatchingOffset
)
{
UINTN Index;
EFI_STATUS Status;
UINTN VirOffValue;
if ((Ffs == NULL) || (Offset == NULL)) {
return EFI_NOT_FOUND;
}
Status = GetAddressByGuid (
Ffs,
&gVfrArrayAttractGuid,
Length,
Offset,
NumOfMatchingOffset
);
if (Status != EFI_SUCCESS) {
return Status;
}
for (Index = 0; Index < *NumOfMatchingOffset; Index++) {
//
// Got the virOffset after the GUID
//
VirOffValue = *(UINTN *)((UINTN)Ffs + *(*Offset + Index));
//
// Transfer the offset to the VA address. One modules may own multiple VfrBin address.
//
*(*Offset + Index) = (UINTN)EfiAddr + VirOffValue;
}
return Status;
}
/**
Parse FFS.
@param[in] Fv2 Pointer to Fv2 protocol.
@param[in] DriverGuid Pointer to driver GUID.
@return Found the driver in the FV or not.
**/
BOOLEAN
ParseFfs (
IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2,
IN EFI_GUID *DriverGuid
)
{
EFI_STATUS Status;
EFI_FV_FILETYPE FoundType;
EFI_FV_FILE_ATTRIBUTES FileAttributes;
UINT32 AuthenticationStatus;
UINTN Size;
VOID *Buffer;
UINTN SectionSize;
VOID *SectionBuffer;
UINTN VfrBinIndex;
UINT8 NumberofMatchingVfrBin;
UINTN *VfrBinBaseAddress;
Status = Fv2->ReadFile (
Fv2,
DriverGuid,
NULL,
&Size,
&FoundType,
&FileAttributes,
&AuthenticationStatus
);
if (EFI_ERROR (Status)) {
return FALSE;
}
Buffer = NULL;
Status = Fv2->ReadSection (
Fv2,
DriverGuid,
EFI_SECTION_RAW,
0, // Instance
&Buffer,
&Size,
&AuthenticationStatus
);
if (!EFI_ERROR (Status)) {
Status = SearchVfrBinInFfs (Buffer, 0, Size, &VfrBinBaseAddress, &NumberofMatchingVfrBin);
if (!EFI_ERROR (Status)) {
SectionBuffer = NULL;
Status = Fv2->ReadSection (
Fv2,
DriverGuid,
EFI_SECTION_PE32,
0, // Instance
&SectionBuffer,
&SectionSize,
&AuthenticationStatus
);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "FfsNameGuid - %g\n", DriverGuid));
DEBUG ((DEBUG_INFO, "NumberofMatchingVfrBin - 0x%02x\n", NumberofMatchingVfrBin));
for (VfrBinIndex = 0; VfrBinIndex < NumberofMatchingVfrBin; VfrBinIndex++) {
#ifdef DUMP_HII_DATA
DEBUG_CODE (
DumpHiiPackage ((UINT8 *)(UINTN)SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32));
);
#endif
VarCheckParseHiiPackage ((UINT8 *)(UINTN)SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32), TRUE);
}
FreePool (SectionBuffer);
}
InternalVarCheckFreePool (VfrBinBaseAddress);
}
FreePool (Buffer);
}
return TRUE;
}
/**
Parse FVs.
@param[in] ScanAll Scan all modules in all FVs or not.
**/
VOID
ParseFv (
IN BOOLEAN ScanAll
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2;
VOID *Key;
EFI_FV_FILETYPE FileType;
EFI_GUID NameGuid;
EFI_FV_FILE_ATTRIBUTES FileAttributes;
UINTN Size;
UINTN FfsIndex;
VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
LIST_ENTRY *VfrDriverLink;
HandleBuffer = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolume2ProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return;
}
//
// Search all FVs
//
for (Index = 0; Index < HandleCount; Index++) {
DEBUG ((DEBUG_INFO, "FvIndex - %x\n", Index));
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolume2ProtocolGuid,
(VOID **)&Fv2
);
ASSERT_EFI_ERROR (Status);
DEBUG_CODE_BEGIN ();
EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *Fvb2;
EFI_PHYSICAL_ADDRESS FvAddress;
UINT64 FvSize;
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolumeBlock2ProtocolGuid,
(VOID **)&Fvb2
);
ASSERT_EFI_ERROR (Status);
Status = Fvb2->GetPhysicalAddress (Fvb2, &FvAddress);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "FvAddress - 0x%08x\n", FvAddress));
FvSize = ((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvAddress)->FvLength;
DEBUG ((DEBUG_INFO, "FvSize - 0x%08x\n", FvSize));
}
DEBUG_CODE_END ();
if (ScanAll) {
//
// Need to parse all modules in all FVs.
//
Key = InternalVarCheckAllocateZeroPool (Fv2->KeySize);
ASSERT (Key != NULL);
for (FfsIndex = 0; ; FfsIndex++) {
FileType = EFI_FV_FILETYPE_ALL;
Status = Fv2->GetNextFile (
Fv2,
Key,
&FileType,
&NameGuid,
&FileAttributes,
&Size
);
if (EFI_ERROR (Status)) {
break;
}
ParseFfs (Fv2, &NameGuid);
}
InternalVarCheckFreePool (Key);
} else {
//
// Only parse drivers in the VFR drivers list.
//
VfrDriverLink = mVfrDriverList.ForwardLink;
while (VfrDriverLink != &mVfrDriverList) {
VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
VfrDriverLink = VfrDriverLink->ForwardLink;
if (ParseFfs (Fv2, VfrDriverInfo->DriverGuid)) {
//
// Found the driver in the FV.
//
RemoveEntryList (&VfrDriverInfo->Link);
InternalVarCheckFreePool (VfrDriverInfo);
}
}
}
}
FreePool (HandleBuffer);
}
/**
Create Vfr Driver List.
@param[in] DriverGuidArray Driver Guid Array
**/
VOID
CreateVfrDriverList (
IN EFI_GUID *DriverGuidArray
)
{
UINTN Index;
VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
for (Index = 0; !IsZeroGuid (&DriverGuidArray[Index]); Index++) {
DEBUG ((DEBUG_INFO, "CreateVfrDriverList: %g\n", &DriverGuidArray[Index]));
VfrDriverInfo = InternalVarCheckAllocateZeroPool (sizeof (*VfrDriverInfo));
ASSERT (VfrDriverInfo != NULL);
VfrDriverInfo->Signature = VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE;
VfrDriverInfo->DriverGuid = &DriverGuidArray[Index];
InsertTailList (&mVfrDriverList, &VfrDriverInfo->Link);
}
}
/**
Destroy Vfr Driver List.
**/
VOID
DestroyVfrDriverList (
VOID
)
{
VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
LIST_ENTRY *VfrDriverLink;
while (mVfrDriverList.ForwardLink != &mVfrDriverList) {
VfrDriverLink = mVfrDriverList.ForwardLink;
VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
RemoveEntryList (&VfrDriverInfo->Link);
InternalVarCheckFreePool (VfrDriverInfo);
}
}
/**
Generate from FV.
**/
VOID
VarCheckHiiGenFromFv (
VOID
)
{
EFI_GUID *DriverGuidArray;
BOOLEAN ScanAll;
DEBUG ((DEBUG_INFO, "VarCheckHiiGenDxeFromFv\n"));
//
// Get vfr driver guid array from PCD.
//
DriverGuidArray = (EFI_GUID *)PcdGetPtr (PcdVarCheckVfrDriverGuidArray);
if (IsZeroGuid (&DriverGuidArray[0])) {
//
// No VFR driver will be parsed from FVs.
//
return;
}
if (CompareGuid (&DriverGuidArray[0], &mAllFfGuid)) {
ScanAll = TRUE;
} else {
ScanAll = FALSE;
CreateVfrDriverList (DriverGuidArray);
}
ParseFv (ScanAll);
if (!ScanAll) {
DestroyVfrDriverList ();
}
}