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 V3 1/5] FmpDevicePkg: Add FmpDependency library class and BASE instance
Date: Fri, 15 May 2020 05:52:28 +0800	[thread overview]
Message-ID: <20200514215232.13372-2-wei6.xu@intel.com> (raw)
In-Reply-To: <20200514215232.13372-1-wei6.xu@intel.com>

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.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                      |   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."
-- 
2.16.2.windows.1


  reply	other threads:[~2020-05-14 21:52 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-14 21:52 [edk2-devel] [PATCH V3 0/5] FmpDevicePkg: Move capsule dependency implement to library Xu, Wei6
2020-05-14 21:52 ` Xu, Wei6 [this message]
2020-05-15  0:59   ` [edk2-devel] [PATCH V3 1/5] FmpDevicePkg: Add FmpDependency library class and BASE instance Sean
2020-05-14 21:52 ` [edk2-devel] [PATCH V3 2/5] FmpDevicePkg/Test: Add FmpDependencyLib unit test Xu, Wei6
2020-05-14 21:52 ` [edk2-devel] [PATCH V3 3/5] FmpDevicePkg: Add FmpDependencyCheck library class and instances Xu, Wei6
2020-05-14 21:52 ` [edk2-devel] [PATCH V3 4/5] FmpDevicePkg: Add FmpDependencyDevice library class and NULL instance Xu, Wei6
2020-05-14 21:52 ` [edk2-devel] [PATCH V3 5/5] FmpDevicePkg/FmpDxe: Use new Fmp dependency libraries Xu, Wei6

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=20200514215232.13372-2-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