To keep api common please remove the CONST in ValidateDependency function (header and c file). With that change my review applies to the whole series.

After this stable tag it would be great to work on some documentation for FmpDxe. This driver was already complex and has now got even more complicated.


Reviewed-by: Sean Brogan <sean.bro...@microsoft.com>


On 5/14/2020 2:52 PM, Xu, Wei6 wrote:
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2696

This library provides services to evaluate Fmp capsule dependency
expression, validate dependency expression and get dependency
from firmware image.

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                      |   6 +-
  FmpDevicePkg/FmpDevicePkg.dsc                      |   4 +-
  FmpDevicePkg/Include/Library/FmpDependencyLib.h    |  89 ++++
  .../Library/FmpDependencyLib/FmpDependencyLib.c    | 546 +++++++++++++++++++++
  .../Library/FmpDependencyLib/FmpDependencyLib.inf  |  34 ++
  .../Library/FmpDependencyLib/FmpDependencyLib.uni  |  12 +
  6 files changed, 689 insertions(+), 2 deletions(-)
  create mode 100644 FmpDevicePkg/Include/Library/FmpDependencyLib.h
  create mode 100644 FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c
  create mode 100644 FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf
  create mode 100644 FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.uni

diff --git a/FmpDevicePkg/FmpDevicePkg.dec b/FmpDevicePkg/FmpDevicePkg.dec
index 55671878dd..4947008346 100644
--- a/FmpDevicePkg/FmpDevicePkg.dec
+++ b/FmpDevicePkg/FmpDevicePkg.dec
@@ -5,11 +5,11 @@
  # instance that supports the update of firmware storage devices using UEFI
  # Capsules.  The behavior of the Firmware Management Protocol instance is
  # customized using libraries and PCDs.
  #
  # Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
-# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
  #
  # SPDX-License-Identifier: BSD-2-Clause-Patent
  #
  ##
@@ -33,10 +33,14 @@ ## @libraryclass Provides firmware device specific services to support
    #                  updates of a firmware image stored in a firmware device.
    FmpDeviceLib|Include/Library/FmpDeviceLib.h
+ ## @libraryclass Provides generic services to support capsule dependency
+  #                  expression evaluation.
+  FmpDependencyLib|Include/Library/FmpDependencyLib.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
diff --git a/FmpDevicePkg/FmpDevicePkg.dsc b/FmpDevicePkg/FmpDevicePkg.dsc
index b8fb9d7c19..dfb3c1a141 100644
--- a/FmpDevicePkg/FmpDevicePkg.dsc
+++ b/FmpDevicePkg/FmpDevicePkg.dsc
@@ -5,11 +5,11 @@
  # instance that supports the update of firmware storage devices using UEFI
  # Capsules.  The behavior of the Firmware Management Protocol instance is
  # customized using libraries and PCDs.
  #
  # Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
-# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
  # Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights 
reserved.<BR>
  #
  # SPDX-License-Identifier: BSD-2-Clause-Patent
  #
  ##
@@ -58,10 +58,11 @@
  !endif
    
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
    
TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
[LibraryClasses.ARM, LibraryClasses.AARCH64]
    #
    # It is not possible to prevent the ARM compiler for generic intrinsic 
functions.
@@ -86,10 +87,11 @@
    #
    
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/FmpDxe/FmpDxeLib.inf
#
    # Modules
    #
