]> git.proxmox.com Git - mirror_edk2.git/commitdiff
FmpDevicePkg: Add FmpDependency library class and BASE instance
authorWei6 Xu <wei6.xu@intel.com>
Tue, 12 May 2020 05:27:07 +0000 (13:27 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Fri, 15 May 2020 06:11:44 +0000 (06:11 +0000)
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>
Reviewed-by: Sean Brogan <sean.brogan@microsoft.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
FmpDevicePkg/FmpDevicePkg.dec
FmpDevicePkg/FmpDevicePkg.dsc
FmpDevicePkg/Include/Library/FmpDependencyLib.h [new file with mode: 0644]
FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c [new file with mode: 0644]
FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf [new file with mode: 0644]
FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.uni [new file with mode: 0644]

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