/** @file | |
Var Check Hii generation from FV. | |
Copyright (c) 2015, 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 | |
which 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. | |
**/ | |
#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 ((EFI_D_INFO, "FfsNameGuid - %g\n", DriverGuid)); | |
DEBUG ((EFI_D_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 ((EFI_D_INFO, "FvIndex - %x\n", Index)); | |
Status = gBS->HandleProtocol ( | |
HandleBuffer[Index], | |
&gEfiFirmwareVolume2ProtocolGuid, | |
(VOID **) &Fv2 | |
); | |
ASSERT_EFI_ERROR (Status); | |
DEBUG_CODE ( | |
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 ((EFI_D_INFO, "FvAddress - 0x%08x\n", FvAddress)); | |
FvSize = ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvAddress)->FvLength; | |
DEBUG ((EFI_D_INFO, "FvSize - 0x%08x\n", FvSize)); | |
} | |
); | |
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; !CompareGuid (&DriverGuidArray[Index], &gZeroGuid); Index++) { | |
DEBUG ((EFI_D_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 ((EFI_D_INFO, "VarCheckHiiGenDxeFromFv\n")); | |
// | |
// Get vfr driver guid array from PCD. | |
// | |
DriverGuidArray = (EFI_GUID *) PcdGetPtr (PcdVarCheckVfrDriverGuidArray); | |
if (CompareGuid (&DriverGuidArray[0], &gZeroGuid)) { | |
// | |
// 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 (); | |
} | |
} |