public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Xu, Wei6" <wei6.xu@intel.com>
To: devel@edk2.groups.io
Cc: Michael D Kinney <michael.d.kinney@intel.com>,
	Liming Gao <liming.gao@intel.com>,
	Sean Brogan <sean.brogan@microsoft.com>
Subject: [edk2-devel] [PATCH 3/4] FmpDevicePkg: Add FmpDependencyCheck library class and instances
Date: Tue, 28 Apr 2020 21:25:29 +0800	[thread overview]
Message-ID: <20200428132530.4068-4-wei6.xu@intel.com> (raw)
In-Reply-To: <20200428132530.4068-1-wei6.xu@intel.com>

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

* This library class provides services to check Fmp Capsule Dependency
during updating firmware image, save the dependency to Fmp device after
update succeed and retrieve the dependency from Fmp device.
* Add FmpDependencyCheck instance, and provide PCD as an option to
disable Fmp Capsule dependency feature support.
* 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>
---
 FmpDevicePkg/FmpDevicePkg.dec                      |   9 +
 FmpDevicePkg/FmpDevicePkg.dsc                      |   3 +
 FmpDevicePkg/FmpDevicePkg.uni                      |   4 +-
 .../Include/Library/FmpDependencyCheckLib.h        |  71 +++
 .../FmpDependencyCheckLib/FmpDependencyCheckLib.c  | 533 +++++++++++++++++++++
 .../FmpDependencyCheckLib.inf                      |  51 ++
 .../FmpDependencyCheckLib.uni                      |  13 +
 .../FmpDependencyCheckLibNull.c                    |  74 +++
 .../FmpDependencyCheckLibNull.inf                  |  30 ++
 .../FmpDependencyCheckLibNull.uni                  |  13 +
 10 files changed, 800 insertions(+), 1 deletion(-)
 create mode 100644 FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h
 create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
 create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf
 create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.uni
 create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c
 create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
 create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.uni

diff --git a/FmpDevicePkg/FmpDevicePkg.dec b/FmpDevicePkg/FmpDevicePkg.dec
index 4947008346..4905d3b581 100644
--- a/FmpDevicePkg/FmpDevicePkg.dec
+++ b/FmpDevicePkg/FmpDevicePkg.dec
@@ -37,10 +37,14 @@
 
   ##  @libraryclass  Provides generic services to support capsule dependency
   #                  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
   #                  library class.  Instead, services are provided to retrieve
   #                  information from the FMP Payload Header.  If information is
@@ -115,10 +119,15 @@
   ## The Image Type ID to use if one is not provided by FmpDeviceLib. If this
   #  PCD is not a valid GUID value, then gEfiCallerIdGuid is used.
   # @Prompt Firmware Device Image Type ID
   gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageTypeIdGuid|{0}|VOID*|0x40000010
 
+  ## Indicate whether to perform the Fmp dependency check during the update of a
+  #  firmware device.
+  # @Prompt Fmp Dependency Check Enable
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDependencyCheckEnable|FALSE|BOOLEAN|0x40000013
+
 [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
   ## One or more PKCS7 certificates used to verify a firmware device capsule
   #  update image.  Encoded using the Variable-Length Opaque Data format of RFC
   #  4506 External Data Representation Standard (XDR).  The default value is
   #  empty with 0 certificates.
diff --git a/FmpDevicePkg/FmpDevicePkg.dsc b/FmpDevicePkg/FmpDevicePkg.dsc
index 49c6ff3a30..7e80806171 100644
--- a/FmpDevicePkg/FmpDevicePkg.dsc
+++ b/FmpDevicePkg/FmpDevicePkg.dsc
@@ -61,10 +61,11 @@
   FmpAuthenticationLib|SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf
   CapsuleUpdatePolicyLib|FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf
   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]
   #
   # It is not possible to prevent the ARM compiler for generic intrinsic functions.
@@ -90,10 +91,12 @@
   FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf
   FmpDevicePkg/Library/CapsuleUpdatePolicyLibOnProtocol/CapsuleUpdatePolicyLibOnProtocol.inf
   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
 
   #
   # Modules
   #
