| /** @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 (); | |
| } | |
| } |