]> git.proxmox.com Git - mirror_edk2.git/blobdiff - FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
FmpDevicePkg: Add FmpDependencyCheck library class and instances
[mirror_edk2.git] / FmpDevicePkg / Library / FmpDependencyCheckLib / FmpDependencyCheckLib.c
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
new file mode 100644 (file)
index 0000000..5e0241b
--- /dev/null
@@ -0,0 +1,196 @@
+/** @file\r
+  Provides FMP capsule dependency check services when updating the firmware\r
+  image of a FMP device.\r
+\r
+  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/FmpDependencyLib.h>\r
+#include <Library/FmpDependencyCheckLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+/**\r
+  Check dependency for firmware update.\r
+\r
+  @param[in]  ImageTypeId        Image Type Id.\r
+  @param[in]  Version            New version.\r
+  @param[in]  Dependencies       Fmp dependency.\r
+  @param[in]  DependenciesSize   Size, in bytes, of the Fmp dependency.\r
+\r
+  @retval  TRUE    Dependencies are satisfied.\r
+  @retval  FALSE   Dependencies are unsatisfied or dependency check fails.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CheckFmpDependency (\r
+  IN  EFI_GUID                ImageTypeId,\r
+  IN  UINT32                  Version,\r
+  IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL\r
+  IN  UINT32                  DependenciesSize\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             Index;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;\r
+  UINTN                             ImageInfoSize;\r
+  UINT32                            *DescriptorVer;\r
+  UINT8                             FmpImageInfoCount;\r
+  UINTN                             *DescriptorSize;\r
+  UINT32                            PackageVersion;\r
+  CHAR16                            *PackageVersionName;\r
+  UINTN                             NumberOfFmpInstance;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR     **FmpImageInfoBuf;\r
+  FMP_DEPEX_CHECK_VERSION_DATA      *FmpVersions;\r
+  UINTN                             FmpVersionsCount;\r
+  BOOLEAN                           IsSatisfied;\r
+\r
+  FmpImageInfoBuf     = NULL;\r
+  DescriptorVer       = NULL;\r
+  DescriptorSize      = NULL;\r
+  NumberOfFmpInstance = 0;\r
+  FmpVersions         = NULL;\r
+  FmpVersionsCount    = 0;\r
+  IsSatisfied         = TRUE;\r
+  PackageVersionName  = NULL;\r
+\r
+  //\r
+  // Get ImageDescriptors of all FMP instances, and archive them for dependency evaluation.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                ByProtocol,\r
+                &gEfiFirmwareManagementProtocolGuid,\r
+                NULL,\r
+                &NumberOfFmpInstance,\r
+                &HandleBuffer\r
+                );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "CheckFmpDependency: Get Firmware Management Protocol failed. (%r)", Status));\r
+    goto cleanup;\r
+  }\r
+\r
+  FmpImageInfoBuf = AllocateZeroPool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * NumberOfFmpInstance);\r
+  if (FmpImageInfoBuf == NULL) {\r
+    IsSatisfied = FALSE;\r
+    goto cleanup;\r
+  }\r
+\r
+  DescriptorVer = AllocateZeroPool (sizeof(UINT32) * NumberOfFmpInstance);\r
+  if (DescriptorVer == NULL ) {\r
+    IsSatisfied = FALSE;\r
+    goto cleanup;\r
+  }\r
+\r
+  DescriptorSize = AllocateZeroPool (sizeof(UINTN) * NumberOfFmpInstance);\r
+  if (DescriptorSize == NULL ) {\r
+    IsSatisfied = FALSE;\r
+    goto cleanup;\r
+  }\r
+\r
+  FmpVersions = AllocateZeroPool (sizeof(FMP_DEPEX_CHECK_VERSION_DATA) * NumberOfFmpInstance);\r
+  if (FmpVersions == NULL) {\r
+    IsSatisfied = FALSE;\r
+    goto cleanup;\r
+  }\r
+\r
+  for (Index = 0; Index < NumberOfFmpInstance; Index ++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareManagementProtocolGuid,\r
+                    (VOID **) &Fmp\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      continue;\r
+    }\r
+\r
+    ImageInfoSize = 0;\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL\r
+                    );\r
+    if (Status != EFI_BUFFER_TOO_SMALL) {\r
+      continue;\r
+    }\r
+\r
+    FmpImageInfoBuf[Index] = AllocateZeroPool (ImageInfoSize);\r
+    if (FmpImageInfoBuf[Index] == NULL) {\r
+      continue;\r
+    }\r
+\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,               // ImageInfoSize\r
+                    FmpImageInfoBuf[Index],       // ImageInfo\r
+                    &DescriptorVer[Index],        // DescriptorVersion\r
+                    &FmpImageInfoCount,           // DescriptorCount\r
+                    &DescriptorSize[Index],       // DescriptorSize\r
+                    &PackageVersion,              // PackageVersion\r
+                    &PackageVersionName           // PackageVersionName\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      FreePool (FmpImageInfoBuf[Index]);\r
+      FmpImageInfoBuf[Index] = NULL;\r
+      continue;\r
+    }\r
+\r
+    if (PackageVersionName != NULL) {\r
+      FreePool (PackageVersionName);\r
+      PackageVersionName = NULL;\r
+    }\r
+\r
+    CopyGuid (&FmpVersions[FmpVersionsCount].ImageTypeId, &FmpImageInfoBuf[Index]->ImageTypeId);\r
+    FmpVersions[FmpVersionsCount].Version = FmpImageInfoBuf[Index]->Version;\r
+    FmpVersionsCount ++;\r
+  }\r
+\r
+  //\r
+  // Evaluate firmware image's depex, against the version of other Fmp instances.\r
+  //\r
+  if (Dependencies != NULL) {\r
+    IsSatisfied = EvaluateDependency (Dependencies, DependenciesSize, FmpVersions, FmpVersionsCount);\r
+  }\r
+\r
+  if (!IsSatisfied) {\r
+    DEBUG ((DEBUG_ERROR, "CheckFmpDependency: %g\'s dependency is not satisfied!\n", ImageTypeId));\r
+    goto cleanup;\r
+  }\r
+\r
+cleanup:\r
+  if (FmpImageInfoBuf != NULL) {\r
+    for (Index = 0; Index < NumberOfFmpInstance; Index ++) {\r
+      if (FmpImageInfoBuf[Index] != NULL) {\r
+        FreePool (FmpImageInfoBuf[Index]);\r
+      }\r
+    }\r
+    FreePool (FmpImageInfoBuf);\r
+  }\r
+\r
+  if (DescriptorVer != NULL) {\r
+    FreePool (DescriptorVer);\r
+  }\r
+\r
+  if (DescriptorSize != NULL) {\r
+    FreePool (DescriptorSize);\r
+  }\r
+\r
+  if (FmpVersions != NULL) {\r
+    FreePool (FmpVersions);\r
+  }\r
+\r
+  return IsSatisfied;\r
+}\r