diff --git a/FmpDevicePkg/Include/Library/FmpDependencyLib.h 
b/FmpDevicePkg/Include/Library/FmpDependencyLib.h
new file mode 100644
index 0000000000..1a191ca6ee
--- /dev/null
+++ b/FmpDevicePkg/Include/Library/FmpDependencyLib.h
@@ -0,0 +1,89 @@
+/** @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_LIB__
+#define __FMP_DEPENDENCY_LIB__
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+
+//
+// Data struct to store FMP ImageType and version for dependency check.
+//
+typedef struct {
+  EFI_GUID ImageTypeId;
+  UINT32   Version;
+} FMP_DEPEX_CHECK_VERSION_DATA;
+
+/**
+  Validate the dependency expression and output its size.
+
+  @param[in]   Dependencies   Pointer to the EFI_FIRMWARE_IMAGE_DEP.
+  @param[in]   MaxDepexSize   Max size of the dependency.
+  @param[out]  DepexSize      Size of dependency.
+
+  @retval TRUE    The capsule is valid.
+  @retval FALSE   The capsule is invalid.
+
+**/
+BOOLEAN
+EFIAPI
+ValidateDependency (
+  IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,
+  IN  CONST UINTN             MaxDepexSize,
+  OUT UINT32                  *DepexSize
+  );
+
+/**
+  Get dependency from firmware image.
+
+  @param[in]  Image       Points to the firmware image.
+  @param[in]  ImageSize   Size, in bytes, of the firmware image.
+  @param[out] DepexSize   Size, in bytes, of the dependency.
+
+  @retval  The pointer to dependency.
+  @retval  Null
+
+**/
+EFI_FIRMWARE_IMAGE_DEP*
+EFIAPI
+GetImageDependency (
+  IN  EFI_FIRMWARE_IMAGE_AUTHENTICATION  *Image,
+  IN  UINTN                              ImageSize,
+  OUT UINT32                             *DepexSize
+  );
+
+/**
+  Evaluate the dependencies. The caller must search all the Fmp instances and
+  gather their versions into FmpVersions parameter. If there is PUSH_GUID 
opcode
+  in dependency expression with no FmpVersions provided, the dependency will
+  evaluate to FALSE.
+
+  @param[in]   Dependencies       Dependency expressions.
+  @param[in]   DependenciesSize   Size of Dependency expressions.
+  @param[in]   FmpVersions        Array of Fmp ImageTypeId and version. This
+                                  parameter is optional and can be set to NULL.
+  @param[in]   FmpVersionsCount   Element count of the array. When FmpVersions
+                                  is NULL, FmpVersionsCount must be 0.
+
+  @retval TRUE    Dependency expressions evaluate to TRUE.
+  @retval FALSE   Dependency expressions evaluate to FALSE.
+
+**/
+BOOLEAN
+EFIAPI
+EvaluateDependency (
+  IN EFI_FIRMWARE_IMAGE_DEP        *Dependencies,
+  IN UINTN                         DependenciesSize,
+  IN FMP_DEPEX_CHECK_VERSION_DATA  *FmpVersions      OPTIONAL,
+  IN UINTN                         FmpVersionsCount
+  );
+
+#endif
diff --git a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c 
b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c
new file mode 100644
index 0000000000..a8083bff12
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c
@@ -0,0 +1,546 @@
+/** @file
+  Supports Fmp Capsule Dependency Expression.
+
+  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/MemoryAllocationLib.h>
+
+//
+// Define the initial size of the dependency expression evaluation stack
+//
+#define DEPEX_STACK_SIZE_INCREMENT  0x1000
+
+//
+// Type of stack element
+//
+typedef enum {
+  BooleanType,
+  VersionType
+} ELEMENT_TYPE;
+
+//
+// Value of stack element
+//
+typedef union {
+  BOOLEAN   Boolean;
+  UINT32    Version;
+} ELEMENT_VALUE;
+
+//
+// Stack element used to evaluate dependency expressions
+//
+typedef struct {
+  ELEMENT_VALUE Value;
+  ELEMENT_TYPE  Type;
+} DEPEX_ELEMENT;
+
+//
+// Global stack used to evaluate dependency expressions
+//
+DEPEX_ELEMENT  *mDepexEvaluationStack        = NULL;
+DEPEX_ELEMENT  *mDepexEvaluationStackEnd     = NULL;
+DEPEX_ELEMENT  *mDepexEvaluationStackPointer = NULL;
+
+/**
+  Grow size of the Depex stack
+
+  @retval EFI_SUCCESS           Stack successfully growed.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough system memory to grow the 
stack.
+
+**/
+EFI_STATUS
+GrowDepexStack (
+  VOID
+  )
+{
+  DEPEX_ELEMENT  *NewStack;
+  UINTN          Size;
+
+  Size = DEPEX_STACK_SIZE_INCREMENT;
+  if (mDepexEvaluationStack != NULL) {
+    Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
+  }
+
+  NewStack = AllocatePool (Size * sizeof (DEPEX_ELEMENT));
+  if (NewStack == NULL) {
+    DEBUG ((DEBUG_ERROR, "GrowDepexStack: Cannot allocate memory for dependency 
evaluation stack!\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (mDepexEvaluationStack != NULL) {
+    //
+    // Copy to Old Stack to the New Stack
+    //
+    CopyMem (
+      NewStack,
+      mDepexEvaluationStack,
+      (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof 
(DEPEX_ELEMENT)
+      );
+
+    //
+    // Free The Old Stack
+    //
+    FreePool (mDepexEvaluationStack);
+  }
+
+  //
+  // Make the Stack pointer point to the old data in the new stack
+  //
+  mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - 
mDepexEvaluationStack);
+  mDepexEvaluationStack        = NewStack;
+  mDepexEvaluationStackEnd     = NewStack + Size;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Push an element onto the Stack.
+
+  @param[in]  Value                  Value to push.
+  @param[in]  Type                   Element Type
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the 
stack.
+  @retval EFI_INVALID_PARAMETER  Wrong stack element type.
+
+**/
+EFI_STATUS
+Push (
+  IN UINT32   Value,
+  IN UINTN    Type
+  )
+{
+  EFI_STATUS      Status;
+  DEPEX_ELEMENT   Element;
+
+  //
+  // Check Type
+  //
+  if (Type != BooleanType && Type != VersionType) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check for a stack overflow condition
+  //
+  if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
+    //
+    // Grow the stack
+    //
+    Status = GrowDepexStack ();
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  Element.Value.Version = Value;
+  Element.Type = Type;
+
+  //
+  // Push the item onto the stack
+  //
+  *mDepexEvaluationStackPointer = Element;
+  mDepexEvaluationStackPointer++;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Pop an element from the stack.
+
+  @param[out]  Element                Element to pop.
+  @param[in]   Type                   Type of element.
+
+  @retval EFI_SUCCESS            The value was popped onto the stack.
+  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack.
+  @retval EFI_INVALID_PARAMETER  Type is mismatched.
+
+**/
+EFI_STATUS
+Pop (
+  OUT DEPEX_ELEMENT  *Element,
+  IN  ELEMENT_TYPE   Type
+  )
+{
+  //
+  // Check for a stack underflow condition
+  //
+  if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
+    DEBUG ((DEBUG_ERROR, "EvaluateDependency: Stack underflow!\n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Pop the item off the stack
+  //
+  mDepexEvaluationStackPointer--;
+  *Element = *mDepexEvaluationStackPointer;
+  if ((*Element).Type != Type) {
+    DEBUG ((DEBUG_ERROR, "EvaluateDependency: Popped element type is 
mismatched!\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Evaluate the dependencies. The caller must search all the Fmp instances and
+  gather their versions into FmpVersions parameter. If there is PUSH_GUID 
opcode
+  in dependency expression with no FmpVersions provided, the dependency will
+  evaluate to FALSE.
+
+  @param[in]   Dependencies       Dependency expressions.
+  @param[in]   DependenciesSize   Size of Dependency expressions.
+  @param[in]   FmpVersions        Array of Fmp ImageTypeId and version. This
+                                  parameter is optional and can be set to NULL.
+  @param[in]   FmpVersionsCount   Element count of the array. When FmpVersions
+                                  is NULL, FmpVersionsCount must be 0.
+
+  @retval TRUE    Dependency expressions evaluate to TRUE.
+  @retval FALSE   Dependency expressions evaluate to FALSE.
+
+**/
+BOOLEAN
+EFIAPI
+EvaluateDependency (
+  IN EFI_FIRMWARE_IMAGE_DEP        *Dependencies,
+  IN UINTN                         DependenciesSize,
+  IN FMP_DEPEX_CHECK_VERSION_DATA  *FmpVersions      OPTIONAL,
+  IN UINTN                         FmpVersionsCount
+  )
+{
+  EFI_STATUS                        Status;
+  UINT8                             *Iterator;
+  UINT8                             Index;
+  DEPEX_ELEMENT                     Element1;
+  DEPEX_ELEMENT                     Element2;
+  GUID                              ImageTypeId;
+  UINT32                            Version;
+
+  //
+  // Check if parameter is valid.
+  //
+  if (Dependencies == NULL || DependenciesSize == 0) {
+    return FALSE;
+  }
+
+  if (FmpVersions == NULL && FmpVersionsCount > 0) {
+    return FALSE;
+  }
+
+  //
+  // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
+  // incorrectly formed DEPEX expressions
+  //
+  mDepexEvaluationStackPointer = mDepexEvaluationStack;
+
+  Iterator = (UINT8 *) Dependencies->Dependencies;
+  while (Iterator < (UINT8 *) Dependencies->Dependencies + DependenciesSize) {
+    switch (*Iterator)
+    {
+    case EFI_FMP_DEP_PUSH_GUID:
+      if (Iterator + sizeof (EFI_GUID) >= (UINT8 *) Dependencies->Dependencies 
+ DependenciesSize) {
+        DEBUG ((DEBUG_ERROR, "EvaluateDependency: GUID extends beyond end of 
dependency expression!\n"));
+        goto Error;
+      }
+
+      CopyGuid (&ImageTypeId, (EFI_GUID *) (Iterator + 1));
+      Iterator = Iterator + sizeof (EFI_GUID);
+
+      for (Index = 0; Index < FmpVersionsCount; Index ++) {
+        if(CompareGuid (&FmpVersions[Index].ImageTypeId, &ImageTypeId)){
+          Status = Push (FmpVersions[Index].Version, VersionType);
+          if (EFI_ERROR (Status)) {
+            goto Error;
+          }
+          break;
+        }
+      }
+      if (Index == FmpVersionsCount) {
+        DEBUG ((DEBUG_ERROR, "EvaluateDependency: %g is not found!\n", 
&ImageTypeId));
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_PUSH_VERSION:
+      if (Iterator + sizeof (UINT32) >= (UINT8 *) Dependencies->Dependencies + 
DependenciesSize ) {
+        DEBUG ((DEBUG_ERROR, "EvaluateDependency: VERSION extends beyond end of 
dependency expression!\n"));
+        goto Error;
+      }
+
+      Version = *(UINT32 *) (Iterator + 1);
+      Status = Push (Version, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Iterator = Iterator + sizeof (UINT32);
+      break;
+    case EFI_FMP_DEP_VERSION_STR:
+      Iterator += AsciiStrnLenS ((CHAR8 *) Iterator, DependenciesSize - (Iterator 
- Dependencies->Dependencies));
+      if (Iterator == (UINT8 *) Dependencies->Dependencies + DependenciesSize) 
{
+        DEBUG ((DEBUG_ERROR, "EvaluateDependency: STRING extends beyond end of 
dependency expression!\n"));
+      }
+      break;
+    case EFI_FMP_DEP_AND:
+      Status = Pop (&Element1, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Pop (&Element2, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Push (Element1.Value.Boolean & Element2.Value.Boolean, 
BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_OR:
+      Status = Pop (&Element1, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Pop(&Element2, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Push (Element1.Value.Boolean | Element2.Value.Boolean, 
BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_NOT:
+      Status = Pop (&Element1, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Push (!(Element1.Value.Boolean), BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_TRUE:
+      Status = Push (TRUE, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_FALSE:
+      Status = Push (FALSE, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_EQ:
+      Status = Pop (&Element1, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Pop (&Element2, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = (Element1.Value.Version == Element2.Value.Version) ? Push 
(TRUE, BooleanType) : Push (FALSE, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_GT:
+      Status = Pop (&Element1, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Pop (&Element2, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = (Element1.Value.Version >  Element2.Value.Version) ? Push 
(TRUE, BooleanType) : Push (FALSE, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_GTE:
+      Status = Pop (&Element1, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Pop (&Element2, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = (Element1.Value.Version >= Element2.Value.Version) ? Push 
(TRUE, BooleanType) : Push (FALSE, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_LT:
+      Status = Pop (&Element1, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Pop (&Element2, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = (Element1.Value.Version <  Element2.Value.Version) ? Push 
(TRUE, BooleanType) : Push (FALSE, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_LTE:
+      Status = Pop (&Element1, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = Pop (&Element2, VersionType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      Status = (Element1.Value.Version <= Element2.Value.Version) ? Push 
(TRUE, BooleanType) : Push (FALSE, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      break;
+    case EFI_FMP_DEP_END:
+      Status = Pop (&Element1, BooleanType);
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+      return Element1.Value.Boolean;
+    default:
+      DEBUG ((DEBUG_ERROR, "EvaluateDependency: Unknown Opcode - %02x!\n", 
*Iterator));
+      goto Error;
+    }
+    Iterator++;
+  }
+
+  DEBUG ((DEBUG_ERROR, "EvaluateDependency: No EFI_FMP_DEP_END Opcode in 
exression!\n"));
+
+Error:
+  return FALSE;
+}
+
+/**
+  Validate the dependency expression and output its size.
+
+  @param[in]   Dependencies   Pointer to the EFI_FIRMWARE_IMAGE_DEP.
+  @param[in]   MaxDepexSize   Max size of the dependency.
+  @param[out]  DepexSize      Size of dependency.
+
+  @retval TRUE    The capsule is valid.
+  @retval FALSE   The capsule is invalid.
+
+**/
+BOOLEAN
+EFIAPI
+ValidateDependency (
+  IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,
+  IN  CONST UINTN             MaxDepexSize,
+  OUT UINT32                  *DepexSize
+  )
+{
+  UINT8  *Depex;
+
+  if (DepexSize != NULL) {
+      *DepexSize = 0;
+  }
+
+  if (Dependencies == NULL) {
+    return FALSE;
+  }
+
+  Depex = Dependencies->Dependencies;
+  while (Depex < Dependencies->Dependencies + MaxDepexSize) {
+    switch (*Depex)
+    {
+    case EFI_FMP_DEP_PUSH_GUID:
+      Depex += sizeof (EFI_GUID) + 1;
+      break;
+    case EFI_FMP_DEP_PUSH_VERSION:
+      Depex += sizeof (UINT32) + 1;
+      break;
+    case EFI_FMP_DEP_VERSION_STR:
+      Depex += AsciiStrnLenS ((CHAR8 *) Depex, Dependencies->Dependencies + 
MaxDepexSize - Depex) + 1;
+      break;
+    case EFI_FMP_DEP_AND:
+    case EFI_FMP_DEP_OR:
+    case EFI_FMP_DEP_NOT:
+    case EFI_FMP_DEP_TRUE:
+    case EFI_FMP_DEP_FALSE:
+    case EFI_FMP_DEP_EQ:
+    case EFI_FMP_DEP_GT:
+    case EFI_FMP_DEP_GTE:
+    case EFI_FMP_DEP_LT:
+    case EFI_FMP_DEP_LTE:
+      Depex += 1;
+      break;
+    case EFI_FMP_DEP_END:
+      Depex += 1;
+      if (DepexSize != NULL) {
+        *DepexSize = (UINT32)(Depex - Dependencies->Dependencies);
+      }
+      return TRUE;
+    default:
+      return FALSE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Get dependency from firmware image.
+
+  @param[in]  Image       Points to the firmware image.
+  @param[in]  ImageSize   Size, in bytes, of the firmware image.
+  @param[out] DepexSize   Size, in bytes, of the dependency.
+
+  @retval  The pointer to dependency.
+  @retval  Null
+
+**/
+EFI_FIRMWARE_IMAGE_DEP*
+EFIAPI
+GetImageDependency (
+  IN  EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+  IN  UINTN                             ImageSize,
+  OUT UINT32                            *DepexSize
+  )
+{
+  EFI_FIRMWARE_IMAGE_DEP *Depex;
+  UINTN                  MaxDepexSize;
+
+  if (Image == NULL) {
+    return NULL;
+  }
+
+  //
+  // Check to make sure that operation can be safely performed.
+  //
+  if (((UINTN)Image + sizeof (Image->MonotonicCount) + 
Image->AuthInfo.Hdr.dwLength) < (UINTN)Image || \
+      ((UINTN)Image + sizeof (Image->MonotonicCount) + 
Image->AuthInfo.Hdr.dwLength) >= (UINTN)Image + ImageSize) {
+    //
+    // Pointer overflow. Invalid image.
+    //
+    return NULL;
+  }
+
+  Depex = (EFI_FIRMWARE_IMAGE_DEP*)((UINT8 *)Image + sizeof 
(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
+  MaxDepexSize = ImageSize - (sizeof (Image->MonotonicCount) + 
Image->AuthInfo.Hdr.dwLength);
+
+  //
+  // Validate the dependency and get the size of dependency
+  //
+  if (ValidateDependency (Depex, MaxDepexSize, DepexSize)) {
+    return Depex;
+  }
+
+  return NULL;
+}
+
diff --git a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf 
b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf
new file mode 100644
index 0000000000..b7e5c8d002
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf
@@ -0,0 +1,34 @@
+## @file
+#  Provides Fmp Capsule Dependency Expression support.
+#
+#  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010005
+  BASE_NAME       = FmpDependencyLib
+  MODULE_UNI_FILE = FmpDependencyLib.uni
+  FILE_GUID       = 67F55EA4-B4CF-4A08-931B-0BBCF1E0F7A3
+  MODULE_TYPE     = BASE
+  VERSION_STRING  = 1.0
+  LIBRARY_CLASS   = FmpDependencyLib
+
+#
+# The following information is for reference only and not required by the 
build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  FmpDependencyLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  FmpDevicePkg/FmpDevicePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  BaseMemoryLib
diff --git a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.uni 
b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.uni
new file mode 100644
index 0000000000..422a96b570
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.uni
@@ -0,0 +1,12 @@
+// /** @file
+// Provides Fmp Capsule Dependency Expression support.
+//
+// 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 Lib"
+
+#string STR_MODULE_DESCRIPTION  #language en-US  "Provides Fmp Capsule Dependency 
Expression support."


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

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

Reply via email to