/** @file Var Check Hii generation from FV. Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
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; 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); while (TRUE) { 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 (); } }