mirror of https://github.com/acidanthera/audk.git
444 lines
12 KiB
C
444 lines
12 KiB
C
/** @file
|
|
Var Check Hii generation from FV.
|
|
|
|
Copyright (c) 2015 - 2016, 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 ((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 (
|
|
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));
|
|
}
|
|
);
|
|
|
|
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 ();
|
|
}
|
|
}
|