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.kin...@intel.com>
Cc: Liming Gao <liming....@intel.com>
Cc: Sean Brogan <sean.bro...@microsoft.com>
Signed-off-by: Wei6 Xu <wei6...@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


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#58252): https://edk2.groups.io/g/devel/message/58252
Mute This Topic: https://groups.io/mt/73326869/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to