diff --git a/FmpDevicePkg/FmpDevicePkg.uni b/FmpDevicePkg/FmpDevicePkg.uni
index 263f88078b..52e5ba08af 100644
--- a/FmpDevicePkg/FmpDevicePkg.uni
+++ b/FmpDevicePkg/FmpDevicePkg.uni
@@ -78,6 +78,8 @@
                                                                                           "If this PCD is not a valid GUID value, then the firmware device is locked"
                                                                                           "when gEfiEndOfDxeEventGroupGuid (End of DXE Phase) is signaled.  The"
                                                                                           "default value is empty, so by default the firmware device is locked at the"
                                                                                           "end of the DXE phase."
 
-
+#string STR_gFmpDevicePkgTokenSpaceGuid_PcdFmpDependencyCheckEnable_PROMPT  #language en-US "Fmp Dependency Check Enable"
+#string STR_gFmpDevicePkgTokenSpaceGuid_PcdFmpDependencyCheckEnable_HELP    #language en-US "Indicate whether to perform the Fmp dependency check during the update of a"
+                                                                                            "firmware device."
diff --git a/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h b/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h
new file mode 100644
index 0000000000..fe329937d1
--- /dev/null
+++ b/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h
@@ -0,0 +1,71 @@
+/** @file
+  Fmp Capsule Dependency support 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  CONST EFI_GUID                ImageTypeId,
+  IN  CONST UINT32                  Version,
+  IN  CONST EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL
+  IN  CONST UINT32                  DependenciesSize  OPTIONAL
+  );
+
+/**
+  Save dependency to Fmp device.
+
+  @param[in]  Depex       Fmp dependency.
+  @param[in]  DepexSize   Size, in bytes, of the Fmp dependency.
+
+  @retval  EFI_SUCCESS       Save Fmp dependency succeeds.
+  @retval  EFI_UNSUPPORTED   Save Fmp dependency is not supported.
+  @retval  Others            Save Fmp dependency fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SaveFmpDependency (
+  IN EFI_FIRMWARE_IMAGE_DEP  *Depex,
+  IN UINT32                  DepexSize
+  );
+
+/**
+  Get dependency from the Fmp device.
+
+  @param[out]  DepexSize   Size, in bytes, of the dependency.
+
+  @retval  The pointer to dependency.
+  @retval  NULL
+
+**/
+EFI_FIRMWARE_IMAGE_DEP*
+EFIAPI
+GetFmpDependency (
+  OUT UINT32  *DepexSize  OPTIONAL
+  );
+
+#endif
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
new file mode 100644
index 0000000000..05804d6d19
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
@@ -0,0 +1,533 @@
+/** @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/FmpDeviceLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Protocol/VariableLock.h>
+
+#define FMP_DEPENDENCY_VARIABLE_NAME  L"FmpDepex"
+
+/**
+  Check if there is dependency in EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+  @param[in]  FmpImageInfoBuf   Pointer to EFI Firmware Image Descriptor.
+  @param[in]  DescriptorVer     Version of the descriptor.
+  @param[in]  DescriptorSize    Size of the Descriptor.
+
+  @retval  TRUE    There is dependency in descriptor.
+  @retval  FALSE   There is no dependency in descriptor.
+
+**/
+BOOLEAN
+DoDependencyExist (
+  IN EFI_FIRMWARE_IMAGE_DESCRIPTOR  *FmpImageInfoBuf,
+  IN UINT32                         DescriptorVer,
+  IN UINTN                          DescriptorSize
+  )
+{
+  //
+  // Descriptor version must be greater than or equal to 4.
+  //
+  if (DescriptorVer < 4) {
+    return FALSE;
+  }
+
+  //
+  // Dependency must be enabled.
+  //
+  if ((FmpImageInfoBuf->AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) == 0) {
+    return FALSE;
+  }
+
+  //
+  // Descriptor size must be large enough to reference the 'Dependencies' field.
+  //
+  if (DescriptorSize < OFFSET_OF(EFI_FIRMWARE_IMAGE_DESCRIPTOR, Dependencies)) {
+    return FALSE;
+  }
+
+  //
+  // Dependencies must not be NULL.
+  //
+  if (FmpImageInfoBuf->Dependencies == NULL) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  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  CONST EFI_GUID                ImageTypeId,
+  IN  CONST UINT32                  Version,
+  IN  CONST EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL
+  IN  CONST UINT32                  DependenciesSize  OPTIONAL
+  )
+{
+  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                             DepexSize;
+  UINTN                             NumberOfFmpInstance;
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR     **FmpImageInfoBuf;
+  FMP_DEPEX_CHECK_VERSION_DATA      *FmpVersions;
+  UINTN                             FmpVersionsCount;
+  BOOLEAN                           IsSatisfied;
+
+  if (!FeaturePcdGet (PcdFmpDependencyCheckEnable)) {
+    return TRUE;
+  }
+
+  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 ++;
+  }
+
+  //
+  // Step 1 - 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;
+  }
+
+  //
+  // Step 2 - Evaluate the depex of all other Fmp instances, against the new version in
+  // the firmware image.
+  //
+
+  //
+  // Update the new version to FmpVersions.
+  //
+  for (Index = 0; Index < FmpVersionsCount; Index ++) {
+    if (CompareGuid (&ImageTypeId, &FmpVersions[Index].ImageTypeId)) {
+      FmpVersions[Index].Version = Version;
+      break;
+    }
+  }
+
+  //
+  // Evaluate the Dependencies one by one.
+  //
+  for (Index = 0; Index < NumberOfFmpInstance; Index ++) {
+    if (FmpImageInfoBuf[Index] != NULL) {
+      //
+      // Skip the Fmp instance to be "SetImage".
+      //
+      if (CompareGuid (&ImageTypeId, &FmpImageInfoBuf[Index]->ImageTypeId)) {
+        continue;
+      }
+      //
+      // Check if dependency exists in the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+      //
+      if (DoDependencyExist (FmpImageInfoBuf[Index], DescriptorVer[Index], DescriptorSize[Index])) {
+        //
+        // Get the size of dependency.
+        // Assume that the dependencies in EFI_FIRMWARE_IMAGE_DESCRIPTOR is validated when PopulateDescriptor().
+        //
+        DepexSize = GetDependencySize (FmpImageInfoBuf[Index]->Dependencies);
+        if (DepexSize > 0) {
+          IsSatisfied = EvaluateDependency (FmpImageInfoBuf[Index]->Dependencies, DepexSize, FmpVersions, FmpVersionsCount);
+          if (!IsSatisfied) {
+            DEBUG ((DEBUG_ERROR, "CheckFmpDependency: %g\'s dependency is not satisfied!\n", FmpImageInfoBuf[Index]->ImageTypeId));
+            break;
+          }
+        }
+      }
+    }
+  }
+
+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;
+}
+
+/**
+  Generates a Null-terminated Unicode string UEFI Variable name from a base name
+  and a hardware instance.  If the hardware instance value is 0, then the base
+  name is returned.  If the hardware instance value is non-zero, then the 64-bit
+  hardware instance value is converted to a 16 character hex string and appended
+  to base name.  The UEFI Variable name returned is allocated using the UEFI
+  Boot Service AllocatePool().
+
+  @return  Pointer to the allocated UEFI Variable name.  Returns NULL if the
+           UEFI Variable can not be allocated.
+**/
+static
+CHAR16 *
+GenerateFmpDepexVariableName (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Size;
+  CHAR16      *VariableName;
+  UINT64      HardwareInstance;
+
+  //
+  // Allocate Unicode string with room for BaseVariableName and a 16 digit
+  // hexadecimal value for the HardwareInstance value.
+  //
+  Size = StrSize (FMP_DEPENDENCY_VARIABLE_NAME) + 16 * sizeof (CHAR16);
+  VariableName = AllocateCopyPool (Size, FMP_DEPENDENCY_VARIABLE_NAME);
+  if (VariableName == NULL) {
+    DEBUG ((DEBUG_ERROR, "FmpDependencyCheckLib: Failed to generate variable name %s.\n", FMP_DEPENDENCY_VARIABLE_NAME));
+    return VariableName;
+  }
+
+  //
+  // Get the hardware instance from FmpDeviceLib
+  //
+  Status = FmpDeviceGetHardwareInstance (&HardwareInstance);
+  if (EFI_ERROR (Status)) {
+    return VariableName;
+  }
+
+  UnicodeValueToStringS (
+    &VariableName[StrLen(FMP_DEPENDENCY_VARIABLE_NAME)],
+    Size,
+    PREFIX_ZERO | RADIX_HEX,
+    HardwareInstance,
+    16
+    );
+  return VariableName;
+}
+
+/**
+  Save dependency to Fmp device.
+
+  @param[in]  Depex       Fmp dependency.
+  @param[in]  DepexSize   Size, in bytes, of the Fmp dependency.
+
+  @retval  EFI_SUCCESS       Save Fmp dependency succeeds.
+  @retval  EFI_UNSUPPORTED   Save Fmp dependency is not supported.
+  @retval  Others            Save Fmp dependency fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SaveFmpDependency (
+  IN EFI_FIRMWARE_IMAGE_DEP  *Depex,
+  IN UINT32                  DepexSize
+  )
+{
+  EFI_STATUS Status;
+  CHAR16     *VariableName;
+
+  if (!FeaturePcdGet (PcdFmpDependencyCheckEnable)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Generate dependency variable name by HardwareInstance.
+  //
+  VariableName = GenerateFmpDepexVariableName ();
+  if (VariableName == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Save dependency to variable.
+  //
+  Status = gRT->SetVariable (
+             VariableName,
+             &gEfiCallerIdGuid,
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+             DepexSize,
+             (VOID *) Depex
+             );
+
+  if (VariableName != NULL) {
+    FreePool (VariableName);
+  }
+
+  return Status;
+}
+
+/**
+  Get dependency from the Fmp device.
+
+  @param[out]  DepexSize   Size, in bytes, of the dependency.
+
+  @retval  The pointer to dependency.
+  @retval  NULL
+
+**/
+EFI_FIRMWARE_IMAGE_DEP*
+EFIAPI
+GetFmpDependency (
+  OUT UINT32  *DepexSize  OPTIONAL
+  )
+{
+  EFI_STATUS             Status;
+  EFI_FIRMWARE_IMAGE_DEP *Depex;
+  UINTN                  Size;
+  CHAR16                 *VariableName;
+
+  if (DepexSize != NULL) {
+    *DepexSize = 0;
+  }
+
+  if (!FeaturePcdGet (PcdFmpDependencyCheckEnable)) {
+    return NULL;
+  }
+
+  Depex = NULL;
+  Size  = 0;
+
+  //
+  // Generate dependency variable name by HardwareInstance.
+  //
+  VariableName = GenerateFmpDepexVariableName ();
+  if (VariableName == NULL) {
+    return NULL;
+  }
+
+  //
+  // Get dependency from variable.
+  //
+  Status = GetVariable2 (
+             VariableName,
+             &gEfiCallerIdGuid,
+             (VOID **) &Depex,
+             &Size
+             );
+  if (EFI_ERROR (Status)) {
+    if (Status != EFI_NOT_FOUND) {
+      //
+      // Treat EFI_NOT_FOUND as no dependency.
+      // Other errors are treated as dependency evaluates to FALSE.
+      //
+      Size = 2;
+      Depex = AllocatePool (Size * sizeof(UINT8));
+      if (Depex != NULL) {
+        Depex->Dependencies[0] = EFI_FMP_DEP_FALSE;
+        Depex->Dependencies[1] = EFI_FMP_DEP_END;
+      }
+    }
+  }
+
+  if (DepexSize != NULL) {
+    *DepexSize = (UINT32) Size;
+  }
+
+  if (VariableName != NULL) {
+    FreePool (VariableName);
+  }
+
+  return Depex;
+}
+
+/**
+  The constructor function to lock FmpDepex variable.
+
+  @param[in]   ImageHandle   The firmware allocated handle for the EFI image.
+  @param[in]   SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor succeeds.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDependencyCheckLibConstructor (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+)
+{
+  EFI_STATUS                    Status;
+  EDKII_VARIABLE_LOCK_PROTOCOL  *VariableLock;
+  CHAR16                        *VariableName;
+
+  VariableLock = NULL;
+  Status = gBS->LocateProtocol (
+                  &gEdkiiVariableLockProtocolGuid,
+                  NULL,
+                  (VOID **)&VariableLock
+                  );
+  if (EFI_ERROR (Status) || VariableLock == NULL) {
+    DEBUG ((DEBUG_ERROR, "FmpDependencyCheckLib: Failed to locate Variable Lock Protocol (%r).\n", Status));
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Generate dependency variable name by HardwareInstance.
+  //
+  VariableName = GenerateFmpDepexVariableName ();
+  if (VariableName == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  Status = VariableLock->RequestToLock (
+                           VariableLock,
+                           VariableName,
+                           &gEfiCallerIdGuid
+                           );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "FmpDependencyCheckLib: Failed to lock variable %s (%r)\n", VariableName, Status));
+  }
+
+  if (VariableName != NULL) {
+    FreePool (VariableName);
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf
new file mode 100644
index 0000000000..f08516cb28
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf
@@ -0,0 +1,51 @@
+## @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
+  CONSTRUCTOR     = FmpDependencyCheckLibConstructor
+
+#
+# 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
+  FmpDeviceLib
+  MemoryAllocationLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  PcdLib
+  PrintLib
+
+[Pcd]
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDependencyCheckEnable
+
+[Protocols]
+  gEdkiiVariableLockProtocolGuid                ## CONSUMES
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.uni b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.uni
new file mode 100644
index 0000000000..c6369e2277
--- /dev/null
+++ b/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."
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c
new file mode 100644
index 0000000000..d2eea04c15
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c
@@ -0,0 +1,74 @@
+/** @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/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  CONST EFI_GUID                ImageTypeId,
+  IN  CONST UINT32                  Version,
+  IN  CONST EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL
+  IN  CONST UINT32                  DependenciesSize  OPTIONAL
+  )
+{
+  return TRUE;
+}
+
+/**
+  Save dependency to Fmp device.
+
+  @param[in]  Depex       Fmp dependency.
+  @param[in]  DepexSize   Size, in bytes, of the Fmp dependency.
+
+  @retval  EFI_SUCCESS       Save Fmp dependency succeeds.
+  @retval  EFI_UNSUPPORTED   Save Fmp dependency is not supported.
+  @retval  Others            Save Fmp dependency fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SaveFmpDependency (
+  IN EFI_FIRMWARE_IMAGE_DEP  *Depex,
+  IN UINT32                  DepexSize
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Get dependency from the Fmp device.
+
+  @param[out]  DepexSize   Size, in bytes, of the dependency.
+
+  @retval  The pointer to dependency.
+  @retval  NULL
+
+**/
+EFI_FIRMWARE_IMAGE_DEP*
+EFIAPI
+GetFmpDependency (
+  OUT UINT32  *DepexSize  OPTIONAL
+  )
+{
+  return NULL;
+}
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
new file mode 100644
index 0000000000..363c52d85b
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
@@ -0,0 +1,30 @@
+## @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       = 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
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.uni b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.uni
new file mode 100644
index 0000000000..c6369e2277
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.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."
-- 
2.16.2.windows.1


  parent reply	other threads:[~2020-04-28 13:25 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-28 13:25 [edk2-devel] [PATCH 0/4] FmpDevicePkg: Move capsule dependency implement to library Xu, Wei6
2020-04-28 13:25 ` [edk2-devel] [PATCH 1/4] FmpDevicePkg: Add FmpDependency library class and BASE instance Xu, Wei6
2020-04-28 13:25 ` [edk2-devel] [PATCH 2/4] FmpDevicePkg/Test: Add FmpDependencyLib unit test Xu, Wei6
2020-04-28 13:25 ` Xu, Wei6 [this message]
2020-04-28 13:25 ` [edk2-devel] [PATCH 4/4] FmpDevicePkg/FmpDxe: Use FmpDependencyLib and FmpDependencyCheckLib Xu, Wei6
2020-05-06 14:08 ` [edk2-devel] [PATCH 0/4] FmpDevicePkg: Move capsule dependency implement to library Liming Gao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200428132530.4068-4-wei6.xu@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox