]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
MdeModulePkg: Add VarCheckHiiLib NULL class library
[mirror_edk2.git] / MdeModulePkg / Library / VarCheckHiiLib / VarCheckHiiGenFromFv.c
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
new file mode 100644 (file)
index 0000000..21fc80e
--- /dev/null
@@ -0,0 +1,443 @@
+/** @file\r
+  Var Check Hii generation from FV.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "VarCheckHiiGen.h"\r
+\r
+// {d0bc7cb4-6a47-495f-aa11-710746da06a2}\r
+#define EFI_VFR_ATTRACT_GUID \\r
+{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }\r
+\r
+EFI_GUID  gVfrArrayAttractGuid  = EFI_VFR_ATTRACT_GUID;\r
+\r
+#define ALL_FF_GUID \\r
+{ 0xFFFFFFFF, 0xFFFF, 0xFFFF, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }\r
+\r
+EFI_GUID mAllFfGuid             = ALL_FF_GUID;\r
+\r
+#define VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE     SIGNATURE_32 ('V', 'D', 'R', 'I')\r
+\r
+typedef struct {\r
+  UINTN             Signature;\r
+  LIST_ENTRY        Link;\r
+  EFI_GUID          *DriverGuid;\r
+} VAR_CHECK_VFR_DRIVER_INFO;\r
+\r
+LIST_ENTRY                      mVfrDriverList = INITIALIZE_LIST_HEAD_VARIABLE (mVfrDriverList);\r
+\r
+#define VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK(a)  CR (a, VAR_CHECK_VFR_DRIVER_INFO, Link, VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE)\r
+\r
+#define MAX_MATCH_GUID_NUM      100\r
+\r
+/**\r
+  Get the address by Guid.\r
+\r
+  Parse the FFS and find the GUID address.\r
+  There may be multiple Guids matching the searched Guid.\r
+\r
+  @param Ffs                Pointer to the FFS.\r
+  @param Guid               Guid to find.\r
+  @param Length             The length of FFS.\r
+  @param Offset             Pointer to pointer to the offset.\r
+  @param NumOfMatchingGuid  The number of matching Guid.\r
+\r
+  @retval EFI_SUCCESS       One or multiple Guids matching the searched Guid.\r
+  @retval EFI_NOT_FOUND     No Guid matching the searched Guid.\r
+\r
+**/\r
+EFI_STATUS\r
+GetAddressByGuid (\r
+  IN  VOID          *Ffs,\r
+  IN  EFI_GUID      *Guid,\r
+  IN  UINTN         Length,\r
+  OUT UINTN         **Offset,\r
+  OUT UINT8         *NumOfMatchingGuid\r
+  )\r
+{\r
+  UINTN     LoopControl;\r
+  BOOLEAN   Found;\r
+\r
+  if((Ffs == NULL) || (Guid == NULL) || (Length == 0)){\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (NumOfMatchingGuid != NULL) {\r
+    *NumOfMatchingGuid = 0;\r
+  }\r
+\r
+  Found = FALSE;\r
+  for (LoopControl = 0; LoopControl < Length; LoopControl++) {\r
+    if (CompareGuid (Guid, (EFI_GUID *) ((UINT8 *) Ffs + LoopControl))) {\r
+      Found = TRUE;\r
+      //\r
+      // If NumOfMatchGuid or Offset are NULL, means user only want\r
+      // to check whether current FFS includes this Guid or not.\r
+      //\r
+      if ((NumOfMatchingGuid != NULL) && (Offset != NULL)) {\r
+        if (*NumOfMatchingGuid == 0) {\r
+          *Offset = InternalVarCheckAllocateZeroPool (sizeof (UINTN) * MAX_MATCH_GUID_NUM);\r
+          ASSERT (*Offset != NULL);\r
+        }\r
+        *(*Offset + *NumOfMatchingGuid) = LoopControl + sizeof (EFI_GUID);\r
+        (*NumOfMatchingGuid)++;\r
+      } else {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+  Search the VfrBin Base address.\r
+\r
+  According to the known GUID gVfrArrayAttractGuid to get the base address from FFS.\r
+\r
+  @param Ffs                    Pointer to the FFS.\r
+  @param EfiAddr                Pointer to the EFI in FFS\r
+  @param Length                 The length of FFS.\r
+  @param Offset                 Pointer to pointer to the Addr (Offset).\r
+  @param NumOfMatchingOffset    The number of Addr (Offset).\r
+\r
+  @retval EFI_SUCCESS           Get the address successfully.\r
+  @retval EFI_NOT_FOUND         No VfrBin found.\r
+\r
+**/\r
+EFI_STATUS\r
+SearchVfrBinInFfs (\r
+   IN  VOID      *Ffs,\r
+   IN  VOID      *EfiAddr,\r
+   IN  UINTN     Length,\r
+   OUT UINTN     **Offset,\r
+   OUT UINT8     *NumOfMatchingOffset\r
+  )\r
+{\r
+  UINTN        Index;\r
+  EFI_STATUS   Status;\r
+  UINTN        VirOffValue;\r
+\r
+  if ((Ffs == NULL) || (Offset == NULL)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  Status = GetAddressByGuid (\r
+             Ffs,\r
+             &gVfrArrayAttractGuid,\r
+             Length,\r
+             Offset,\r
+             NumOfMatchingOffset\r
+             );\r
+  if (Status != EFI_SUCCESS) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < *NumOfMatchingOffset; Index++) {\r
+    //\r
+    // Got the virOffset after the GUID\r
+    //\r
+    VirOffValue = *(UINTN *) ((UINTN) Ffs + *(*Offset + Index));\r
+    //\r
+    // Transfer the offset to the VA address. One modules may own multiple VfrBin address.\r
+    //\r
+    *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Parse FFS.\r
+\r
+  @param[in] Fv2            Pointer to Fv2 protocol.\r
+  @param[in] DriverGuid     Pointer to driver GUID.\r
+\r
+  @return Found the driver in the FV or not.\r
+\r
+**/\r
+BOOLEAN\r
+ParseFfs (\r
+  IN EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv2,\r
+  IN EFI_GUID                       *DriverGuid\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_FV_FILETYPE               FoundType;\r
+  EFI_FV_FILE_ATTRIBUTES        FileAttributes;\r
+  UINT32                        AuthenticationStatus;\r
+  UINTN                         Size;\r
+  VOID                          *Buffer;\r
+  UINTN                         SectionSize;\r
+  VOID                          *SectionBuffer;\r
+  UINTN                         VfrBinIndex;\r
+  UINT8                         NumberofMatchingVfrBin;\r
+  UINTN                         *VfrBinBaseAddress;\r
+\r
+  Status = Fv2->ReadFile (\r
+                  Fv2,\r
+                  DriverGuid,\r
+                  NULL,\r
+                  &Size,\r
+                  &FoundType,\r
+                  &FileAttributes,\r
+                  &AuthenticationStatus\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Buffer = NULL;\r
+  Status = Fv2->ReadSection (\r
+                  Fv2,\r
+                  DriverGuid,\r
+                  EFI_SECTION_RAW,\r
+                  0, // Instance\r
+                  &Buffer,\r
+                  &Size,\r
+                  &AuthenticationStatus\r
+                  );\r
+   if (!EFI_ERROR (Status)) {\r
+     Status = SearchVfrBinInFfs (Buffer, 0, Size, &VfrBinBaseAddress, &NumberofMatchingVfrBin);\r
+     if (!EFI_ERROR (Status)) {\r
+        SectionBuffer = NULL;\r
+        Status = Fv2->ReadSection (\r
+                        Fv2,\r
+                        DriverGuid,\r
+                        EFI_SECTION_PE32,\r
+                        0, // Instance\r
+                        &SectionBuffer,\r
+                        &SectionSize,\r
+                        &AuthenticationStatus\r
+                        );\r
+        if (!EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_INFO, "FfsNameGuid - %g\n", DriverGuid));\r
+          DEBUG ((EFI_D_INFO, "NumberofMatchingVfrBin - 0x%02x\n", NumberofMatchingVfrBin));\r
+\r
+          for (VfrBinIndex = 0; VfrBinIndex < NumberofMatchingVfrBin; VfrBinIndex++) {\r
+#ifdef DUMP_HII_DATA\r
+            DEBUG_CODE (\r
+              DumpHiiPackage ((UINT8 *) (UINTN) SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32));\r
+              );\r
+#endif\r
+            VarCheckParseHiiPackage ((UINT8 *) (UINTN) SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32), TRUE);\r
+          }\r
+\r
+          FreePool (SectionBuffer);\r
+        }\r
+\r
+        InternalVarCheckFreePool (VfrBinBaseAddress);\r
+      }\r
+\r
+      FreePool (Buffer);\r
+    }\r
+\r
+   return TRUE;\r
+}\r
+\r
+/**\r
+  Parse FVs.\r
+\r
+  @param[in] ScanAll    Scan all modules in all FVs or not.\r
+\r
+**/\r
+VOID\r
+ParseFv (\r
+  IN BOOLEAN    ScanAll\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_HANDLE                    *HandleBuffer;\r
+  UINTN                         HandleCount;\r
+  UINTN                         Index;\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2;\r
+  VOID                          *Key;\r
+  EFI_FV_FILETYPE               FileType;\r
+  EFI_GUID                      NameGuid;\r
+  EFI_FV_FILE_ATTRIBUTES        FileAttributes;\r
+  UINTN                         Size;\r
+  UINTN                         FfsIndex;\r
+  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;\r
+  LIST_ENTRY                    *VfrDriverLink;\r
+\r
+  HandleBuffer = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareVolume2ProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Search all FVs\r
+  //\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    DEBUG ((EFI_D_INFO, "FvIndex - %x\n", Index));\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareVolume2ProtocolGuid,\r
+                    (VOID **) &Fv2\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    DEBUG_CODE (\r
+      EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL   *Fvb2;\r
+      EFI_PHYSICAL_ADDRESS                  FvAddress;\r
+      UINT64                                FvSize;\r
+\r
+      Status = gBS->HandleProtocol (\r
+                      HandleBuffer[Index],\r
+                      &gEfiFirmwareVolumeBlock2ProtocolGuid,\r
+                      (VOID **) &Fvb2\r
+                      );\r
+      ASSERT_EFI_ERROR (Status);\r
+      Status = Fvb2->GetPhysicalAddress (Fvb2, &FvAddress);\r
+      if (!EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_INFO, "FvAddress - 0x%08x\n", FvAddress));\r
+        FvSize = ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvAddress)->FvLength;\r
+        DEBUG ((EFI_D_INFO, "FvSize    - 0x%08x\n", FvSize));\r
+      }\r
+    );\r
+\r
+    if (ScanAll) {\r
+      //\r
+      // Need to parse all modules in all FVs.\r
+      //\r
+      Key = InternalVarCheckAllocateZeroPool (Fv2->KeySize);\r
+      ASSERT (Key != NULL);\r
+\r
+      for (FfsIndex = 0; ; FfsIndex++) {\r
+        FileType = EFI_FV_FILETYPE_ALL;\r
+        Status = Fv2->GetNextFile (\r
+                        Fv2,\r
+                        Key,\r
+                        &FileType,\r
+                        &NameGuid,\r
+                        &FileAttributes,\r
+                        &Size\r
+                      );\r
+        if (EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
+\r
+        ParseFfs (Fv2, &NameGuid);\r
+      }\r
+\r
+      InternalVarCheckFreePool (Key);\r
+    } else {\r
+      //\r
+      // Only parse drivers in the VFR drivers list.\r
+      //\r
+      VfrDriverLink = mVfrDriverList.ForwardLink;\r
+      while (VfrDriverLink != &mVfrDriverList) {\r
+        VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);\r
+        VfrDriverLink = VfrDriverLink->ForwardLink;\r
+        if (ParseFfs (Fv2, VfrDriverInfo->DriverGuid)) {\r
+          //\r
+          // Found the driver in the FV.\r
+          //\r
+          RemoveEntryList (&VfrDriverInfo->Link);\r
+          InternalVarCheckFreePool (VfrDriverInfo);\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  FreePool (HandleBuffer);\r
+}\r
+\r
+/**\r
+  Create Vfr Driver List.\r
+\r
+  @param[in] DriverGuidArray    Driver Guid Array\r
+\r
+**/\r
+VOID\r
+CreateVfrDriverList (\r
+  IN EFI_GUID   *DriverGuidArray\r
+  )\r
+{\r
+  UINTN                         Index;\r
+  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;\r
+\r
+  for (Index = 0; !CompareGuid (&DriverGuidArray[Index], &gZeroGuid); Index++) {\r
+     DEBUG ((EFI_D_INFO, "CreateVfrDriverList: %g\n", &DriverGuidArray[Index]));\r
+     VfrDriverInfo = InternalVarCheckAllocateZeroPool (sizeof (*VfrDriverInfo));\r
+     ASSERT (VfrDriverInfo != NULL);\r
+     VfrDriverInfo->Signature = VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE;\r
+     VfrDriverInfo->DriverGuid = &DriverGuidArray[Index];\r
+     InsertTailList (&mVfrDriverList, &VfrDriverInfo->Link);\r
+  }\r
+}\r
+\r
+/**\r
+  Destroy Vfr Driver List.\r
+\r
+**/\r
+VOID\r
+DestroyVfrDriverList (\r
+  VOID\r
+  )\r
+{\r
+  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;\r
+  LIST_ENTRY                    *VfrDriverLink;\r
+\r
+  while (mVfrDriverList.ForwardLink != &mVfrDriverList) {\r
+    VfrDriverLink = mVfrDriverList.ForwardLink;\r
+    VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);\r
+    RemoveEntryList (&VfrDriverInfo->Link);\r
+    InternalVarCheckFreePool (VfrDriverInfo);\r
+  }\r
+}\r
+\r
+/**\r
+  Generate from FV.\r
+\r
+**/\r
+VOID\r
+VarCheckHiiGenFromFv (\r
+  VOID\r
+  )\r
+{\r
+  EFI_GUID      *DriverGuidArray;\r
+  BOOLEAN       ScanAll;\r
+\r
+  DEBUG ((EFI_D_INFO, "VarCheckHiiGenDxeFromFv\n"));\r
+\r
+  //\r
+  // Get vfr driver guid array from PCD.\r
+  //\r
+  DriverGuidArray = (EFI_GUID *) PcdGetPtr (PcdVarCheckVfrDriverGuidArray);\r
+\r
+  if (CompareGuid (&DriverGuidArray[0], &gZeroGuid)) {\r
+    //\r
+    // No VFR driver will be parsed from FVs.\r
+    //\r
+    return;\r
+  }\r
+\r
+  if (CompareGuid (&DriverGuidArray[0], &mAllFfGuid)) {\r
+    ScanAll = TRUE;\r
+  } else {\r
+    ScanAll = FALSE;\r
+    CreateVfrDriverList (DriverGuidArray);\r
+  }\r
+\r
+  ParseFv (ScanAll);\r
+\r
+  if (!ScanAll) {\r
+    DestroyVfrDriverList ();\r
+  }\r
+}\r