]> git.proxmox.com Git - mirror_edk2.git/blobdiff - FmpDevicePkg/FmpDxe/Dependency.c
FmdDevicePkg/FmpDxe: Support Fmp Capsule Dependency.
[mirror_edk2.git] / FmpDevicePkg / FmpDxe / Dependency.c
diff --git a/FmpDevicePkg/FmpDxe/Dependency.c b/FmpDevicePkg/FmpDxe/Dependency.c
new file mode 100644 (file)
index 0000000..b63a36b
--- /dev/null
@@ -0,0 +1,679 @@
+/** @file\r
+  Supports 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 "FmpDxe.h"\r
+#include "Dependency.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 variable used to support dependency evaluation\r
+//\r
+UINTN                          mNumberOfFmpInstance = 0;\r
+EFI_FIRMWARE_IMAGE_DESCRIPTOR  **mFmpImageInfoBuf   = NULL;\r
+\r
+//\r
+// Indicates the status of dependency check, default value is DEPENDENCIES_SATISFIED.\r
+//\r
+UINT8  mDependenciesCheckStatus = DEPENDENCIES_SATISFIED;\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
+    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
+/**\r
+  Pop an element from the stack.\r
+\r
+  @param[in]  Value                  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
+    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
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Evaluate the dependencies.\r
+\r
+  @param[in]   Dependencies        Dependency expressions.\r
+  @param[in]   DependenciesSize    Size of Dependency expressions.\r
+\r
+  @retval TRUE           Dependency expressions evaluate to TRUE.\r
+  @retval FALSE          Dependency expressions evaluate to FALSE.\r
+\r
+**/\r
+BOOLEAN\r
+EvaluateDependencies (\r
+  IN  CONST EFI_FIRMWARE_IMAGE_DEP *     Dependencies,\r
+  IN  CONST UINTN                        DependenciesSize\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
+  if (Dependencies == NULL || DependenciesSize == 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
+        Status = EFI_INVALID_PARAMETER;\r
+        goto Error;\r
+      }\r
+\r
+      CopyGuid (&ImageTypeId, (EFI_GUID *) (Iterator + 1));\r
+      Iterator = Iterator + sizeof (EFI_GUID);\r
+\r
+      for (Index = 0; Index < mNumberOfFmpInstance; Index ++){\r
+        if (mFmpImageInfoBuf[Index] == NULL) {\r
+          continue;\r
+        }\r
+        if(CompareGuid (&mFmpImageInfoBuf[Index]->ImageTypeId, &ImageTypeId)){\r
+          Status = Push (mFmpImageInfoBuf[Index]->Version, VersionType);\r
+          if (EFI_ERROR (Status)) {\r
+            goto Error;\r
+          }\r
+          break;\r
+        }\r
+      }\r
+      if (Index == mNumberOfFmpInstance) {\r
+        Status = EFI_NOT_FOUND;\r
+        goto Error;\r
+      }\r
+      break;\r
+    case EFI_FMP_DEP_PUSH_VERSION:\r
+      if (Iterator + sizeof (UINT32) >= (UINT8 *) Dependencies->Dependencies + DependenciesSize ) {\r
+        Status = EFI_INVALID_PARAMETER;\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
+      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
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Error;\r
+    }\r
+    Iterator++;\r
+  }\r
+\r
+Error:\r
+\r
+  DEBUG ((DEBUG_ERROR, "FmpDxe(%s): EvaluateDependencies() - RESULT = FALSE (Status = %r)\n", mImageIdName, Status));\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Validate the dependency expression and output its size.\r
+\r
+  @param[in]   ImageDepex      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
+ValidateImageDepex (\r
+  IN  EFI_FIRMWARE_IMAGE_DEP             *ImageDepex,\r
+  IN  CONST UINTN                        MaxDepexSize,\r
+  OUT UINT32                             *DepexSize\r
+  )\r
+{\r
+  UINT8  *Depex;\r
+\r
+  *DepexSize = 0;\r
+  Depex = ImageDepex->Dependencies;\r
+  while (Depex < ImageDepex->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, ImageDepex->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
+      *DepexSize = (UINT32)(Depex - ImageDepex->Dependencies);\r
+      return TRUE;\r
+    default:\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Get the size of dependencies. Assume the dependencies is validated before\r
+  calling this function.\r
+\r
+  @param[in]   Dependencies    Pointer to the EFI_FIRMWARE_IMAGE_DEP.\r
+\r
+  @retval  The size of dependencies.\r
+\r
+**/\r
+UINTN\r
+GetDepexSize (\r
+  IN CONST EFI_FIRMWARE_IMAGE_DEP  *Dependencies\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  if (Dependencies == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Index = 0;\r
+  while (Dependencies->Dependencies[Index] != EFI_FMP_DEP_END) {\r
+    Index ++;\r
+  }\r
+\r
+  return Index + 1;\r
+}\r
+\r
+/**\r
+  Check dependency for firmware update.\r
+\r
+  @param[in]   ImageTypeId         Image Type Id.\r
+  @param[in]   Version             New version.\r
+  @param[in]   Dependencies        The dependencies.\r
+  @param[in]   DependenciesSize    Size of the dependencies\r
+  @param[out]  IsSatisfied         Indicate the dependencies is satisfied or not.\r
+\r
+  @retval  EFI_SUCCESS             Dependency Evaluation is successful.\r
+  @retval  Others                  Dependency Evaluation fails with unexpected error.\r
+\r
+**/\r
+EFI_STATUS\r
+EvaluateImageDependencies (\r
+  IN CONST EFI_GUID                ImageTypeId,\r
+  IN CONST UINT32                  Version,\r
+  IN CONST EFI_FIRMWARE_IMAGE_DEP  *Dependencies,\r
+  IN CONST UINT32                  DependenciesSize,\r
+  OUT BOOLEAN                      *IsSatisfied\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             Index;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;\r
+  UINTN                             ImageInfoSize;\r
+  UINT32                            FmpImageInfoDescriptorVer;\r
+  UINT8                             FmpImageInfoCount;\r
+  UINTN                             DescriptorSize;\r
+  UINT32                            PackageVersion;\r
+  CHAR16                            *PackageVersionName;\r
+  UINTN                             DepexSize;\r
+\r
+  *IsSatisfied       = TRUE;\r
+  PackageVersionName = NULL;\r
+\r
+  //\r
+  // Get ImageDescriptors of all FMP instances, and archive them for depex evaluation.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                ByProtocol,\r
+                &gEfiFirmwareManagementProtocolGuid,\r
+                NULL,\r
+                &mNumberOfFmpInstance,\r
+                &HandleBuffer\r
+                );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  mFmpImageInfoBuf = AllocatePool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * mNumberOfFmpInstance);\r
+  if (mFmpImageInfoBuf == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareManagementProtocolGuid,\r
+                    (VOID **) &Fmp\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      continue;\r
+    }\r
+\r
+    ImageInfoSize = 0;\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL\r
+                    );\r
+    if (Status != EFI_BUFFER_TOO_SMALL) {\r
+      continue;\r
+    }\r
+\r
+    mFmpImageInfoBuf[Index] = AllocateZeroPool (ImageInfoSize);\r
+    if (mFmpImageInfoBuf[Index] == NULL) {\r
+      continue;\r
+    }\r
+\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,               // ImageInfoSize\r
+                    mFmpImageInfoBuf[Index],      // ImageInfo\r
+                    &FmpImageInfoDescriptorVer,   // DescriptorVersion\r
+                    &FmpImageInfoCount,           // DescriptorCount\r
+                    &DescriptorSize,              // DescriptorSize\r
+                    &PackageVersion,              // PackageVersion\r
+                    &PackageVersionName           // PackageVersionName\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      FreePool (mFmpImageInfoBuf[Index]);\r
+      mFmpImageInfoBuf[Index] = NULL;\r
+      continue;\r
+    }\r
+\r
+    if (PackageVersionName != NULL) {\r
+      FreePool (PackageVersionName);\r
+      PackageVersionName = NULL;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Step 1 - Evaluate firmware image's depex, against the version of other Fmp instances.\r
+  //\r
+  if (Dependencies != NULL) {\r
+    *IsSatisfied = EvaluateDependencies (Dependencies, DependenciesSize);\r
+  }\r
+\r
+  if (!*IsSatisfied) {\r
+    goto cleanup;\r
+  }\r
+\r
+  //\r
+  // Step 2 - Evaluate the depex of all other Fmp instances, against the new version in\r
+  // the firmware image.\r
+  //\r
+\r
+  //\r
+  // Update the new version to mFmpImageInfoBuf.\r
+  //\r
+  for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {\r
+    if (mFmpImageInfoBuf[Index] != NULL) {\r
+      if (CompareGuid (&ImageTypeId, &mFmpImageInfoBuf[Index]->ImageTypeId)) {\r
+        mFmpImageInfoBuf[Index]->Version = Version;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Evaluate the Dependencies one by one.\r
+  //\r
+  for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {\r
+    if (mFmpImageInfoBuf[Index] != NULL) {\r
+      //\r
+      // Skip the Fmp instance to be "SetImage".\r
+      //\r
+      if (CompareGuid (&ImageTypeId, &mFmpImageInfoBuf[Index]->ImageTypeId)) {\r
+        continue;\r
+      }\r
+      if ((mFmpImageInfoBuf[Index]->AttributesSupported & IMAGE_ATTRIBUTE_DEPENDENCY) &&\r
+           mFmpImageInfoBuf[Index]->Dependencies != NULL) {\r
+        //\r
+        // Get the size of depex.\r
+        // Assume that the dependencies in EFI_FIRMWARE_IMAGE_DESCRIPTOR is validated when PopulateDescriptor().\r
+        //\r
+        DepexSize = GetDepexSize (mFmpImageInfoBuf[Index]->Dependencies);\r
+        if (DepexSize > 0) {\r
+          *IsSatisfied = EvaluateDependencies (mFmpImageInfoBuf[Index]->Dependencies, DepexSize);\r
+          if (!*IsSatisfied) {\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+cleanup:\r
+  if (mFmpImageInfoBuf != NULL) {\r
+    for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {\r
+      if (mFmpImageInfoBuf[Index] != NULL) {\r
+        FreePool (mFmpImageInfoBuf[Index]);\r
+      }\r
+    }\r
+    FreePool (mFmpImageInfoBuf);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r