Browse Source

FmpDevicePkg: Add FmpDependencyCheck library class and instances

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2696

* This library class provides platform specific services to support
dependency check during updating firmware image. Platform can perform
dependency check in platform specific manner by implementing its own
FmpDependencyCheckLib.
* Add FmpDependencyCheck instance to provide a sample of dependency
check. The sample instance only checks the dependency from capsule
image. The dependency from other FMP instances isn't checked here.
* Add NULL instance as an option to skip the dependency check.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Signed-off-by: Wei6 Xu <wei6.xu@intel.com>
Reviewed-by: Sean Brogan <sean.brogan@microsoft.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
Wei6 Xu 4 years ago
parent
commit
6c4966423b

+ 4 - 0
FmpDevicePkg/FmpDevicePkg.dec

@@ -39,6 +39,10 @@
   #                  expression evaluation.
   FmpDependencyLib|Include/Library/FmpDependencyLib.h
 
+  ##  @libraryclass  Provides platform specific services to support dependency
+  #                  check during update of firmware image.
+  FmpDependencyCheckLib|Include/Library/FmpDependencyCheckLib.h
+
 [LibraryClasses.Common.Private]
   ##  @libraryclass  Provides services to retrieve values from a capsule's FMP
   #                  Payload Header.  The structure is not included in the

+ 3 - 0
FmpDevicePkg/FmpDevicePkg.dsc

@@ -63,6 +63,7 @@
   FmpPayloadHeaderLib|FmpDevicePkg/Library/FmpPayloadHeaderLibV1/FmpPayloadHeaderLibV1.inf
   FmpDeviceLib|FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf
   FmpDependencyLib|FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf
+  FmpDependencyCheckLib|FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
   TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
 
 [LibraryClasses.ARM, LibraryClasses.AARCH64]
@@ -92,6 +93,8 @@
   FmpDevicePkg/Library/FmpPayloadHeaderLibV1/FmpPayloadHeaderLibV1.inf
   FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf
   FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf
+  FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf
+  FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
   FmpDevicePkg/FmpDxe/FmpDxeLib.inf
 
   #

+ 38 - 0
FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h

@@ -0,0 +1,38 @@
+/** @file
+  Fmp Capsule Dependency check functions for Firmware Management Protocol based
+  firmware updates.
+
+  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FMP_DEPENDENCY_CHECK_LIB__
+#define __FMP_DEPENDENCY_CHECK_LIB__
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+
+/**
+  Check dependency for firmware update.
+
+  @param[in]  ImageTypeId        Image Type Id.
+  @param[in]  Version            New version.
+  @param[in]  Dependencies       Fmp dependency.
+  @param[in]  DependenciesSize   Size, in bytes, of the Fmp dependency.
+
+  @retval  TRUE    Dependencies are satisfied.
+  @retval  FALSE   Dependencies are unsatisfied or dependency check fails.
+
+**/
+BOOLEAN
+EFIAPI
+CheckFmpDependency (
+  IN  EFI_GUID                ImageTypeId,
+  IN  UINT32                  Version,
+  IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL
+  IN  UINT32                  DependenciesSize
+  );
+
+#endif

+ 196 - 0
FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c

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

+ 43 - 0
FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf

@@ -0,0 +1,43 @@
+## @file
+#  Provides FMP capsule dependency check services when updating the firmware
+#  image of a FMP device.
+#
+#  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010005
+  BASE_NAME       = FmpDependencyCheckLib
+  MODULE_UNI_FILE = FmpDependencyCheckLib.uni
+  FILE_GUID       = 8296D425-3095-4CFE-88D8-B0A44DB174A8
+  MODULE_TYPE     = DXE_DRIVER
+  VERSION_STRING  = 1.0
+  LIBRARY_CLASS   = FmpDependencyCheckLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  FmpDependencyCheckLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  FmpDevicePkg/FmpDevicePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  FmpDependencyLib
+  MemoryAllocationLib
+  UefiLib
+  UefiBootServicesTableLib
+
+[Protocols]
+  gEfiFirmwareManagementProtocolGuid  ## CONSUMES

+ 13 - 0
FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.uni

@@ -0,0 +1,13 @@
+// /** @file
+// Provides FMP capsule dependency check services when updating the firmware
+// image of a FMP device.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT     #language en-US  "FMP Dependency Check Lib"
+
+#string STR_MODULE_DESCRIPTION  #language en-US  "Provides FMP capsule dependency check services when updating the firmware image of a FMP device."

+ 34 - 0
FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c

@@ -0,0 +1,34 @@
+/** @file
+  Null instance of FmpDependencyCheckLib.
+
+  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiDxe.h>
+#include <Library/FmpDependencyCheckLib.h>
+
+/**
+  Check dependency for firmware update.
+
+  @param[in]  ImageTypeId        Image Type Id.
+  @param[in]  Version            New version.
+  @param[in]  Dependencies       Fmp dependency.
+  @param[in]  DependenciesSize   Size, in bytes, of the Fmp dependency.
+
+  @retval  TRUE    Dependencies are satisfied.
+  @retval  FALSE   Dependencies are unsatisfied or dependency check fails.
+
+**/
+BOOLEAN
+EFIAPI
+CheckFmpDependency (
+  IN  EFI_GUID                ImageTypeId,
+  IN  UINT32                  Version,
+  IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL
+  IN  UINT32                  DependenciesSize
+  )
+{
+  return TRUE;
+}

+ 30 - 0
FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf

@@ -0,0 +1,30 @@
+## @file
+#  Null instance of FmpDependencyCheckLib as an option to skip the dependency
+#  check when updating the firmware image of a FMP device.
+#
+#  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010005
+  BASE_NAME       = FmpDependencyCheckLibNull
+  MODULE_UNI_FILE = FmpDependencyCheckLibNull.uni
+  FILE_GUID       = D63F3166-9CBC-4AC2-8F23-8818E42EA2BD
+  MODULE_TYPE     = DXE_DRIVER
+  VERSION_STRING  = 1.0
+  LIBRARY_CLASS   = FmpDependencyCheckLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  FmpDependencyCheckLibNull.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  FmpDevicePkg/FmpDevicePkg.dec

+ 13 - 0
FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.uni

@@ -0,0 +1,13 @@
+// /** @file
+// Null instance of FmpDependencyCheckLib as an option to skip the dependency
+// check when updating the firmware image of a FMP device.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT     #language en-US  "FMP Dependency Check Library NULL instance"
+
+#string STR_MODULE_DESCRIPTION  #language en-US  "Null instance of FmpDependencyCheckLib as an option to skip the dependency check when updating the firmware image of a FMP device."