]> git.proxmox.com Git - mirror_edk2.git/commitdiff
FmpDevicePkg: Add Last Attempt Status support to dependency libs
authorMichael Kubacki <michael.kubacki@microsoft.com>
Mon, 19 Oct 2020 23:59:38 +0000 (07:59 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 28 Oct 2020 06:05:52 +0000 (06:05 +0000)
The FMP dependency libraries are leveraged during firmware update
to check for dependencies required to update the image.

This change adds granular Last Attempt Status code support to these
services so failures can be more easily observed during the firmware
update process via Last Attempt Status codes.

Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Cc: Wei6 Xu <wei6.xu@intel.com>
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
Acked-by: Liming Gao <gaoliming@byosoft.com.cn>
Reviewed-by: Wei6 Xu <wei6.xu@intel.com>
Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
FmpDevicePkg/FmpDxe/FmpDxe.c
FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h
FmpDevicePkg/Include/Library/FmpDependencyLib.h
FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c
FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.c
FmpDevicePkg/Test/UnitTest/Library/FmpDependencyLib/EvaluateDependencyUnitTest.c

index b7fd9c93aea0cee0115dd274f3bffbea3a6b8f1b..de7f1fe53e327a387f8b99592f9d892e03d08796 100644 (file)
@@ -730,6 +730,15 @@ GetAllHeaderSize (
                                  LAST_ATTEMPT_STATUS_DRIVER_MIN_ERROR_CODE_VALUE\r
                                  to LAST_ATTEMPT_STATUS_DRIVER_MAX_ERROR_CODE_VALUE.\r
 \r
+                                 This function might also return error codes that occur within libraries\r
+                                 linked against this module that return last attempt error codes such as:\r
+\r
+                                 LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_LIB_MIN_ERROR_CODE_VALUE to\r
+                                 LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_LIB_MAX_ERROR_CODE_VALUE\r
+\r
+                                 LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_CHECK_LIB_MIN_ERROR_CODE_VALUE to\r
+                                 LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_CHECK_LIB_MAX_ERROR_CODE_VALUE\r
+\r
   @retval EFI_SUCCESS            The image was successfully checked.\r
   @retval EFI_ABORTED            The operation is aborted.\r
   @retval EFI_INVALID_PARAMETER  The Image was NULL.\r
@@ -925,7 +934,16 @@ CheckTheImageInternal (
   //\r
   // Get the dependency from Image.\r
   //\r
-  Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize);\r
+  Dependencies =  GetImageDependency (\r
+                    (EFI_FIRMWARE_IMAGE_AUTHENTICATION *) Image,\r
+                    ImageSize,\r
+                    &DependenciesSize,\r
+                    LastAttemptStatus\r
+                    );\r
+  if (*LastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) {\r
+    Status = EFI_ABORTED;\r
+    goto cleanup;\r
+  }\r
 \r
   //\r
   // Check the FmpPayloadHeader\r
@@ -964,11 +982,18 @@ CheckTheImageInternal (
   //\r
   // Evaluate dependency expression\r
   //\r
-  Private->DependenciesSatisfied = CheckFmpDependency (Private->Descriptor.ImageTypeId, Version, Dependencies, DependenciesSize);\r
+  Private->DependenciesSatisfied =  CheckFmpDependency (\r
+                                      Private->Descriptor.ImageTypeId,\r
+                                      Version,\r
+                                      Dependencies,\r
+                                      DependenciesSize,\r
+                                      &LocalLastAttemptStatus\r
+                                      );\r
   if (!Private->DependenciesSatisfied) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency check failed.\n", mImageIdName));\r
     *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
     Status = EFI_SUCCESS;\r
+    *LastAttemptStatus = LocalLastAttemptStatus;\r
     goto cleanup;\r
   }\r
 \r
@@ -1181,7 +1206,7 @@ SetTheImage (
   //\r
   // Get the dependency from Image.\r
   //\r
-  Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize);\r
+  Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize, &LastAttemptStatus);\r
 \r
   //\r
   // No functional error in CheckTheImage.  Attempt to get the Version to\r
index ec380c4947bda61f6313c200819ca49006f09214..785bda9401e6bea2545b38a3367f5b1b73ff04d7 100644 (file)
@@ -2,6 +2,7 @@
   Fmp Capsule Dependency check functions for Firmware Management Protocol based\r
   firmware updates.\r
 \r
+  Copyright (c) Microsoft Corporation.<BR>\r
   Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
 \r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
   @param[in]  Version            New version.\r
   @param[in]  Dependencies       Fmp dependency.\r
   @param[in]  DependenciesSize   Size, in bytes, of the Fmp dependency.\r
+  @param[out] LastAttemptStatus  An optional pointer to a UINT32 that holds the\r
+                                 last attempt status to report back to the caller.\r
+                                 This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS\r
+                                 if an error code is not set.\r
 \r
   @retval  TRUE    Dependencies are satisfied.\r
   @retval  FALSE   Dependencies are unsatisfied or dependency check fails.\r
@@ -32,7 +37,8 @@ CheckFmpDependency (
   IN  EFI_GUID                ImageTypeId,\r
   IN  UINT32                  Version,\r
   IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL\r
-  IN  UINT32                  DependenciesSize\r
+  IN  UINT32                  DependenciesSize,\r
+  OUT UINT32                  *LastAttemptStatus OPTIONAL\r
   );\r
 \r
 #endif\r
index c732903425b4c57d9a21ab61797416c6c4090160..f460f0f07882a6dba0093c22900c4ca8f14a8a1e 100644 (file)
@@ -26,9 +26,13 @@ typedef struct {
 /**\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
+  @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
+  @param[out]  LastAttemptStatus  An optional pointer to a UINT32 that holds the\r
+                                  last attempt status to report back to the caller.\r
+                                  If a last attempt status error code is not returned,\r
+                                  this function will not modify the LastAttemptStatus value.\r
 \r
   @retval TRUE    The dependency expression is valid.\r
   @retval FALSE   The dependency expression is invalid.\r
@@ -39,16 +43,20 @@ EFIAPI
 ValidateDependency (\r
   IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,\r
   IN  UINTN                   MaxDepexSize,\r
-  OUT UINT32                  *DepexSize\r
+  OUT UINT32                  *DepexSize,\r
+  OUT UINT32                  *LastAttemptStatus OPTIONAL\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
+  @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
+  @param[out] LastAttemptStatus   An optional pointer to a UINT32 that holds the\r
+                                  last attempt status to report back to the caller.\r
+                                  If a last attempt status error code is not returned,\r
+                                  this function will not modify the LastAttemptStatus value.\r
   @retval  The pointer to dependency.\r
   @retval  Null\r
 \r
@@ -56,9 +64,10 @@ ValidateDependency (
 EFI_FIRMWARE_IMAGE_DEP*\r
 EFIAPI\r
 GetImageDependency (\r
-  IN  EFI_FIRMWARE_IMAGE_AUTHENTICATION  *Image,\r
-  IN  UINTN                              ImageSize,\r
-  OUT UINT32                             *DepexSize\r
+  IN  EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,\r
+  IN  UINTN                             ImageSize,\r
+  OUT UINT32                            *DepexSize,\r
+  OUT UINT32                            *LastAttemptStatus  OPTIONAL\r
   );\r
 \r
 /**\r
@@ -73,6 +82,10 @@ GetImageDependency (
                                   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
+  @param[out]  LastAttemptStatus  An optional pointer to a UINT32 that holds the\r
+                                  last attempt status to report back to the caller.\r
+                                  This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS\r
+                                  if an error code is not set.\r
 \r
   @retval TRUE    Dependency expressions evaluate to TRUE.\r
   @retval FALSE   Dependency expressions evaluate to FALSE.\r
@@ -81,10 +94,11 @@ GetImageDependency (
 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
+  IN  EFI_FIRMWARE_IMAGE_DEP        *Dependencies,\r
+  IN  UINTN                         DependenciesSize,\r
+  IN  FMP_DEPEX_CHECK_VERSION_DATA  *FmpVersions,      OPTIONAL\r
+  IN  UINTN                         FmpVersionsCount,\r
+  OUT UINT32                        *LastAttemptStatus OPTIONAL\r
   );\r
 \r
 #endif\r
index 02ed600e0e95617ab570bf53e2b3067034930c56..cca83dbe4a149e1a7ce19523f104e7e1d1774341 100644 (file)
@@ -17,6 +17,9 @@
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
+#include <Guid/SystemResourceTable.h>\r
+#include <LastAttemptStatus.h>\r
+#include <FmpLastAttemptStatus.h>\r
 \r
 /**\r
   Check dependency for firmware update.\r
   @param[in]  Version            New version.\r
   @param[in]  Dependencies       Fmp dependency.\r
   @param[in]  DependenciesSize   Size, in bytes, of the Fmp dependency.\r
+  @param[out] LastAttemptStatus  An optional pointer to a UINT32 that holds the\r
+                                 last attempt status to report back to the caller.\r
+                                 This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS\r
+                                 if an error code is not set.\r
 \r
   @retval  TRUE    Dependencies are satisfied.\r
   @retval  FALSE   Dependencies are unsatisfied or dependency check fails.\r
@@ -36,7 +43,8 @@ CheckFmpDependency (
   IN  EFI_GUID                ImageTypeId,\r
   IN  UINT32                  Version,\r
   IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL\r
-  IN  UINT32                  DependenciesSize\r
+  IN  UINT32                  DependenciesSize,\r
+  OUT UINT32                  *LastAttemptStatus OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                        Status;\r
@@ -44,6 +52,7 @@ CheckFmpDependency (
   UINTN                             Index;\r
   EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;\r
   UINTN                             ImageInfoSize;\r
+  UINT32                            LocalLastAttemptStatus;\r
   UINT32                            *DescriptorVer;\r
   UINT8                             FmpImageInfoCount;\r
   UINTN                             *DescriptorSize;\r
@@ -55,14 +64,15 @@ CheckFmpDependency (
   UINTN                             FmpVersionsCount;\r
   BOOLEAN                           IsSatisfied;\r
 \r
-  FmpImageInfoBuf     = NULL;\r
-  DescriptorVer       = NULL;\r
-  DescriptorSize      = NULL;\r
-  NumberOfFmpInstance = 0;\r
-  FmpVersions         = NULL;\r
-  FmpVersionsCount    = 0;\r
-  IsSatisfied         = TRUE;\r
-  PackageVersionName  = NULL;\r
+  LocalLastAttemptStatus  = LAST_ATTEMPT_STATUS_SUCCESS;\r
+  FmpImageInfoBuf         = NULL;\r
+  DescriptorVer           = NULL;\r
+  DescriptorSize          = NULL;\r
+  NumberOfFmpInstance     = 0;\r
+  FmpVersions             = NULL;\r
+  FmpVersionsCount        = 0;\r
+  IsSatisfied             = TRUE;\r
+  PackageVersionName      = NULL;\r
 \r
   //\r
   // Get ImageDescriptors of all FMP instances, and archive them for dependency evaluation.\r
@@ -77,30 +87,35 @@ CheckFmpDependency (
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "CheckFmpDependency: Get Firmware Management Protocol failed. (%r)", Status));\r
     IsSatisfied = FALSE;\r
+    LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_FMP_PROTOCOL_NOT_FOUND;\r
     goto cleanup;\r
   }\r
 \r
   FmpImageInfoBuf = AllocateZeroPool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * NumberOfFmpInstance);\r
   if (FmpImageInfoBuf == NULL) {\r
     IsSatisfied = FALSE;\r
+    LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_FMP_INFO_BUFFER_FAILED;\r
     goto cleanup;\r
   }\r
 \r
   DescriptorVer = AllocateZeroPool (sizeof(UINT32) * NumberOfFmpInstance);\r
   if (DescriptorVer == NULL ) {\r
     IsSatisfied = FALSE;\r
+    LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_DESC_VER_BUFFER_FAILED;\r
     goto cleanup;\r
   }\r
 \r
   DescriptorSize = AllocateZeroPool (sizeof(UINTN) * NumberOfFmpInstance);\r
   if (DescriptorSize == NULL ) {\r
     IsSatisfied = FALSE;\r
+    LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_DESC_SIZE_BUFFER_FAILED;\r
     goto cleanup;\r
   }\r
 \r
   FmpVersions = AllocateZeroPool (sizeof(FMP_DEPEX_CHECK_VERSION_DATA) * NumberOfFmpInstance);\r
   if (FmpVersions == NULL) {\r
     IsSatisfied = FALSE;\r
+    LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_FMP_VER_BUFFER_FAILED;\r
     goto cleanup;\r
   }\r
 \r
@@ -164,7 +179,7 @@ CheckFmpDependency (
   // Evaluate firmware image's depex, against the version of other Fmp instances.\r
   //\r
   if (Dependencies != NULL) {\r
-    IsSatisfied = EvaluateDependency (Dependencies, DependenciesSize, FmpVersions, FmpVersionsCount);\r
+    IsSatisfied = EvaluateDependency (Dependencies, DependenciesSize, FmpVersions, FmpVersionsCount, &LocalLastAttemptStatus);\r
   }\r
 \r
   if (!IsSatisfied) {\r
@@ -194,5 +209,9 @@ cleanup:
     FreePool (FmpVersions);\r
   }\r
 \r
+  if (LastAttemptStatus != NULL) {\r
+    *LastAttemptStatus = LocalLastAttemptStatus;\r
+  }\r
+\r
   return IsSatisfied;\r
 }\r
index 55e9af22909d3f57af04cd2ce90a51f462ac33cb..74247957ac4f8fcf9702172698f3365e50ee80c5 100644 (file)
@@ -2,11 +2,13 @@
   Null instance of FmpDependencyCheckLib.\r
 \r
   Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) Microsoft Corporation.<BR>\r
 \r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 #include <PiDxe.h>\r
+#include <Guid/SystemResourceTable.h>\r
 #include <Library/FmpDependencyCheckLib.h>\r
 \r
 /**\r
   @param[in]  Version            New version.\r
   @param[in]  Dependencies       Fmp dependency.\r
   @param[in]  DependenciesSize   Size, in bytes, of the Fmp dependency.\r
-\r
+  @param[out] LastAttemptStatus  An optional pointer to a UINT32 that holds the\r
+                                 last attempt status to report back to the caller.\r
+                                 This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS\r
+                                 if an error code is not set.\r
   @retval  TRUE    Dependencies are satisfied.\r
   @retval  FALSE   Dependencies are unsatisfied or dependency check fails.\r
 \r
@@ -27,8 +32,13 @@ CheckFmpDependency (
   IN  EFI_GUID                ImageTypeId,\r
   IN  UINT32                  Version,\r
   IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,    OPTIONAL\r
-  IN  UINT32                  DependenciesSize\r
+  IN  UINT32                  DependenciesSize,\r
+  OUT UINT32                  *LastAttemptStatus OPTIONAL\r
   )\r
 {\r
+  if (LastAttemptStatus != NULL) {\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+  }\r
+\r
   return TRUE;\r
 }\r
index 5ef25d2415cf5c59910d1cab6922406aea19c99d..b222ace6d6ca20d90a495bbda90769b39ecbe3e6 100644 (file)
@@ -13,6 +13,9 @@
 #include <Library/DebugLib.h>\r
 #include <Library/FmpDependencyLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Guid/SystemResourceTable.h>\r
+#include <LastAttemptStatus.h>\r
+#include <FmpLastAttemptStatus.h>\r
 \r
 //\r
 // Define the initial size of the dependency expression evaluation stack\r
@@ -203,6 +206,10 @@ Pop (
                                   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
+  @param[out]  LastAttemptStatus  An optional pointer to a UINT32 that holds the\r
+                                  last attempt status to report back to the caller.\r
+                                  This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS\r
+                                  if an error code is not set.\r
 \r
   @retval TRUE    Dependency expressions evaluate to TRUE.\r
   @retval FALSE   Dependency expressions evaluate to FALSE.\r
@@ -211,10 +218,11 @@ Pop (
 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
+  IN  EFI_FIRMWARE_IMAGE_DEP        *Dependencies,\r
+  IN  UINTN                         DependenciesSize,\r
+  IN  FMP_DEPEX_CHECK_VERSION_DATA  *FmpVersions,      OPTIONAL\r
+  IN  UINTN                         FmpVersionsCount,\r
+  OUT UINT32                        *LastAttemptStatus OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                        Status;\r
@@ -224,6 +232,9 @@ EvaluateDependency (
   DEPEX_ELEMENT                     Element2;\r
   GUID                              ImageTypeId;\r
   UINT32                            Version;\r
+  UINT32                            LocalLastAttemptStatus;\r
+\r
+  LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
 \r
   //\r
   // Check if parameter is valid.\r
@@ -249,6 +260,7 @@ EvaluateDependency (
     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
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GUID_BEYOND_DEPEX;\r
         goto Error;\r
       }\r
 \r
@@ -259,6 +271,7 @@ EvaluateDependency (
         if(CompareGuid (&FmpVersions[Index].ImageTypeId, &ImageTypeId)){\r
           Status = Push (FmpVersions[Index].Version, VersionType);\r
           if (EFI_ERROR (Status)) {\r
+            LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
             goto Error;\r
           }\r
           break;\r
@@ -266,18 +279,21 @@ EvaluateDependency (
       }\r
       if (Index == FmpVersionsCount) {\r
         DEBUG ((DEBUG_ERROR, "EvaluateDependency: %g is not found!\n", &ImageTypeId));\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_FMP_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
         DEBUG ((DEBUG_ERROR, "EvaluateDependency: VERSION extends beyond end of dependency expression!\n"));\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_VERSION_BEYOND_DEPEX;\r
         goto Error;\r
       }\r
 \r
       Version = *(UINT32 *) (Iterator + 1);\r
       Status = Push (Version, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       Iterator = Iterator + sizeof (UINT32);\r
@@ -286,154 +302,191 @@ EvaluateDependency (
       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
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_VERSION_STR_BEYOND_DEPEX;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_AND:\r
       Status = Pop (&Element1, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Pop (&Element2, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Push (Element1.Value.Boolean & Element2.Value.Boolean, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_OR:\r
       Status = Pop (&Element1, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Pop(&Element2, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Push (Element1.Value.Boolean | Element2.Value.Boolean, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_NOT:\r
       Status = Pop (&Element1, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Push (!(Element1.Value.Boolean), BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_TRUE:\r
       Status = Push (TRUE, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_FALSE:\r
       Status = Push (FALSE, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_EQ:\r
       Status = Pop (&Element1, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Pop (&Element2, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = (Element1.Value.Version == Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_GT:\r
       Status = Pop (&Element1, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Pop (&Element2, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = (Element1.Value.Version >  Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_GTE:\r
       Status = Pop (&Element1, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Pop (&Element2, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = (Element1.Value.Version >= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_LT:\r
       Status = Pop (&Element1, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Pop (&Element2, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus= LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = (Element1.Value.Version <  Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_LTE:\r
       Status = Pop (&Element1, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = Pop (&Element2, VersionType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       Status = (Element1.Value.Version <= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;\r
         goto Error;\r
       }\r
       break;\r
     case EFI_FMP_DEP_END:\r
       Status = Pop (&Element1, BooleanType);\r
       if (EFI_ERROR (Status)) {\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;\r
         goto Error;\r
       }\r
       return Element1.Value.Boolean;\r
     default:\r
       DEBUG ((DEBUG_ERROR, "EvaluateDependency: Unknown Opcode - %02x!\n", *Iterator));\r
+      LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_UNKNOWN_OPCODE;\r
       goto Error;\r
     }\r
     Iterator++;\r
   }\r
 \r
   DEBUG ((DEBUG_ERROR, "EvaluateDependency: No EFI_FMP_DEP_END Opcode in expression!\n"));\r
+  LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_NO_END_OPCODE;\r
 \r
 Error:\r
+  if (LastAttemptStatus != NULL) {\r
+    *LastAttemptStatus = LocalLastAttemptStatus;\r
+  }\r
+\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
+  @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
+  @param[out]  LastAttemptStatus  An optional pointer to a UINT32 that holds the\r
+                                  last attempt status to report back to the caller.\r
+                                  If a last attempt status error code is not returned,\r
+                                  this function will not modify the LastAttemptStatus value.\r
 \r
   @retval TRUE    The dependency expression is valid.\r
   @retval FALSE   The dependency expression is invalid.\r
@@ -444,7 +497,8 @@ EFIAPI
 ValidateDependency (\r
   IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,\r
   IN  UINTN                   MaxDepexSize,\r
-  OUT UINT32                  *DepexSize\r
+  OUT UINT32                  *DepexSize,\r
+  OUT UINT32                  *LastAttemptStatus OPTIONAL\r
   )\r
 {\r
   UINT8  *Depex;\r
@@ -493,16 +547,23 @@ ValidateDependency (
     }\r
   }\r
 \r
+  if (LastAttemptStatus != NULL) {\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_NO_END_OPCODE;\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
+  @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
+  @param[out] LastAttemptStatus   An optional pointer to a UINT32 that holds the\r
+                                  last attempt status to report back to the caller.\r
+                                  If a last attempt status error code is not returned,\r
+                                  this function will not modify the LastAttemptStatus value.\r
   @retval  The pointer to dependency.\r
   @retval  Null\r
 \r
@@ -512,7 +573,8 @@ EFIAPI
 GetImageDependency (\r
   IN  EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,\r
   IN  UINTN                             ImageSize,\r
-  OUT UINT32                            *DepexSize\r
+  OUT UINT32                            *DepexSize,\r
+  OUT UINT32                            *LastAttemptStatus  OPTIONAL\r
   )\r
 {\r
   EFI_FIRMWARE_IMAGE_DEP *Depex;\r
@@ -530,6 +592,9 @@ GetImageDependency (
     //\r
     // Pointer overflow. Invalid image.\r
     //\r
+    if (LastAttemptStatus != NULL) {\r
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GET_DEPEX_FAILURE;\r
+    }\r
     return NULL;\r
   }\r
 \r
@@ -539,7 +604,7 @@ GetImageDependency (
   //\r
   // Validate the dependency and get the size of dependency\r
   //\r
-  if (ValidateDependency (Depex, MaxDepexSize, DepexSize)) {\r
+  if (ValidateDependency (Depex, MaxDepexSize, DepexSize, LastAttemptStatus)) {\r
     return Depex;\r
   }\r
 \r
index f8ccdd906f29da1c6c7ff5b8d33aad735cf329a0..01ac19a7d5d7e2b4fda30c7bdad1f83562f7001e 100644 (file)
@@ -2,6 +2,7 @@
   Unit tests of EvaluateDependency API in FmpDependencyLib.\r
 \r
   Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) Microsoft Corporation.<BR>\r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
@@ -162,6 +163,7 @@ EvaluateDependencyTest (
 {\r
   BASIC_TEST_CONTEXT  *TestContext;\r
   BOOLEAN             EvaluationResult;\r
+  UINT32              LastAttemptStatus;\r
 \r
   TestContext = (BASIC_TEST_CONTEXT *)Context;\r
 \r
@@ -169,8 +171,9 @@ EvaluateDependencyTest (
                        (EFI_FIRMWARE_IMAGE_DEP *)TestContext->Dependencies,\r
                        TestContext->DependenciesSize,\r
                        mFmpVersions,\r
-                       sizeof(mFmpVersions)/sizeof(FMP_DEPEX_CHECK_VERSION_DATA)\r
-                     );\r
+                       sizeof(mFmpVersions)/sizeof(FMP_DEPEX_CHECK_VERSION_DATA),\r
+                       &LastAttemptStatus\r
+                       );\r
 \r
   UT_ASSERT_EQUAL (EvaluationResult, TestContext->ExpectedResult);\r
 \r