public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
@ 2020-10-01 21:58 Michael Kubacki
  2020-10-29  1:12 ` Michael D Kinney
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Kubacki @ 2020-10-01 21:58 UTC (permalink / raw)
  To: devel; +Cc: Michael D Kinney, Yi Qian, Zailiang Sun

From: Michael Kubacki <michael.kubacki@microsoft.com>

Makes the changes necessary for these library instances of
FmpDeviceLib to be compatible with new functions added recently
to FmpDeviceLib.

Two new functions were introduced in FmpDeviceLib to allow a
library instance to return a Last Attempt Status code during
check image and set image operations:
  1. FmpDeviceCheckImageWithStatus ( )
  2. FmpDeviceSetImageWithStatus ( )

FmpDxe (in FmpDevicePkg) will begin calling these new functions
instead of the previous functions. Therefore, this change:
  1. Adds these functions to Vlv2TbltDevicePkg implementations
  2. Moves the main functionality to these new functions
  3. Updates the old functions to call the new functions
     (for backward compatibility)

Note: As of this commit, the Vlv2TbltDevicePkg build is broken
due to:
  1. A required RngLib library instance not defined by the platform
  2. Other FMP libraries not being defined by the platform
     (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)

Those changes were fixed locally to test the changes in this commit
but maintainers should make the proper changes for those issues.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Yi Qian <yi.qian@intel.com>
Cc: Zailiang Sun <zailiang.sun@intel.com>
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
---

Notes:
    Only build was checked, I do not have access to a
    VLV2 device for testing.

 Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       | 299 +++++++++++++++-----
 Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c | 284 ++++++++++++++-----
 2 files changed, 446 insertions(+), 137 deletions(-)

diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
index d8c9036012ad..df8a36d9854c 100644
--- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
+++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
@@ -1,6 +1,6 @@
 /**
 
-Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
+Copyright (c) Microsoft Corporation.<BR>
 Copyright (c) 2019, Intel Corporation.  All rights reserved.
 
 SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include <PiDxe.h>
-
+#include <LastAttemptStatus.h>
+#include <Guid/SystemResourceTable.h>
 #include <Library/FmpDeviceLib.h>
 
 #include <Library/DebugLib.h>
@@ -444,20 +445,17 @@ FmpDeviceGetImage (
 }
 
 /**
-  Updates the firmware image of the device.
-
-  This function updates the hardware with the new firmware image.  This function
-  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
-  firmware image is updatable, the function should perform the following minimal
-  validations before proceeding to do the firmware image update.
-    - Validate the image is a supported image for this device.  The function
-      returns EFI_ABORTED if the image is unsupported.  The function can
-      optionally provide more detailed information on why the image is not a
-      supported image.
-    - Validate the data from VendorCode if not null.  Image validation must be
-      performed before VendorCode data validation.  VendorCode data is ignored
-      or considered invalid if image validation failed.  The function returns
-      EFI_ABORTED if the data is invalid.
+  Updates a firmware device with a new firmware image.  This function returns
+  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
+  is updatable, the function should perform the following minimal validations
+  before proceeding to do the firmware image update.
+    - Validate that the image is a supported image for this firmware device.
+      Return EFI_ABORTED if the image is not supported.  Additional details
+      on why the image is not a supported image may be returned in AbortReason.
+    - Validate the data from VendorCode if is not NULL.  Firmware image
+      validation must be performed before VendorCode data validation.
+      VendorCode data is ignored or considered invalid if image validation
+      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
 
   VendorCode enables vendor to implement vendor-specific firmware image update
   policy.  Null if the caller did not specify the policy or use the default
@@ -470,38 +468,56 @@ FmpDeviceGetImage (
   have the option to provide a more detailed description of the abort reason to
   the caller.
 
-  @param[in]  Image             Points to the new image.
-  @param[in]  ImageSize         Size of the new image in bytes.
+  @param[in]  Image             Points to the new firmware image.
+  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
   @param[in]  VendorCode        This enables vendor to implement vendor-specific
-                                firmware image update policy. Null indicates the
-                                caller did not specify the policy or use the
+                                firmware image update policy.  NULL indicates
+                                the caller did not specify the policy or use the
                                 default policy.
-  @param[in]  Progress          A function used by the driver to report the
-                                progress of the firmware update.
-  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
-  @param[out] AbortReason       A pointer to a pointer to a null-terminated
-                                string providing more details for the aborted
-                                operation. The buffer is allocated by this
-                                function with AllocatePool(), and it is the
-                                caller's responsibility to free it with a call
-                                to FreePool().
+  @param[in]  Progress          A function used to report the progress of
+                                updating the firmware device with the new
+                                firmware image.
+  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
+                                update capsule that provided the new firmware
+                                image.
+  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
+                                Unicode string providing more details on an
+                                aborted operation. The buffer is allocated by
+                                this function with
+                                EFI_BOOT_SERVICES.AllocatePool().  It is the
+                                caller's responsibility to free this buffer with
+                                EFI_BOOT_SERVICES.FreePool().
+  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
+                                status to report back to the ESRT table in case
+                                of error. This value will only be checked when this
+                                function returns an error.
 
-  @retval EFI_SUCCESS            The device was successfully updated with the
-                                 new image.
-  @retval EFI_ABORTED            The operation is aborted.
+                                The return status code must fall in the range of
+                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
+                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
+
+                                If the value falls outside this range, it will be converted
+                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
+
+  @retval EFI_SUCCESS            The firmware device was successfully updated
+                                 with the new firmware image.
+  @retval EFI_ABORTED            The operation is aborted.  Additional details
+                                 are provided in AbortReason.
   @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
   @retval EFI_UNSUPPORTED        The operation is not supported.
 
 **/
 EFI_STATUS
 EFIAPI
-FmpDeviceSetImage (
+FmpDeviceSetImageWithStatus (
   IN  CONST VOID                                     *Image,
   IN  UINTN                                          ImageSize,
-  IN  CONST VOID                                     *VendorCode,
-  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
+  IN  CONST VOID                                     *VendorCode,       OPTIONAL
+  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
   IN  UINT32                                         CapsuleFwVersion,
-  OUT CHAR16                                         **AbortReason
+  OUT CHAR16                                         **AbortReason,
+  OUT UINT32                                         *LastAttemptStatus
   )
 {
   EFI_STATUS          Status;
@@ -513,25 +529,27 @@ FmpDeviceSetImage (
   UINTN               BytesWritten;
 
   Updateable = 0;
-  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
+  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
   if (EFI_ERROR (Status)) {
-    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with %r.\n", Status));
+    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image failed with %r.\n", Status));
     return Status;
   }
 
   if (Updateable != IMAGE_UPDATABLE_VALID) {
-    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n", Updateable));
+    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n", Updateable));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
     return EFI_ABORTED;
   }
 
   if (Progress == NULL) {
-    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress callback\n"));
+    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
     return EFI_INVALID_PARAMETER;
   }
 
   Status = Progress (15);
   if (EFI_ERROR (Status)) {
-    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
+    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
   }
 
   //
@@ -539,7 +557,7 @@ FmpDeviceSetImage (
   //
   Progress (20);
   if (EFI_ERROR (Status)) {
-    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
+    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
   }
 
   //
@@ -553,11 +571,11 @@ FmpDeviceSetImage (
 
 //    Progress (Percentage);
 //    if (EFI_ERROR (Status)) {
-//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
+//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
 //    }
   }
 
-  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
+  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
 
   if (ARRAY_SIZE (mUpdateConfigData) == 0) {
     DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
@@ -605,11 +623,173 @@ FmpDeviceSetImage (
     BytesWritten += ConfigData->Length;
   }
 
-  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
+  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
+
+  if (EFI_ERROR (Status)) {
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+  }
 
   return Status;
 }
 
+/**
+  Updates the firmware image of the device.
+
+  This function updates the hardware with the new firmware image.  This function
+  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
+  firmware image is updatable, the function should perform the following minimal
+  validations before proceeding to do the firmware image update.
+    - Validate the image is a supported image for this device.  The function
+      returns EFI_ABORTED if the image is unsupported.  The function can
+      optionally provide more detailed information on why the image is not a
+      supported image.
+    - Validate the data from VendorCode if not null.  Image validation must be
+      performed before VendorCode data validation.  VendorCode data is ignored
+      or considered invalid if image validation failed.  The function returns
+      EFI_ABORTED if the data is invalid.
+
+  VendorCode enables vendor to implement vendor-specific firmware image update
+  policy.  Null if the caller did not specify the policy or use the default
+  policy.  As an example, vendor can implement a policy to allow an option to
+  force a firmware image update when the abort reason is due to the new firmware
+  image version is older than the current firmware image version or bad image
+  checksum.  Sensitive operations such as those wiping the entire firmware image
+  and render the device to be non-functional should be encoded in the image
+  itself rather than passed with the VendorCode.  AbortReason enables vendor to
+  have the option to provide a more detailed description of the abort reason to
+  the caller.
+
+  @param[in]  Image             Points to the new image.
+  @param[in]  ImageSize         Size of the new image in bytes.
+  @param[in]  VendorCode        This enables vendor to implement vendor-specific
+                                firmware image update policy. Null indicates the
+                                caller did not specify the policy or use the
+                                default policy.
+  @param[in]  Progress          A function used by the driver to report the
+                                progress of the firmware update.
+  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
+  @param[out] AbortReason       A pointer to a pointer to a null-terminated
+                                string providing more details for the aborted
+                                operation. The buffer is allocated by this
+                                function with AllocatePool(), and it is the
+                                caller's responsibility to free it with a call
+                                to FreePool().
+
+  @retval EFI_SUCCESS            The device was successfully updated with the
+                                 new image.
+  @retval EFI_ABORTED            The operation is aborted.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceSetImage (
+  IN  CONST VOID                                     *Image,
+  IN  UINTN                                          ImageSize,
+  IN  CONST VOID                                     *VendorCode,
+  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
+  IN  UINT32                                         CapsuleFwVersion,
+  OUT CHAR16                                         **AbortReason
+  )
+{
+  UINT32  LastAttemptStatus;
+
+  return  FmpDeviceSetImageWithStatus (
+            Image,
+            ImageSize,
+            VendorCode,
+            Progress,
+            CapsuleFwVersion,
+            AbortReason,
+            &LastAttemptStatus
+            );
+}
+
+/**
+  Checks if a new firmware image is valid for the firmware device.  This
+  function allows firmware update operation to validate the firmware image
+  before FmpDeviceSetImage() is called.
+
+  @param[in]  Image               Points to a new firmware image.
+  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
+  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
+                                  a firmware update to the firmware device.  The
+                                  following values from the Firmware Management
+                                  Protocol are supported:
+                                    IMAGE_UPDATABLE_VALID
+                                    IMAGE_UPDATABLE_INVALID
+                                    IMAGE_UPDATABLE_INVALID_TYPE
+                                    IMAGE_UPDATABLE_INVALID_OLD
+                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
+  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
+                                  status to report back to the ESRT table in case
+                                  of error. This value will only be checked when this
+                                  function returns an error.
+
+                                  The return status code must fall in the range of
+                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
+                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
+
+                                  If the value falls outside this range, it will be converted
+                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
+
+  @retval EFI_SUCCESS            The image was successfully checked.  Additional
+                                 status information is returned in
+                                 ImageUpdatable.
+  @retval EFI_INVALID_PARAMETER  Image is NULL.
+  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
+  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceCheckImageWithStatus (
+  IN  CONST VOID  *Image,
+  IN  UINTN       ImageSize,
+  OUT UINT32      *ImageUpdatable,
+  OUT UINT32      *LastAttemptStatus
+  )
+{
+  if (LastAttemptStatus == NULL) {
+    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+
+  if (ImageUpdatable == NULL) {
+    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  //Set to valid and then if any tests fail it will update this flag.
+  //
+  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
+
+  if (Image == NULL) {
+    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
+    //
+    // Not sure if this is needed
+    //
+    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Make sure the image size is correct
+  //
+  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
+    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
 /**
 Checks if the firmware image is valid for the device.
 
@@ -633,34 +813,9 @@ FmpDeviceCheckImage (
   OUT UINT32      *ImageUpdateable
   )
 {
-  if (ImageUpdateable == NULL) {
-    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
-    return EFI_INVALID_PARAMETER;
-  }
+  UINT32  LastAttemptStatus;
 
-  //
-  //Set to valid and then if any tests fail it will update this flag.
-  //
-  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
-
-  if (Image == NULL) {
-    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
-    //
-    // Not sure if this is needed
-    //
-    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Make sure the image size is correct
-  //
-  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
-    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
-    return EFI_INVALID_PARAMETER;
-  }
-
-  return EFI_SUCCESS;
+  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
 }
 
 /**
diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
index db0f238ea534..132b60844ad4 100644
--- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
+++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
@@ -1,6 +1,6 @@
 /**
 
-Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
 
 SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 
 #include <PiDxe.h>
+#include <LastAttemptStatus.h>
+#include <Guid/SystemResourceTable.h>
 #include <Library/DebugLib.h>
 #include <Protocol/FirmwareManagement.h>
 #include <Library/BaseLib.h>
@@ -345,6 +347,131 @@ Return Value:
 }//GetImage()
 
 
+/**
+  Updates a firmware device with a new firmware image.  This function returns
+  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
+  is updatable, the function should perform the following minimal validations
+  before proceeding to do the firmware image update.
+    - Validate that the image is a supported image for this firmware device.
+      Return EFI_ABORTED if the image is not supported.  Additional details
+      on why the image is not a supported image may be returned in AbortReason.
+    - Validate the data from VendorCode if is not NULL.  Firmware image
+      validation must be performed before VendorCode data validation.
+      VendorCode data is ignored or considered invalid if image validation
+      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
+
+  VendorCode enables vendor to implement vendor-specific firmware image update
+  policy.  Null if the caller did not specify the policy or use the default
+  policy.  As an example, vendor can implement a policy to allow an option to
+  force a firmware image update when the abort reason is due to the new firmware
+  image version is older than the current firmware image version or bad image
+  checksum.  Sensitive operations such as those wiping the entire firmware image
+  and render the device to be non-functional should be encoded in the image
+  itself rather than passed with the VendorCode.  AbortReason enables vendor to
+  have the option to provide a more detailed description of the abort reason to
+  the caller.
+
+  @param[in]  Image             Points to the new firmware image.
+  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
+  @param[in]  VendorCode        This enables vendor to implement vendor-specific
+                                firmware image update policy.  NULL indicates
+                                the caller did not specify the policy or use the
+                                default policy.
+  @param[in]  Progress          A function used to report the progress of
+                                updating the firmware device with the new
+                                firmware image.
+  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
+                                update capsule that provided the new firmware
+                                image.
+  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
+                                Unicode string providing more details on an
+                                aborted operation. The buffer is allocated by
+                                this function with
+                                EFI_BOOT_SERVICES.AllocatePool().  It is the
+                                caller's responsibility to free this buffer with
+                                EFI_BOOT_SERVICES.FreePool().
+  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
+                                status to report back to the ESRT table in case
+                                of error. This value will only be checked when this
+                                function returns an error.
+
+                                The return status code must fall in the range of
+                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
+                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
+
+                                If the value falls outside this range, it will be converted
+                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
+
+  @retval EFI_SUCCESS            The firmware device was successfully updated
+                                 with the new firmware image.
+  @retval EFI_ABORTED            The operation is aborted.  Additional details
+                                 are provided in AbortReason.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceSetImageWithStatus (
+  IN  CONST VOID                                     *Image,
+  IN  UINTN                                          ImageSize,
+  IN  CONST VOID                                     *VendorCode,       OPTIONAL
+  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
+  IN  UINT32                                         CapsuleFwVersion,
+  OUT CHAR16                                         **AbortReason,
+  OUT UINT32                                         *LastAttemptStatus
+  )
+{
+    EFI_STATUS Status                         = EFI_SUCCESS;
+    UINT32 Updateable                         = 0;
+
+    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
+    if (EFI_ERROR(Status))
+    {
+        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed with %r.\n", Status));
+        goto cleanup;
+    }
+
+    if (Updateable != IMAGE_UPDATABLE_VALID)
+    {
+        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n", Updateable));
+        Status = EFI_ABORTED;
+        goto cleanup;
+    }
+
+    if (Progress == NULL)
+    {
+        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress callback\n"));
+        Status = EFI_INVALID_PARAMETER;
+        goto cleanup;
+    }
+
+    Status = Progress(15);
+    if (EFI_ERROR(Status))
+    {
+        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback failed with Status %r.\n", Status));
+    }
+
+    {
+      UINTN  p;
+
+      for (p = 20; p < 100; p++) {
+        gBS->Stall (100000);  //us  = 0.1 seconds
+        Progress (p);
+      }
+    }
+
+    //TODO: add support for VendorCode, and AbortReason
+cleanup:
+    if (EFI_ERROR (Status)) {
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+    }
+
+    return Status;
+}// SetImageWithStatus()
+
+
 /**
 Updates the firmware image of the device.
 
@@ -396,51 +523,98 @@ IN  UINT32                                           CapsuleFwVersion,
 OUT CHAR16                                           **AbortReason
 )
 {
-    EFI_STATUS Status                         = EFI_SUCCESS;
-    UINT32 Updateable                         = 0;
-
-    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
-    if (EFI_ERROR(Status))
-    {
-        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with %r.\n", Status));
-        goto cleanup;
-    }
-
-    if (Updateable != IMAGE_UPDATABLE_VALID)
-    {
-        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n", Updateable));
-        Status = EFI_ABORTED;
-        goto cleanup;
-    }
-
-    if (Progress == NULL)
-    {
-        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
-        Status = EFI_INVALID_PARAMETER;
-        goto cleanup;
-    }
-
-    Status = Progress(15);
-    if (EFI_ERROR(Status))
-    {
-        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with Status %r.\n", Status));
-    }
-
-    {
-      UINTN  p;
-
-      for (p = 20; p < 100; p++) {
-        gBS->Stall (100000);  //us  = 0.1 seconds
-        Progress (p);
-      }
-    }
-
-    //TODO: add support for VendorCode, and AbortReason
-cleanup:
-    return Status;
+  UINT32  LastAttemptStatus;
+
+  return  FmpDeviceSetImageWithStatus (
+            Image,
+            ImageSize,
+            VendorCode,
+            Progress,
+            CapsuleFwVersion,
+            AbortReason,
+            &LastAttemptStatus
+            );
 }// SetImage()
 
 
+/**
+  Checks if a new firmware image is valid for the firmware device.  This
+  function allows firmware update operation to validate the firmware image
+  before FmpDeviceSetImage() is called.
+
+  @param[in]  Image               Points to a new firmware image.
+  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
+  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
+                                  a firmware update to the firmware device.  The
+                                  following values from the Firmware Management
+                                  Protocol are supported:
+                                    IMAGE_UPDATABLE_VALID
+                                    IMAGE_UPDATABLE_INVALID
+                                    IMAGE_UPDATABLE_INVALID_TYPE
+                                    IMAGE_UPDATABLE_INVALID_OLD
+                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
+  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
+                                  status to report back to the ESRT table in case
+                                  of error. This value will only be checked when this
+                                  function returns an error.
+
+                                  The return status code must fall in the range of
+                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
+                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
+
+                                  If the value falls outside this range, it will be converted
+                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
+
+  @retval EFI_SUCCESS            The image was successfully checked.  Additional
+                                 status information is returned in
+                                 ImageUpdatable.
+  @retval EFI_INVALID_PARAMETER  Image is NULL.
+  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
+  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceCheckImageWithStatus (
+  IN  CONST VOID  *Image,
+  IN  UINTN       ImageSize,
+  OUT UINT32      *ImageUpdatable,
+  OUT UINT32      *LastAttemptStatus
+  )
+{
+    EFI_STATUS status = EFI_SUCCESS;
+
+    if (LastAttemptStatus == NULL) {
+      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
+      return EFI_INVALID_PARAMETER;
+    }
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+
+    if (ImageUpdatable == NULL)
+    {
+        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
+        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+        status = EFI_INVALID_PARAMETER;
+        goto cleanup;
+    }
+
+    //
+    //Set to valid and then if any tests fail it will update this flag.
+    //
+    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
+
+    if (Image == NULL)
+    {
+        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
+        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
+        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+        return EFI_INVALID_PARAMETER;
+    }
+
+cleanup:
+    return status;
+}// CheckImageWithStatus()
+
 
 /**
 Checks if the firmware image is valid for the device.
@@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
 OUT UINT32                            *ImageUpdateable
 )
 {
-    EFI_STATUS status = EFI_SUCCESS;
+  UINT32  LastAttemptStatus;
 
-    if (ImageUpdateable == NULL)
-    {
-        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
-        status = EFI_INVALID_PARAMETER;
-        goto cleanup;
-    }
-
-    //
-    //Set to valid and then if any tests fail it will update this flag.
-    //
-    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
-
-    if (Image == NULL)
-    {
-        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
-        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
-        return EFI_INVALID_PARAMETER;
-    }
-
-cleanup:
-    return status;
+  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
 }// CheckImage()
 
 /**
-- 
2.28.0.windows.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
       [not found] <1639FD37CA1FD9A2.6392@groups.io>
@ 2020-10-15 21:27 ` Michael Kubacki
       [not found] ` <bf090dba-75d3-520e-7414-bcdb8314562b@outlook.com>
  1 sibling, 0 replies; 10+ messages in thread
From: Michael Kubacki @ 2020-10-15 21:27 UTC (permalink / raw)
  To: devel; +Cc: Michael D Kinney, Yi Qian, Zailiang Sun

Hi,

It's been two weeks with no feedback.

A review would be appreciated.

Thanks,
Michael

On 10/1/2020 2:58 PM, Michael Kubacki wrote:
> From: Michael Kubacki <michael.kubacki@microsoft.com>
> 
> Makes the changes necessary for these library instances of
> FmpDeviceLib to be compatible with new functions added recently
> to FmpDeviceLib.
> 
> Two new functions were introduced in FmpDeviceLib to allow a
> library instance to return a Last Attempt Status code during
> check image and set image operations:
>    1. FmpDeviceCheckImageWithStatus ( )
>    2. FmpDeviceSetImageWithStatus ( )
> 
> FmpDxe (in FmpDevicePkg) will begin calling these new functions
> instead of the previous functions. Therefore, this change:
>    1. Adds these functions to Vlv2TbltDevicePkg implementations
>    2. Moves the main functionality to these new functions
>    3. Updates the old functions to call the new functions
>       (for backward compatibility)
> 
> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
> due to:
>    1. A required RngLib library instance not defined by the platform
>    2. Other FMP libraries not being defined by the platform
>       (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
> 
> Those changes were fixed locally to test the changes in this commit
> but maintainers should make the proper changes for those issues.
> 
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Yi Qian <yi.qian@intel.com>
> Cc: Zailiang Sun <zailiang.sun@intel.com>
> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
> ---
> 
> Notes:
>      Only build was checked, I do not have access to a
>      VLV2 device for testing.
> 
>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       | 299 +++++++++++++++-----
>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c | 284 ++++++++++++++-----
>   2 files changed, 446 insertions(+), 137 deletions(-)
> 
> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> index d8c9036012ad..df8a36d9854c 100644
> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> @@ -1,6 +1,6 @@
>   /**
>   
> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
> +Copyright (c) Microsoft Corporation.<BR>
>   Copyright (c) 2019, Intel Corporation.  All rights reserved.
>   
>   SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
>   
>   #include <PiDxe.h>
> -
> +#include <LastAttemptStatus.h>
> +#include <Guid/SystemResourceTable.h>
>   #include <Library/FmpDeviceLib.h>
>   
>   #include <Library/DebugLib.h>
> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
>   }
>   
>   /**
> -  Updates the firmware image of the device.
> -
> -  This function updates the hardware with the new firmware image.  This function
> -  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> -  firmware image is updatable, the function should perform the following minimal
> -  validations before proceeding to do the firmware image update.
> -    - Validate the image is a supported image for this device.  The function
> -      returns EFI_ABORTED if the image is unsupported.  The function can
> -      optionally provide more detailed information on why the image is not a
> -      supported image.
> -    - Validate the data from VendorCode if not null.  Image validation must be
> -      performed before VendorCode data validation.  VendorCode data is ignored
> -      or considered invalid if image validation failed.  The function returns
> -      EFI_ABORTED if the data is invalid.
> +  Updates a firmware device with a new firmware image.  This function returns
> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> +  is updatable, the function should perform the following minimal validations
> +  before proceeding to do the firmware image update.
> +    - Validate that the image is a supported image for this firmware device.
> +      Return EFI_ABORTED if the image is not supported.  Additional details
> +      on why the image is not a supported image may be returned in AbortReason.
> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> +      validation must be performed before VendorCode data validation.
> +      VendorCode data is ignored or considered invalid if image validation
> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>   
>     VendorCode enables vendor to implement vendor-specific firmware image update
>     policy.  Null if the caller did not specify the policy or use the default
> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
>     have the option to provide a more detailed description of the abort reason to
>     the caller.
>   
> -  @param[in]  Image             Points to the new image.
> -  @param[in]  ImageSize         Size of the new image in bytes.
> +  @param[in]  Image             Points to the new firmware image.
> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
>     @param[in]  VendorCode        This enables vendor to implement vendor-specific
> -                                firmware image update policy. Null indicates the
> -                                caller did not specify the policy or use the
> +                                firmware image update policy.  NULL indicates
> +                                the caller did not specify the policy or use the
>                                   default policy.
> -  @param[in]  Progress          A function used by the driver to report the
> -                                progress of the firmware update.
> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> -  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> -                                string providing more details for the aborted
> -                                operation. The buffer is allocated by this
> -                                function with AllocatePool(), and it is the
> -                                caller's responsibility to free it with a call
> -                                to FreePool().
> +  @param[in]  Progress          A function used to report the progress of
> +                                updating the firmware device with the new
> +                                firmware image.
> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> +                                update capsule that provided the new firmware
> +                                image.
> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> +                                Unicode string providing more details on an
> +                                aborted operation. The buffer is allocated by
> +                                this function with
> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> +                                caller's responsibility to free this buffer with
> +                                EFI_BOOT_SERVICES.FreePool().
> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> +                                status to report back to the ESRT table in case
> +                                of error. This value will only be checked when this
> +                                function returns an error.
>   
> -  @retval EFI_SUCCESS            The device was successfully updated with the
> -                                 new image.
> -  @retval EFI_ABORTED            The operation is aborted.
> +                                The return status code must fall in the range of
> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> +
> +                                If the value falls outside this range, it will be converted
> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> +
> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> +                                 with the new firmware image.
> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> +                                 are provided in AbortReason.
>     @retval EFI_INVALID_PARAMETER  The Image was NULL.
> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>     @retval EFI_UNSUPPORTED        The operation is not supported.
>   
>   **/
>   EFI_STATUS
>   EFIAPI
> -FmpDeviceSetImage (
> +FmpDeviceSetImageWithStatus (
>     IN  CONST VOID                                     *Image,
>     IN  UINTN                                          ImageSize,
> -  IN  CONST VOID                                     *VendorCode,
> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
>     IN  UINT32                                         CapsuleFwVersion,
> -  OUT CHAR16                                         **AbortReason
> +  OUT CHAR16                                         **AbortReason,
> +  OUT UINT32                                         *LastAttemptStatus
>     )
>   {
>     EFI_STATUS          Status;
> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
>     UINTN               BytesWritten;
>   
>     Updateable = 0;
> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
>     if (EFI_ERROR (Status)) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with %r.\n", Status));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image failed with %r.\n", Status));
>       return Status;
>     }
>   
>     if (Updateable != IMAGE_UPDATABLE_VALID) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n", Updateable));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n", Updateable));
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>       return EFI_ABORTED;
>     }
>   
>     if (Progress == NULL) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress callback\n"));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>       return EFI_INVALID_PARAMETER;
>     }
>   
>     Status = Progress (15);
>     if (EFI_ERROR (Status)) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>     }
>   
>     //
> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
>     //
>     Progress (20);
>     if (EFI_ERROR (Status)) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>     }
>   
>     //
> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
>   
>   //    Progress (Percentage);
>   //    if (EFI_ERROR (Status)) {
> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>   //    }
>     }
>   
> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
>   
>     if (ARRAY_SIZE (mUpdateConfigData) == 0) {
>       DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
>       BytesWritten += ConfigData->Length;
>     }
>   
> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
> +
> +  if (EFI_ERROR (Status)) {
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +  }
>   
>     return Status;
>   }
>   
> +/**
> +  Updates the firmware image of the device.
> +
> +  This function updates the hardware with the new firmware image.  This function
> +  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> +  firmware image is updatable, the function should perform the following minimal
> +  validations before proceeding to do the firmware image update.
> +    - Validate the image is a supported image for this device.  The function
> +      returns EFI_ABORTED if the image is unsupported.  The function can
> +      optionally provide more detailed information on why the image is not a
> +      supported image.
> +    - Validate the data from VendorCode if not null.  Image validation must be
> +      performed before VendorCode data validation.  VendorCode data is ignored
> +      or considered invalid if image validation failed.  The function returns
> +      EFI_ABORTED if the data is invalid.
> +
> +  VendorCode enables vendor to implement vendor-specific firmware image update
> +  policy.  Null if the caller did not specify the policy or use the default
> +  policy.  As an example, vendor can implement a policy to allow an option to
> +  force a firmware image update when the abort reason is due to the new firmware
> +  image version is older than the current firmware image version or bad image
> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> +  and render the device to be non-functional should be encoded in the image
> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> +  have the option to provide a more detailed description of the abort reason to
> +  the caller.
> +
> +  @param[in]  Image             Points to the new image.
> +  @param[in]  ImageSize         Size of the new image in bytes.
> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> +                                firmware image update policy. Null indicates the
> +                                caller did not specify the policy or use the
> +                                default policy.
> +  @param[in]  Progress          A function used by the driver to report the
> +                                progress of the firmware update.
> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> +  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> +                                string providing more details for the aborted
> +                                operation. The buffer is allocated by this
> +                                function with AllocatePool(), and it is the
> +                                caller's responsibility to free it with a call
> +                                to FreePool().
> +
> +  @retval EFI_SUCCESS            The device was successfully updated with the
> +                                 new image.
> +  @retval EFI_ABORTED            The operation is aborted.
> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FmpDeviceSetImage (
> +  IN  CONST VOID                                     *Image,
> +  IN  UINTN                                          ImageSize,
> +  IN  CONST VOID                                     *VendorCode,
> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> +  IN  UINT32                                         CapsuleFwVersion,
> +  OUT CHAR16                                         **AbortReason
> +  )
> +{
> +  UINT32  LastAttemptStatus;
> +
> +  return  FmpDeviceSetImageWithStatus (
> +            Image,
> +            ImageSize,
> +            VendorCode,
> +            Progress,
> +            CapsuleFwVersion,
> +            AbortReason,
> +            &LastAttemptStatus
> +            );
> +}
> +
> +/**
> +  Checks if a new firmware image is valid for the firmware device.  This
> +  function allows firmware update operation to validate the firmware image
> +  before FmpDeviceSetImage() is called.
> +
> +  @param[in]  Image               Points to a new firmware image.
> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> +                                  a firmware update to the firmware device.  The
> +                                  following values from the Firmware Management
> +                                  Protocol are supported:
> +                                    IMAGE_UPDATABLE_VALID
> +                                    IMAGE_UPDATABLE_INVALID
> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> +                                    IMAGE_UPDATABLE_INVALID_OLD
> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> +                                  status to report back to the ESRT table in case
> +                                  of error. This value will only be checked when this
> +                                  function returns an error.
> +
> +                                  The return status code must fall in the range of
> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> +
> +                                  If the value falls outside this range, it will be converted
> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> +
> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> +                                 status information is returned in
> +                                 ImageUpdatable.
> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FmpDeviceCheckImageWithStatus (
> +  IN  CONST VOID  *Image,
> +  IN  UINTN       ImageSize,
> +  OUT UINT32      *ImageUpdatable,
> +  OUT UINT32      *LastAttemptStatus
> +  )
> +{
> +  if (LastAttemptStatus == NULL) {
> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> +
> +  if (ImageUpdatable == NULL) {
> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  //Set to valid and then if any tests fail it will update this flag.
> +  //
> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> +
> +  if (Image == NULL) {
> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> +    //
> +    // Not sure if this is needed
> +    //
> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Make sure the image size is correct
> +  //
> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
>   /**
>   Checks if the firmware image is valid for the device.
>   
> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
>     OUT UINT32      *ImageUpdateable
>     )
>   {
> -  if (ImageUpdateable == NULL) {
> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> -    return EFI_INVALID_PARAMETER;
> -  }
> +  UINT32  LastAttemptStatus;
>   
> -  //
> -  //Set to valid and then if any tests fail it will update this flag.
> -  //
> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> -
> -  if (Image == NULL) {
> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> -    //
> -    // Not sure if this is needed
> -    //
> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> -    return EFI_INVALID_PARAMETER;
> -  }
> -
> -  //
> -  // Make sure the image size is correct
> -  //
> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> -    return EFI_INVALID_PARAMETER;
> -  }
> -
> -  return EFI_SUCCESS;
> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
>   }
>   
>   /**
> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> index db0f238ea534..132b60844ad4 100644
> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> @@ -1,6 +1,6 @@
>   /**
>   
> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
> +Copyright (c) Microsoft Corporation.<BR>
>   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>   
>   SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>   
>   
>   #include <PiDxe.h>
> +#include <LastAttemptStatus.h>
> +#include <Guid/SystemResourceTable.h>
>   #include <Library/DebugLib.h>
>   #include <Protocol/FirmwareManagement.h>
>   #include <Library/BaseLib.h>
> @@ -345,6 +347,131 @@ Return Value:
>   }//GetImage()
>   
>   
> +/**
> +  Updates a firmware device with a new firmware image.  This function returns
> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> +  is updatable, the function should perform the following minimal validations
> +  before proceeding to do the firmware image update.
> +    - Validate that the image is a supported image for this firmware device.
> +      Return EFI_ABORTED if the image is not supported.  Additional details
> +      on why the image is not a supported image may be returned in AbortReason.
> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> +      validation must be performed before VendorCode data validation.
> +      VendorCode data is ignored or considered invalid if image validation
> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> +
> +  VendorCode enables vendor to implement vendor-specific firmware image update
> +  policy.  Null if the caller did not specify the policy or use the default
> +  policy.  As an example, vendor can implement a policy to allow an option to
> +  force a firmware image update when the abort reason is due to the new firmware
> +  image version is older than the current firmware image version or bad image
> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> +  and render the device to be non-functional should be encoded in the image
> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> +  have the option to provide a more detailed description of the abort reason to
> +  the caller.
> +
> +  @param[in]  Image             Points to the new firmware image.
> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> +                                firmware image update policy.  NULL indicates
> +                                the caller did not specify the policy or use the
> +                                default policy.
> +  @param[in]  Progress          A function used to report the progress of
> +                                updating the firmware device with the new
> +                                firmware image.
> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> +                                update capsule that provided the new firmware
> +                                image.
> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> +                                Unicode string providing more details on an
> +                                aborted operation. The buffer is allocated by
> +                                this function with
> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> +                                caller's responsibility to free this buffer with
> +                                EFI_BOOT_SERVICES.FreePool().
> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> +                                status to report back to the ESRT table in case
> +                                of error. This value will only be checked when this
> +                                function returns an error.
> +
> +                                The return status code must fall in the range of
> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> +
> +                                If the value falls outside this range, it will be converted
> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> +
> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> +                                 with the new firmware image.
> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> +                                 are provided in AbortReason.
> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FmpDeviceSetImageWithStatus (
> +  IN  CONST VOID                                     *Image,
> +  IN  UINTN                                          ImageSize,
> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
> +  IN  UINT32                                         CapsuleFwVersion,
> +  OUT CHAR16                                         **AbortReason,
> +  OUT UINT32                                         *LastAttemptStatus
> +  )
> +{
> +    EFI_STATUS Status                         = EFI_SUCCESS;
> +    UINT32 Updateable                         = 0;
> +
> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
> +    if (EFI_ERROR(Status))
> +    {
> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed with %r.\n", Status));
> +        goto cleanup;
> +    }
> +
> +    if (Updateable != IMAGE_UPDATABLE_VALID)
> +    {
> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n", Updateable));
> +        Status = EFI_ABORTED;
> +        goto cleanup;
> +    }
> +
> +    if (Progress == NULL)
> +    {
> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress callback\n"));
> +        Status = EFI_INVALID_PARAMETER;
> +        goto cleanup;
> +    }
> +
> +    Status = Progress(15);
> +    if (EFI_ERROR(Status))
> +    {
> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback failed with Status %r.\n", Status));
> +    }
> +
> +    {
> +      UINTN  p;
> +
> +      for (p = 20; p < 100; p++) {
> +        gBS->Stall (100000);  //us  = 0.1 seconds
> +        Progress (p);
> +      }
> +    }
> +
> +    //TODO: add support for VendorCode, and AbortReason
> +cleanup:
> +    if (EFI_ERROR (Status)) {
> +      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +    }
> +
> +    return Status;
> +}// SetImageWithStatus()
> +
> +
>   /**
>   Updates the firmware image of the device.
>   
> @@ -396,51 +523,98 @@ IN  UINT32                                           CapsuleFwVersion,
>   OUT CHAR16                                           **AbortReason
>   )
>   {
> -    EFI_STATUS Status                         = EFI_SUCCESS;
> -    UINT32 Updateable                         = 0;
> -
> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
> -    if (EFI_ERROR(Status))
> -    {
> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with %r.\n", Status));
> -        goto cleanup;
> -    }
> -
> -    if (Updateable != IMAGE_UPDATABLE_VALID)
> -    {
> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n", Updateable));
> -        Status = EFI_ABORTED;
> -        goto cleanup;
> -    }
> -
> -    if (Progress == NULL)
> -    {
> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
> -        Status = EFI_INVALID_PARAMETER;
> -        goto cleanup;
> -    }
> -
> -    Status = Progress(15);
> -    if (EFI_ERROR(Status))
> -    {
> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with Status %r.\n", Status));
> -    }
> -
> -    {
> -      UINTN  p;
> -
> -      for (p = 20; p < 100; p++) {
> -        gBS->Stall (100000);  //us  = 0.1 seconds
> -        Progress (p);
> -      }
> -    }
> -
> -    //TODO: add support for VendorCode, and AbortReason
> -cleanup:
> -    return Status;
> +  UINT32  LastAttemptStatus;
> +
> +  return  FmpDeviceSetImageWithStatus (
> +            Image,
> +            ImageSize,
> +            VendorCode,
> +            Progress,
> +            CapsuleFwVersion,
> +            AbortReason,
> +            &LastAttemptStatus
> +            );
>   }// SetImage()
>   
>   
> +/**
> +  Checks if a new firmware image is valid for the firmware device.  This
> +  function allows firmware update operation to validate the firmware image
> +  before FmpDeviceSetImage() is called.
> +
> +  @param[in]  Image               Points to a new firmware image.
> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> +                                  a firmware update to the firmware device.  The
> +                                  following values from the Firmware Management
> +                                  Protocol are supported:
> +                                    IMAGE_UPDATABLE_VALID
> +                                    IMAGE_UPDATABLE_INVALID
> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> +                                    IMAGE_UPDATABLE_INVALID_OLD
> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> +                                  status to report back to the ESRT table in case
> +                                  of error. This value will only be checked when this
> +                                  function returns an error.
> +
> +                                  The return status code must fall in the range of
> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> +
> +                                  If the value falls outside this range, it will be converted
> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> +
> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> +                                 status information is returned in
> +                                 ImageUpdatable.
> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FmpDeviceCheckImageWithStatus (
> +  IN  CONST VOID  *Image,
> +  IN  UINTN       ImageSize,
> +  OUT UINT32      *ImageUpdatable,
> +  OUT UINT32      *LastAttemptStatus
> +  )
> +{
> +    EFI_STATUS status = EFI_SUCCESS;
> +
> +    if (LastAttemptStatus == NULL) {
> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> +
> +    if (ImageUpdatable == NULL)
> +    {
> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +        status = EFI_INVALID_PARAMETER;
> +        goto cleanup;
> +    }
> +
> +    //
> +    //Set to valid and then if any tests fail it will update this flag.
> +    //
> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> +
> +    if (Image == NULL)
> +    {
> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +        return EFI_INVALID_PARAMETER;
> +    }
> +
> +cleanup:
> +    return status;
> +}// CheckImageWithStatus()
> +
>   
>   /**
>   Checks if the firmware image is valid for the device.
> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
>   OUT UINT32                            *ImageUpdateable
>   )
>   {
> -    EFI_STATUS status = EFI_SUCCESS;
> +  UINT32  LastAttemptStatus;
>   
> -    if (ImageUpdateable == NULL)
> -    {
> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> -        status = EFI_INVALID_PARAMETER;
> -        goto cleanup;
> -    }
> -
> -    //
> -    //Set to valid and then if any tests fail it will update this flag.
> -    //
> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> -
> -    if (Image == NULL)
> -    {
> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> -        return EFI_INVALID_PARAMETER;
> -    }
> -
> -cleanup:
> -    return status;
> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
>   }// CheckImage()
>   
>   /**
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
       [not found] ` <bf090dba-75d3-520e-7414-bcdb8314562b@outlook.com>
@ 2020-10-27  0:50   ` Michael Kubacki
  0 siblings, 0 replies; 10+ messages in thread
From: Michael Kubacki @ 2020-10-27  0:50 UTC (permalink / raw)
  To: devel; +Cc: Michael D Kinney, Yi Qian, Zailiang Sun

I still haven't seen any feedback on this patch.

Can you please review it?

Thanks,
Michael

On 10/15/2020 2:27 PM, Michael Kubacki wrote:
> Hi,
> 
> It's been two weeks with no feedback.
> 
> A review would be appreciated.
> 
> Thanks,
> Michael
> 
> On 10/1/2020 2:58 PM, Michael Kubacki wrote:
>> From: Michael Kubacki <michael.kubacki@microsoft.com>
>>
>> Makes the changes necessary for these library instances of
>> FmpDeviceLib to be compatible with new functions added recently
>> to FmpDeviceLib.
>>
>> Two new functions were introduced in FmpDeviceLib to allow a
>> library instance to return a Last Attempt Status code during
>> check image and set image operations:
>>    1. FmpDeviceCheckImageWithStatus ( )
>>    2. FmpDeviceSetImageWithStatus ( )
>>
>> FmpDxe (in FmpDevicePkg) will begin calling these new functions
>> instead of the previous functions. Therefore, this change:
>>    1. Adds these functions to Vlv2TbltDevicePkg implementations
>>    2. Moves the main functionality to these new functions
>>    3. Updates the old functions to call the new functions
>>       (for backward compatibility)
>>
>> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
>> due to:
>>    1. A required RngLib library instance not defined by the platform
>>    2. Other FMP libraries not being defined by the platform
>>       (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
>>
>> Those changes were fixed locally to test the changes in this commit
>> but maintainers should make the proper changes for those issues.
>>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Yi Qian <yi.qian@intel.com>
>> Cc: Zailiang Sun <zailiang.sun@intel.com>
>> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
>> ---
>>
>> Notes:
>>      Only build was checked, I do not have access to a
>>      VLV2 device for testing.
>>
>>   
>> Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       
>> | 299 +++++++++++++++-----
>>   
>> Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c 
>> | 284 ++++++++++++++-----
>>   2 files changed, 446 insertions(+), 137 deletions(-)
>>
>> diff --git 
>> a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c 
>> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c 
>>
>> index d8c9036012ad..df8a36d9854c 100644
>> --- 
>> a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c 
>>
>> +++ 
>> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c 
>>
>> @@ -1,6 +1,6 @@
>>   /**
>> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
>> +Copyright (c) Microsoft Corporation.<BR>
>>   Copyright (c) 2019, Intel Corporation.  All rights reserved.
>>   SPDX-License-Identifier: BSD-2-Clause-Patent
>> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>>   **/
>>   #include <PiDxe.h>
>> -
>> +#include <LastAttemptStatus.h>
>> +#include <Guid/SystemResourceTable.h>
>>   #include <Library/FmpDeviceLib.h>
>>   #include <Library/DebugLib.h>
>> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
>>   }
>>   /**
>> -  Updates the firmware image of the device.
>> -
>> -  This function updates the hardware with the new firmware image.  
>> This function
>> -  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If 
>> the
>> -  firmware image is updatable, the function should perform the 
>> following minimal
>> -  validations before proceeding to do the firmware image update.
>> -    - Validate the image is a supported image for this device.  The 
>> function
>> -      returns EFI_ABORTED if the image is unsupported.  The function can
>> -      optionally provide more detailed information on why the image 
>> is not a
>> -      supported image.
>> -    - Validate the data from VendorCode if not null.  Image 
>> validation must be
>> -      performed before VendorCode data validation.  VendorCode data 
>> is ignored
>> -      or considered invalid if image validation failed.  The function 
>> returns
>> -      EFI_ABORTED if the data is invalid.
>> +  Updates a firmware device with a new firmware image.  This function 
>> returns
>> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the 
>> firmware image
>> +  is updatable, the function should perform the following minimal 
>> validations
>> +  before proceeding to do the firmware image update.
>> +    - Validate that the image is a supported image for this firmware 
>> device.
>> +      Return EFI_ABORTED if the image is not supported.  Additional 
>> details
>> +      on why the image is not a supported image may be returned in 
>> AbortReason.
>> +    - Validate the data from VendorCode if is not NULL.  Firmware image
>> +      validation must be performed before VendorCode data validation.
>> +      VendorCode data is ignored or considered invalid if image 
>> validation
>> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>>     VendorCode enables vendor to implement vendor-specific firmware 
>> image update
>>     policy.  Null if the caller did not specify the policy or use the 
>> default
>> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
>>     have the option to provide a more detailed description of the 
>> abort reason to
>>     the caller.
>> -  @param[in]  Image             Points to the new image.
>> -  @param[in]  ImageSize         Size of the new image in bytes.
>> +  @param[in]  Image             Points to the new firmware image.
>> +  @param[in]  ImageSize         Size, in bytes, of the new firmware 
>> image.
>>     @param[in]  VendorCode        This enables vendor to implement 
>> vendor-specific
>> -                                firmware image update policy. Null 
>> indicates the
>> -                                caller did not specify the policy or 
>> use the
>> +                                firmware image update policy.  NULL 
>> indicates
>> +                                the caller did not specify the policy 
>> or use the
>>                                   default policy.
>> -  @param[in]  Progress          A function used by the driver to 
>> report the
>> -                                progress of the firmware update.
>> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
>> -  @param[out] AbortReason       A pointer to a pointer to a 
>> null-terminated
>> -                                string providing more details for the 
>> aborted
>> -                                operation. The buffer is allocated by 
>> this
>> -                                function with AllocatePool(), and it 
>> is the
>> -                                caller's responsibility to free it 
>> with a call
>> -                                to FreePool().
>> +  @param[in]  Progress          A function used to report the 
>> progress of
>> +                                updating the firmware device with the 
>> new
>> +                                firmware image.
>> +  @param[in]  CapsuleFwVersion  The version of the new firmware image 
>> from the
>> +                                update capsule that provided the new 
>> firmware
>> +                                image.
>> +  @param[out] AbortReason       A pointer to a pointer to a 
>> Null-terminated
>> +                                Unicode string providing more details 
>> on an
>> +                                aborted operation. The buffer is 
>> allocated by
>> +                                this function with
>> +                                EFI_BOOT_SERVICES.AllocatePool().  It 
>> is the
>> +                                caller's responsibility to free this 
>> buffer with
>> +                                EFI_BOOT_SERVICES.FreePool().
>> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the 
>> last attempt
>> +                                status to report back to the ESRT 
>> table in case
>> +                                of error. This value will only be 
>> checked when this
>> +                                function returns an error.
>> -  @retval EFI_SUCCESS            The device was successfully updated 
>> with the
>> -                                 new image.
>> -  @retval EFI_ABORTED            The operation is aborted.
>> +                                The return status code must fall in 
>> the range of
>> +                                
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                If the value falls outside this 
>> range, it will be converted
>> +                                to 
>> LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The firmware device was successfully 
>> updated
>> +                                 with the new firmware image.
>> +  @retval EFI_ABORTED            The operation is aborted.  
>> Additional details
>> +                                 are provided in AbortReason.
>>     @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>>     @retval EFI_UNSUPPORTED        The operation is not supported.
>>   **/
>>   EFI_STATUS
>>   EFIAPI
>> -FmpDeviceSetImage (
>> +FmpDeviceSetImageWithStatus (
>>     IN  CONST VOID                                     *Image,
>>     IN  UINTN                                          ImageSize,
>> -  IN  CONST VOID                                     *VendorCode,
>> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
>> +  IN  CONST VOID                                     
>> *VendorCode,       OPTIONAL
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  
>> Progress,          OPTIONAL
>>     IN  UINT32                                         CapsuleFwVersion,
>> -  OUT CHAR16                                         **AbortReason
>> +  OUT CHAR16                                         **AbortReason,
>> +  OUT UINT32                                         *LastAttemptStatus
>>     )
>>   {
>>     EFI_STATUS          Status;
>> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
>>     UINTN               BytesWritten;
>>     Updateable = 0;
>> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
>> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, 
>> &Updateable, LastAttemptStatus);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with 
>> %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image 
>> failed with %r.\n", Status));
>>       return Status;
>>     }
>>     if (Updateable != IMAGE_UPDATABLE_VALID) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned 
>> that the Image was not valid for update.  Updatable value = 0x%X.\n", 
>> Updateable));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image 
>> returned that the Image was not valid for update.  Updatable value = 
>> 0x%X.\n", Updateable));
>> +    *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>>       return EFI_ABORTED;
>>     }
>>     if (Progress == NULL) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress 
>> callback\n"));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid 
>> progress callback\n"));
>> +    *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>>       return EFI_INVALID_PARAMETER;
>>     }
>>     Status = Progress (15);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed 
>> with Status %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress 
>> Callback failed with Status %r.\n", Status));
>>     }
>>     //
>> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
>>     //
>>     Progress (20);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed 
>> with Status %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress 
>> Callback failed with Status %r.\n", Status));
>>     }
>>     //
>> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
>>   //    Progress (Percentage);
>>   //    if (EFI_ERROR (Status)) {
>> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback 
>> failed with Status %r.\n", Status));
>> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress 
>> Callback failed with Status %r.\n", Status));
>>   //    }
>>     }
>> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", 
>> ARRAY_SIZE (mUpdateConfigData)));
>> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images 
>> ...\n", ARRAY_SIZE (mUpdateConfigData)));
>>     if (ARRAY_SIZE (mUpdateConfigData) == 0) {
>>       DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx 
>> ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
>> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
>>       BytesWritten += ConfigData->Length;
>>     }
>> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
>> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +  }
>>     return Status;
>>   }
>> +/**
>> +  Updates the firmware image of the device.
>> +
>> +  This function updates the hardware with the new firmware image.  
>> This function
>> +  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If 
>> the
>> +  firmware image is updatable, the function should perform the 
>> following minimal
>> +  validations before proceeding to do the firmware image update.
>> +    - Validate the image is a supported image for this device.  The 
>> function
>> +      returns EFI_ABORTED if the image is unsupported.  The function can
>> +      optionally provide more detailed information on why the image 
>> is not a
>> +      supported image.
>> +    - Validate the data from VendorCode if not null.  Image 
>> validation must be
>> +      performed before VendorCode data validation.  VendorCode data 
>> is ignored
>> +      or considered invalid if image validation failed.  The function 
>> returns
>> +      EFI_ABORTED if the data is invalid.
>> +
>> +  VendorCode enables vendor to implement vendor-specific firmware 
>> image update
>> +  policy.  Null if the caller did not specify the policy or use the 
>> default
>> +  policy.  As an example, vendor can implement a policy to allow an 
>> option to
>> +  force a firmware image update when the abort reason is due to the 
>> new firmware
>> +  image version is older than the current firmware image version or 
>> bad image
>> +  checksum.  Sensitive operations such as those wiping the entire 
>> firmware image
>> +  and render the device to be non-functional should be encoded in the 
>> image
>> +  itself rather than passed with the VendorCode.  AbortReason enables 
>> vendor to
>> +  have the option to provide a more detailed description of the abort 
>> reason to
>> +  the caller.
>> +
>> +  @param[in]  Image             Points to the new image.
>> +  @param[in]  ImageSize         Size of the new image in bytes.
>> +  @param[in]  VendorCode        This enables vendor to implement 
>> vendor-specific
>> +                                firmware image update policy. Null 
>> indicates the
>> +                                caller did not specify the policy or 
>> use the
>> +                                default policy.
>> +  @param[in]  Progress          A function used by the driver to 
>> report the
>> +                                progress of the firmware update.
>> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
>> +  @param[out] AbortReason       A pointer to a pointer to a 
>> null-terminated
>> +                                string providing more details for the 
>> aborted
>> +                                operation. The buffer is allocated by 
>> this
>> +                                function with AllocatePool(), and it 
>> is the
>> +                                caller's responsibility to free it 
>> with a call
>> +                                to FreePool().
>> +
>> +  @retval EFI_SUCCESS            The device was successfully updated 
>> with the
>> +                                 new image.
>> +  @retval EFI_ABORTED            The operation is aborted.
>> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_UNSUPPORTED        The operation is not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceSetImage (
>> +  IN  CONST VOID                                     *Image,
>> +  IN  UINTN                                          ImageSize,
>> +  IN  CONST VOID                                     *VendorCode,
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
>> +  IN  UINT32                                         CapsuleFwVersion,
>> +  OUT CHAR16                                         **AbortReason
>> +  )
>> +{
>> +  UINT32  LastAttemptStatus;
>> +
>> +  return  FmpDeviceSetImageWithStatus (
>> +            Image,
>> +            ImageSize,
>> +            VendorCode,
>> +            Progress,
>> +            CapsuleFwVersion,
>> +            AbortReason,
>> +            &LastAttemptStatus
>> +            );
>> +}
>> +
>> +/**
>> +  Checks if a new firmware image is valid for the firmware device.  This
>> +  function allows firmware update operation to validate the firmware 
>> image
>> +  before FmpDeviceSetImage() is called.
>> +
>> +  @param[in]  Image               Points to a new firmware image.
>> +  @param[in]  ImageSize           Size, in bytes, of a new firmware 
>> image.
>> +  @param[out] ImageUpdatable      Indicates if a new firmware image 
>> is valid for
>> +                                  a firmware update to the firmware 
>> device.  The
>> +                                  following values from the Firmware 
>> Management
>> +                                  Protocol are supported:
>> +                                    IMAGE_UPDATABLE_VALID
>> +                                    IMAGE_UPDATABLE_INVALID
>> +                                    IMAGE_UPDATABLE_INVALID_TYPE
>> +                                    IMAGE_UPDATABLE_INVALID_OLD
>> +                                    
>> IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
>> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds 
>> the last attempt
>> +                                  status to report back to the ESRT 
>> table in case
>> +                                  of error. This value will only be 
>> checked when this
>> +                                  function returns an error.
>> +
>> +                                  The return status code must fall in 
>> the range of
>> +                                  
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                  
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                  If the value falls outside this 
>> range, it will be converted
>> +                                  to 
>> LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The image was successfully checked.  
>> Additional
>> +                                 status information is returned in
>> +                                 ImageUpdatable.
>> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
>> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceCheckImageWithStatus (
>> +  IN  CONST VOID  *Image,
>> +  IN  UINTN       ImageSize,
>> +  OUT UINT32      *ImageUpdatable,
>> +  OUT UINT32      *LastAttemptStatus
>> +  )
>> +{
>> +  if (LastAttemptStatus == NULL) {
>> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus 
>> Pointer Parameter is NULL.\n"));
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
>> +
>> +  if (ImageUpdatable == NULL) {
>> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable 
>> Pointer Parameter is NULL.\n"));
>> +    *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  //
>> +  //Set to valid and then if any tests fail it will update this flag.
>> +  //
>> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
>> +
>> +  if (Image == NULL) {
>> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer 
>> Parameter is NULL.\n"));
>> +    //
>> +    // Not sure if this is needed
>> +    //
>> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
>> +    *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  //
>> +  // Make sure the image size is correct
>> +  //
>> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
>> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
>> +    *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>>   /**
>>   Checks if the firmware image is valid for the device.
>> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
>>     OUT UINT32      *ImageUpdateable
>>     )
>>   {
>> -  if (ImageUpdateable == NULL) {
>> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer 
>> Parameter is NULL.\n"));
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> +  UINT32  LastAttemptStatus;
>> -  //
>> -  //Set to valid and then if any tests fail it will update this flag.
>> -  //
>> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
>> -
>> -  if (Image == NULL) {
>> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is 
>> NULL.\n"));
>> -    //
>> -    // Not sure if this is needed
>> -    //
>> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> -
>> -  //
>> -  // Make sure the image size is correct
>> -  //
>> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
>> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> -
>> -  return EFI_SUCCESS;
>> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, 
>> ImageUpdateable, &LastAttemptStatus);
>>   }
>>   /**
>> diff --git 
>> a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c 
>> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c 
>>
>> index db0f238ea534..132b60844ad4 100644
>> --- 
>> a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c 
>>
>> +++ 
>> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c 
>>
>> @@ -1,6 +1,6 @@
>>   /**
>> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
>> +Copyright (c) Microsoft Corporation.<BR>
>>   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>>   SPDX-License-Identifier: BSD-2-Clause-Patent
>> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>>   #include <PiDxe.h>
>> +#include <LastAttemptStatus.h>
>> +#include <Guid/SystemResourceTable.h>
>>   #include <Library/DebugLib.h>
>>   #include <Protocol/FirmwareManagement.h>
>>   #include <Library/BaseLib.h>
>> @@ -345,6 +347,131 @@ Return Value:
>>   }//GetImage()
>> +/**
>> +  Updates a firmware device with a new firmware image.  This function 
>> returns
>> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the 
>> firmware image
>> +  is updatable, the function should perform the following minimal 
>> validations
>> +  before proceeding to do the firmware image update.
>> +    - Validate that the image is a supported image for this firmware 
>> device.
>> +      Return EFI_ABORTED if the image is not supported.  Additional 
>> details
>> +      on why the image is not a supported image may be returned in 
>> AbortReason.
>> +    - Validate the data from VendorCode if is not NULL.  Firmware image
>> +      validation must be performed before VendorCode data validation.
>> +      VendorCode data is ignored or considered invalid if image 
>> validation
>> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>> +
>> +  VendorCode enables vendor to implement vendor-specific firmware 
>> image update
>> +  policy.  Null if the caller did not specify the policy or use the 
>> default
>> +  policy.  As an example, vendor can implement a policy to allow an 
>> option to
>> +  force a firmware image update when the abort reason is due to the 
>> new firmware
>> +  image version is older than the current firmware image version or 
>> bad image
>> +  checksum.  Sensitive operations such as those wiping the entire 
>> firmware image
>> +  and render the device to be non-functional should be encoded in the 
>> image
>> +  itself rather than passed with the VendorCode.  AbortReason enables 
>> vendor to
>> +  have the option to provide a more detailed description of the abort 
>> reason to
>> +  the caller.
>> +
>> +  @param[in]  Image             Points to the new firmware image.
>> +  @param[in]  ImageSize         Size, in bytes, of the new firmware 
>> image.
>> +  @param[in]  VendorCode        This enables vendor to implement 
>> vendor-specific
>> +                                firmware image update policy.  NULL 
>> indicates
>> +                                the caller did not specify the policy 
>> or use the
>> +                                default policy.
>> +  @param[in]  Progress          A function used to report the 
>> progress of
>> +                                updating the firmware device with the 
>> new
>> +                                firmware image.
>> +  @param[in]  CapsuleFwVersion  The version of the new firmware image 
>> from the
>> +                                update capsule that provided the new 
>> firmware
>> +                                image.
>> +  @param[out] AbortReason       A pointer to a pointer to a 
>> Null-terminated
>> +                                Unicode string providing more details 
>> on an
>> +                                aborted operation. The buffer is 
>> allocated by
>> +                                this function with
>> +                                EFI_BOOT_SERVICES.AllocatePool().  It 
>> is the
>> +                                caller's responsibility to free this 
>> buffer with
>> +                                EFI_BOOT_SERVICES.FreePool().
>> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the 
>> last attempt
>> +                                status to report back to the ESRT 
>> table in case
>> +                                of error. This value will only be 
>> checked when this
>> +                                function returns an error.
>> +
>> +                                The return status code must fall in 
>> the range of
>> +                                
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                If the value falls outside this 
>> range, it will be converted
>> +                                to 
>> LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The firmware device was successfully 
>> updated
>> +                                 with the new firmware image.
>> +  @retval EFI_ABORTED            The operation is aborted.  
>> Additional details
>> +                                 are provided in AbortReason.
>> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>> +  @retval EFI_UNSUPPORTED        The operation is not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceSetImageWithStatus (
>> +  IN  CONST VOID                                     *Image,
>> +  IN  UINTN                                          ImageSize,
>> +  IN  CONST VOID                                     
>> *VendorCode,       OPTIONAL
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  
>> Progress,          OPTIONAL
>> +  IN  UINT32                                         CapsuleFwVersion,
>> +  OUT CHAR16                                         **AbortReason,
>> +  OUT UINT32                                         *LastAttemptStatus
>> +  )
>> +{
>> +    EFI_STATUS Status                         = EFI_SUCCESS;
>> +    UINT32 Updateable                         = 0;
>> +
>> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, 
>> &Updateable, LastAttemptStatus);
>> +    if (EFI_ERROR(Status))
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed 
>> with %r.\n", Status));
>> +        goto cleanup;
>> +    }
>> +
>> +    if (Updateable != IMAGE_UPDATABLE_VALID)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image 
>> returned that the Image was not valid for update.  Updatable value = 
>> 0x%X.\n", Updateable));
>> +        Status = EFI_ABORTED;
>> +        goto cleanup;
>> +    }
>> +
>> +    if (Progress == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress 
>> callback\n"));
>> +        Status = EFI_INVALID_PARAMETER;
>> +        goto cleanup;
>> +    }
>> +
>> +    Status = Progress(15);
>> +    if (EFI_ERROR(Status))
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback 
>> failed with Status %r.\n", Status));
>> +    }
>> +
>> +    {
>> +      UINTN  p;
>> +
>> +      for (p = 20; p < 100; p++) {
>> +        gBS->Stall (100000);  //us  = 0.1 seconds
>> +        Progress (p);
>> +      }
>> +    }
>> +
>> +    //TODO: add support for VendorCode, and AbortReason
>> +cleanup:
>> +    if (EFI_ERROR (Status)) {
>> +      *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    }
>> +
>> +    return Status;
>> +}// SetImageWithStatus()
>> +
>> +
>>   /**
>>   Updates the firmware image of the device.
>> @@ -396,51 +523,98 @@ IN  
>> UINT32                                           CapsuleFwVersion,
>>   OUT CHAR16                                           **AbortReason
>>   )
>>   {
>> -    EFI_STATUS Status                         = EFI_SUCCESS;
>> -    UINT32 Updateable                         = 0;
>> -
>> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
>> -    if (EFI_ERROR(Status))
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with 
>> %r.\n", Status));
>> -        goto cleanup;
>> -    }
>> -
>> -    if (Updateable != IMAGE_UPDATABLE_VALID)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the 
>> Image was not valid for update.  Updatable value = 0x%X.\n", 
>> Updateable));
>> -        Status = EFI_ABORTED;
>> -        goto cleanup;
>> -    }
>> -
>> -    if (Progress == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
>> -        Status = EFI_INVALID_PARAMETER;
>> -        goto cleanup;
>> -    }
>> -
>> -    Status = Progress(15);
>> -    if (EFI_ERROR(Status))
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with 
>> Status %r.\n", Status));
>> -    }
>> -
>> -    {
>> -      UINTN  p;
>> -
>> -      for (p = 20; p < 100; p++) {
>> -        gBS->Stall (100000);  //us  = 0.1 seconds
>> -        Progress (p);
>> -      }
>> -    }
>> -
>> -    //TODO: add support for VendorCode, and AbortReason
>> -cleanup:
>> -    return Status;
>> +  UINT32  LastAttemptStatus;
>> +
>> +  return  FmpDeviceSetImageWithStatus (
>> +            Image,
>> +            ImageSize,
>> +            VendorCode,
>> +            Progress,
>> +            CapsuleFwVersion,
>> +            AbortReason,
>> +            &LastAttemptStatus
>> +            );
>>   }// SetImage()
>> +/**
>> +  Checks if a new firmware image is valid for the firmware device.  This
>> +  function allows firmware update operation to validate the firmware 
>> image
>> +  before FmpDeviceSetImage() is called.
>> +
>> +  @param[in]  Image               Points to a new firmware image.
>> +  @param[in]  ImageSize           Size, in bytes, of a new firmware 
>> image.
>> +  @param[out] ImageUpdatable      Indicates if a new firmware image 
>> is valid for
>> +                                  a firmware update to the firmware 
>> device.  The
>> +                                  following values from the Firmware 
>> Management
>> +                                  Protocol are supported:
>> +                                    IMAGE_UPDATABLE_VALID
>> +                                    IMAGE_UPDATABLE_INVALID
>> +                                    IMAGE_UPDATABLE_INVALID_TYPE
>> +                                    IMAGE_UPDATABLE_INVALID_OLD
>> +                                    
>> IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
>> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds 
>> the last attempt
>> +                                  status to report back to the ESRT 
>> table in case
>> +                                  of error. This value will only be 
>> checked when this
>> +                                  function returns an error.
>> +
>> +                                  The return status code must fall in 
>> the range of
>> +                                  
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                  
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                  If the value falls outside this 
>> range, it will be converted
>> +                                  to 
>> LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The image was successfully checked.  
>> Additional
>> +                                 status information is returned in
>> +                                 ImageUpdatable.
>> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
>> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceCheckImageWithStatus (
>> +  IN  CONST VOID  *Image,
>> +  IN  UINTN       ImageSize,
>> +  OUT UINT32      *ImageUpdatable,
>> +  OUT UINT32      *LastAttemptStatus
>> +  )
>> +{
>> +    EFI_STATUS status = EFI_SUCCESS;
>> +
>> +    if (LastAttemptStatus == NULL) {
>> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus 
>> Pointer Parameter is NULL.\n"));
>> +      return EFI_INVALID_PARAMETER;
>> +    }
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
>> +
>> +    if (ImageUpdatable == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable 
>> Pointer Parameter is NULL.\n"));
>> +        *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +        status = EFI_INVALID_PARAMETER;
>> +        goto cleanup;
>> +    }
>> +
>> +    //
>> +    //Set to valid and then if any tests fail it will update this flag.
>> +    //
>> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
>> +
>> +    if (Image == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer 
>> Parameter is NULL.\n"));
>> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this 
>> is needed
>> +        *LastAttemptStatus = 
>> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +        return EFI_INVALID_PARAMETER;
>> +    }
>> +
>> +cleanup:
>> +    return status;
>> +}// CheckImageWithStatus()
>> +
>>   /**
>>   Checks if the firmware image is valid for the device.
>> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
>>   OUT UINT32                            *ImageUpdateable
>>   )
>>   {
>> -    EFI_STATUS status = EFI_SUCCESS;
>> +  UINT32  LastAttemptStatus;
>> -    if (ImageUpdateable == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer 
>> Parameter is NULL.\n"));
>> -        status = EFI_INVALID_PARAMETER;
>> -        goto cleanup;
>> -    }
>> -
>> -    //
>> -    //Set to valid and then if any tests fail it will update this flag.
>> -    //
>> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
>> -
>> -    if (Image == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is 
>> NULL.\n"));
>> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if 
>> this is needed
>> -        return EFI_INVALID_PARAMETER;
>> -    }
>> -
>> -cleanup:
>> -    return status;
>> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, 
>> ImageUpdateable, &LastAttemptStatus);
>>   }// CheckImage()
>>   /**
>>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
  2020-10-01 21:58 [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility Michael Kubacki
@ 2020-10-29  1:12 ` Michael D Kinney
  2020-10-29  4:45   ` Michael Kubacki
  2020-11-05 20:36   ` Michael Kubacki
  0 siblings, 2 replies; 10+ messages in thread
From: Michael D Kinney @ 2020-10-29  1:12 UTC (permalink / raw)
  To: michael.kubacki@outlook.com, devel@edk2.groups.io,
	Kinney, Michael D
  Cc: Qian, Yi, Sun, Zailiang

Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>

I also verified build and boot and FMP based capsule updates work as expected.

Tested-by: Michael D Kinney <Michael.d.kinney@intel.com>

Thanks,

Mike


> -----Original Message-----
> From: michael.kubacki@outlook.com <michael.kubacki@outlook.com>
> Sent: Thursday, October 1, 2020 2:59 PM
> To: devel@edk2.groups.io
> Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Qian, Yi <yi.qian@intel.com>; Sun, Zailiang <zailiang.sun@intel.com>
> Subject: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
> 
> From: Michael Kubacki <michael.kubacki@microsoft.com>
> 
> Makes the changes necessary for these library instances of
> FmpDeviceLib to be compatible with new functions added recently
> to FmpDeviceLib.
> 
> Two new functions were introduced in FmpDeviceLib to allow a
> library instance to return a Last Attempt Status code during
> check image and set image operations:
>   1. FmpDeviceCheckImageWithStatus ( )
>   2. FmpDeviceSetImageWithStatus ( )
> 
> FmpDxe (in FmpDevicePkg) will begin calling these new functions
> instead of the previous functions. Therefore, this change:
>   1. Adds these functions to Vlv2TbltDevicePkg implementations
>   2. Moves the main functionality to these new functions
>   3. Updates the old functions to call the new functions
>      (for backward compatibility)
> 
> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
> due to:
>   1. A required RngLib library instance not defined by the platform
>   2. Other FMP libraries not being defined by the platform
>      (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
> 
> Those changes were fixed locally to test the changes in this commit
> but maintainers should make the proper changes for those issues.
> 
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Yi Qian <yi.qian@intel.com>
> Cc: Zailiang Sun <zailiang.sun@intel.com>
> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
> ---
> 
> Notes:
>     Only build was checked, I do not have access to a
>     VLV2 device for testing.
> 
>  Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       | 299 +++++++++++++++-----
>  Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c | 284 ++++++++++++++-----
>  2 files changed, 446 insertions(+), 137 deletions(-)
> 
> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> index d8c9036012ad..df8a36d9854c 100644
> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> @@ -1,6 +1,6 @@
>  /**
> 
> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
> +Copyright (c) Microsoft Corporation.<BR>
>  Copyright (c) 2019, Intel Corporation.  All rights reserved.
> 
>  SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
> 
>  #include <PiDxe.h>
> -
> +#include <LastAttemptStatus.h>
> +#include <Guid/SystemResourceTable.h>
>  #include <Library/FmpDeviceLib.h>
> 
>  #include <Library/DebugLib.h>
> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
>  }
> 
>  /**
> -  Updates the firmware image of the device.
> -
> -  This function updates the hardware with the new firmware image.  This function
> -  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> -  firmware image is updatable, the function should perform the following minimal
> -  validations before proceeding to do the firmware image update.
> -    - Validate the image is a supported image for this device.  The function
> -      returns EFI_ABORTED if the image is unsupported.  The function can
> -      optionally provide more detailed information on why the image is not a
> -      supported image.
> -    - Validate the data from VendorCode if not null.  Image validation must be
> -      performed before VendorCode data validation.  VendorCode data is ignored
> -      or considered invalid if image validation failed.  The function returns
> -      EFI_ABORTED if the data is invalid.
> +  Updates a firmware device with a new firmware image.  This function returns
> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> +  is updatable, the function should perform the following minimal validations
> +  before proceeding to do the firmware image update.
> +    - Validate that the image is a supported image for this firmware device.
> +      Return EFI_ABORTED if the image is not supported.  Additional details
> +      on why the image is not a supported image may be returned in AbortReason.
> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> +      validation must be performed before VendorCode data validation.
> +      VendorCode data is ignored or considered invalid if image validation
> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> 
>    VendorCode enables vendor to implement vendor-specific firmware image update
>    policy.  Null if the caller did not specify the policy or use the default
> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
>    have the option to provide a more detailed description of the abort reason to
>    the caller.
> 
> -  @param[in]  Image             Points to the new image.
> -  @param[in]  ImageSize         Size of the new image in bytes.
> +  @param[in]  Image             Points to the new firmware image.
> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
>    @param[in]  VendorCode        This enables vendor to implement vendor-specific
> -                                firmware image update policy. Null indicates the
> -                                caller did not specify the policy or use the
> +                                firmware image update policy.  NULL indicates
> +                                the caller did not specify the policy or use the
>                                  default policy.
> -  @param[in]  Progress          A function used by the driver to report the
> -                                progress of the firmware update.
> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> -  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> -                                string providing more details for the aborted
> -                                operation. The buffer is allocated by this
> -                                function with AllocatePool(), and it is the
> -                                caller's responsibility to free it with a call
> -                                to FreePool().
> +  @param[in]  Progress          A function used to report the progress of
> +                                updating the firmware device with the new
> +                                firmware image.
> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> +                                update capsule that provided the new firmware
> +                                image.
> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> +                                Unicode string providing more details on an
> +                                aborted operation. The buffer is allocated by
> +                                this function with
> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> +                                caller's responsibility to free this buffer with
> +                                EFI_BOOT_SERVICES.FreePool().
> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> +                                status to report back to the ESRT table in case
> +                                of error. This value will only be checked when this
> +                                function returns an error.
> 
> -  @retval EFI_SUCCESS            The device was successfully updated with the
> -                                 new image.
> -  @retval EFI_ABORTED            The operation is aborted.
> +                                The return status code must fall in the range of
> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> +
> +                                If the value falls outside this range, it will be converted
> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> +
> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> +                                 with the new firmware image.
> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> +                                 are provided in AbortReason.
>    @retval EFI_INVALID_PARAMETER  The Image was NULL.
> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>    @retval EFI_UNSUPPORTED        The operation is not supported.
> 
>  **/
>  EFI_STATUS
>  EFIAPI
> -FmpDeviceSetImage (
> +FmpDeviceSetImageWithStatus (
>    IN  CONST VOID                                     *Image,
>    IN  UINTN                                          ImageSize,
> -  IN  CONST VOID                                     *VendorCode,
> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
>    IN  UINT32                                         CapsuleFwVersion,
> -  OUT CHAR16                                         **AbortReason
> +  OUT CHAR16                                         **AbortReason,
> +  OUT UINT32                                         *LastAttemptStatus
>    )
>  {
>    EFI_STATUS          Status;
> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
>    UINTN               BytesWritten;
> 
>    Updateable = 0;
> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
>    if (EFI_ERROR (Status)) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with %r.\n", Status));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image failed with %r.\n", Status));
>      return Status;
>    }
> 
>    if (Updateable != IMAGE_UPDATABLE_VALID) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned that the Image was not valid for update.  Updatable
> value = 0x%X.\n", Updateable));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image returned that the Image was not valid for update.
> Updatable value = 0x%X.\n", Updateable));
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>      return EFI_ABORTED;
>    }
> 
>    if (Progress == NULL) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress callback\n"));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>      return EFI_INVALID_PARAMETER;
>    }
> 
>    Status = Progress (15);
>    if (EFI_ERROR (Status)) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>    }
> 
>    //
> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
>    //
>    Progress (20);
>    if (EFI_ERROR (Status)) {
> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>    }
> 
>    //
> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
> 
>  //    Progress (Percentage);
>  //    if (EFI_ERROR (Status)) {
> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>  //    }
>    }
> 
> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> 
>    if (ARRAY_SIZE (mUpdateConfigData) == 0) {
>      DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
>      BytesWritten += ConfigData->Length;
>    }
> 
> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
> +
> +  if (EFI_ERROR (Status)) {
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +  }
> 
>    return Status;
>  }
> 
> +/**
> +  Updates the firmware image of the device.
> +
> +  This function updates the hardware with the new firmware image.  This function
> +  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> +  firmware image is updatable, the function should perform the following minimal
> +  validations before proceeding to do the firmware image update.
> +    - Validate the image is a supported image for this device.  The function
> +      returns EFI_ABORTED if the image is unsupported.  The function can
> +      optionally provide more detailed information on why the image is not a
> +      supported image.
> +    - Validate the data from VendorCode if not null.  Image validation must be
> +      performed before VendorCode data validation.  VendorCode data is ignored
> +      or considered invalid if image validation failed.  The function returns
> +      EFI_ABORTED if the data is invalid.
> +
> +  VendorCode enables vendor to implement vendor-specific firmware image update
> +  policy.  Null if the caller did not specify the policy or use the default
> +  policy.  As an example, vendor can implement a policy to allow an option to
> +  force a firmware image update when the abort reason is due to the new firmware
> +  image version is older than the current firmware image version or bad image
> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> +  and render the device to be non-functional should be encoded in the image
> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> +  have the option to provide a more detailed description of the abort reason to
> +  the caller.
> +
> +  @param[in]  Image             Points to the new image.
> +  @param[in]  ImageSize         Size of the new image in bytes.
> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> +                                firmware image update policy. Null indicates the
> +                                caller did not specify the policy or use the
> +                                default policy.
> +  @param[in]  Progress          A function used by the driver to report the
> +                                progress of the firmware update.
> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> +  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> +                                string providing more details for the aborted
> +                                operation. The buffer is allocated by this
> +                                function with AllocatePool(), and it is the
> +                                caller's responsibility to free it with a call
> +                                to FreePool().
> +
> +  @retval EFI_SUCCESS            The device was successfully updated with the
> +                                 new image.
> +  @retval EFI_ABORTED            The operation is aborted.
> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FmpDeviceSetImage (
> +  IN  CONST VOID                                     *Image,
> +  IN  UINTN                                          ImageSize,
> +  IN  CONST VOID                                     *VendorCode,
> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> +  IN  UINT32                                         CapsuleFwVersion,
> +  OUT CHAR16                                         **AbortReason
> +  )
> +{
> +  UINT32  LastAttemptStatus;
> +
> +  return  FmpDeviceSetImageWithStatus (
> +            Image,
> +            ImageSize,
> +            VendorCode,
> +            Progress,
> +            CapsuleFwVersion,
> +            AbortReason,
> +            &LastAttemptStatus
> +            );
> +}
> +
> +/**
> +  Checks if a new firmware image is valid for the firmware device.  This
> +  function allows firmware update operation to validate the firmware image
> +  before FmpDeviceSetImage() is called.
> +
> +  @param[in]  Image               Points to a new firmware image.
> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> +                                  a firmware update to the firmware device.  The
> +                                  following values from the Firmware Management
> +                                  Protocol are supported:
> +                                    IMAGE_UPDATABLE_VALID
> +                                    IMAGE_UPDATABLE_INVALID
> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> +                                    IMAGE_UPDATABLE_INVALID_OLD
> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> +                                  status to report back to the ESRT table in case
> +                                  of error. This value will only be checked when this
> +                                  function returns an error.
> +
> +                                  The return status code must fall in the range of
> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> +
> +                                  If the value falls outside this range, it will be converted
> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> +
> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> +                                 status information is returned in
> +                                 ImageUpdatable.
> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FmpDeviceCheckImageWithStatus (
> +  IN  CONST VOID  *Image,
> +  IN  UINTN       ImageSize,
> +  OUT UINT32      *ImageUpdatable,
> +  OUT UINT32      *LastAttemptStatus
> +  )
> +{
> +  if (LastAttemptStatus == NULL) {
> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> +
> +  if (ImageUpdatable == NULL) {
> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  //Set to valid and then if any tests fail it will update this flag.
> +  //
> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> +
> +  if (Image == NULL) {
> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> +    //
> +    // Not sure if this is needed
> +    //
> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Make sure the image size is correct
> +  //
> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
>  /**
>  Checks if the firmware image is valid for the device.
> 
> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
>    OUT UINT32      *ImageUpdateable
>    )
>  {
> -  if (ImageUpdateable == NULL) {
> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> -    return EFI_INVALID_PARAMETER;
> -  }
> +  UINT32  LastAttemptStatus;
> 
> -  //
> -  //Set to valid and then if any tests fail it will update this flag.
> -  //
> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> -
> -  if (Image == NULL) {
> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> -    //
> -    // Not sure if this is needed
> -    //
> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> -    return EFI_INVALID_PARAMETER;
> -  }
> -
> -  //
> -  // Make sure the image size is correct
> -  //
> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> -    return EFI_INVALID_PARAMETER;
> -  }
> -
> -  return EFI_SUCCESS;
> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
>  }
> 
>  /**
> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> index db0f238ea534..132b60844ad4 100644
> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> @@ -1,6 +1,6 @@
>  /**
> 
> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
> +Copyright (c) Microsoft Corporation.<BR>
>  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> 
>  SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> 
>  #include <PiDxe.h>
> +#include <LastAttemptStatus.h>
> +#include <Guid/SystemResourceTable.h>
>  #include <Library/DebugLib.h>
>  #include <Protocol/FirmwareManagement.h>
>  #include <Library/BaseLib.h>
> @@ -345,6 +347,131 @@ Return Value:
>  }//GetImage()
> 
> 
> +/**
> +  Updates a firmware device with a new firmware image.  This function returns
> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> +  is updatable, the function should perform the following minimal validations
> +  before proceeding to do the firmware image update.
> +    - Validate that the image is a supported image for this firmware device.
> +      Return EFI_ABORTED if the image is not supported.  Additional details
> +      on why the image is not a supported image may be returned in AbortReason.
> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> +      validation must be performed before VendorCode data validation.
> +      VendorCode data is ignored or considered invalid if image validation
> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> +
> +  VendorCode enables vendor to implement vendor-specific firmware image update
> +  policy.  Null if the caller did not specify the policy or use the default
> +  policy.  As an example, vendor can implement a policy to allow an option to
> +  force a firmware image update when the abort reason is due to the new firmware
> +  image version is older than the current firmware image version or bad image
> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> +  and render the device to be non-functional should be encoded in the image
> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> +  have the option to provide a more detailed description of the abort reason to
> +  the caller.
> +
> +  @param[in]  Image             Points to the new firmware image.
> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> +                                firmware image update policy.  NULL indicates
> +                                the caller did not specify the policy or use the
> +                                default policy.
> +  @param[in]  Progress          A function used to report the progress of
> +                                updating the firmware device with the new
> +                                firmware image.
> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> +                                update capsule that provided the new firmware
> +                                image.
> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> +                                Unicode string providing more details on an
> +                                aborted operation. The buffer is allocated by
> +                                this function with
> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> +                                caller's responsibility to free this buffer with
> +                                EFI_BOOT_SERVICES.FreePool().
> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> +                                status to report back to the ESRT table in case
> +                                of error. This value will only be checked when this
> +                                function returns an error.
> +
> +                                The return status code must fall in the range of
> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> +
> +                                If the value falls outside this range, it will be converted
> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> +
> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> +                                 with the new firmware image.
> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> +                                 are provided in AbortReason.
> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FmpDeviceSetImageWithStatus (
> +  IN  CONST VOID                                     *Image,
> +  IN  UINTN                                          ImageSize,
> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
> +  IN  UINT32                                         CapsuleFwVersion,
> +  OUT CHAR16                                         **AbortReason,
> +  OUT UINT32                                         *LastAttemptStatus
> +  )
> +{
> +    EFI_STATUS Status                         = EFI_SUCCESS;
> +    UINT32 Updateable                         = 0;
> +
> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
> +    if (EFI_ERROR(Status))
> +    {
> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed with %r.\n", Status));
> +        goto cleanup;
> +    }
> +
> +    if (Updateable != IMAGE_UPDATABLE_VALID)
> +    {
> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image returned that the Image was not valid for update.
> Updatable value = 0x%X.\n", Updateable));
> +        Status = EFI_ABORTED;
> +        goto cleanup;
> +    }
> +
> +    if (Progress == NULL)
> +    {
> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress callback\n"));
> +        Status = EFI_INVALID_PARAMETER;
> +        goto cleanup;
> +    }
> +
> +    Status = Progress(15);
> +    if (EFI_ERROR(Status))
> +    {
> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback failed with Status %r.\n", Status));
> +    }
> +
> +    {
> +      UINTN  p;
> +
> +      for (p = 20; p < 100; p++) {
> +        gBS->Stall (100000);  //us  = 0.1 seconds
> +        Progress (p);
> +      }
> +    }
> +
> +    //TODO: add support for VendorCode, and AbortReason
> +cleanup:
> +    if (EFI_ERROR (Status)) {
> +      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +    }
> +
> +    return Status;
> +}// SetImageWithStatus()
> +
> +
>  /**
>  Updates the firmware image of the device.
> 
> @@ -396,51 +523,98 @@ IN  UINT32                                           CapsuleFwVersion,
>  OUT CHAR16                                           **AbortReason
>  )
>  {
> -    EFI_STATUS Status                         = EFI_SUCCESS;
> -    UINT32 Updateable                         = 0;
> -
> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
> -    if (EFI_ERROR(Status))
> -    {
> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with %r.\n", Status));
> -        goto cleanup;
> -    }
> -
> -    if (Updateable != IMAGE_UPDATABLE_VALID)
> -    {
> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the Image was not valid for update.  Updatable value =
> 0x%X.\n", Updateable));
> -        Status = EFI_ABORTED;
> -        goto cleanup;
> -    }
> -
> -    if (Progress == NULL)
> -    {
> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
> -        Status = EFI_INVALID_PARAMETER;
> -        goto cleanup;
> -    }
> -
> -    Status = Progress(15);
> -    if (EFI_ERROR(Status))
> -    {
> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with Status %r.\n", Status));
> -    }
> -
> -    {
> -      UINTN  p;
> -
> -      for (p = 20; p < 100; p++) {
> -        gBS->Stall (100000);  //us  = 0.1 seconds
> -        Progress (p);
> -      }
> -    }
> -
> -    //TODO: add support for VendorCode, and AbortReason
> -cleanup:
> -    return Status;
> +  UINT32  LastAttemptStatus;
> +
> +  return  FmpDeviceSetImageWithStatus (
> +            Image,
> +            ImageSize,
> +            VendorCode,
> +            Progress,
> +            CapsuleFwVersion,
> +            AbortReason,
> +            &LastAttemptStatus
> +            );
>  }// SetImage()
> 
> 
> +/**
> +  Checks if a new firmware image is valid for the firmware device.  This
> +  function allows firmware update operation to validate the firmware image
> +  before FmpDeviceSetImage() is called.
> +
> +  @param[in]  Image               Points to a new firmware image.
> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> +                                  a firmware update to the firmware device.  The
> +                                  following values from the Firmware Management
> +                                  Protocol are supported:
> +                                    IMAGE_UPDATABLE_VALID
> +                                    IMAGE_UPDATABLE_INVALID
> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> +                                    IMAGE_UPDATABLE_INVALID_OLD
> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> +                                  status to report back to the ESRT table in case
> +                                  of error. This value will only be checked when this
> +                                  function returns an error.
> +
> +                                  The return status code must fall in the range of
> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> +
> +                                  If the value falls outside this range, it will be converted
> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> +
> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> +                                 status information is returned in
> +                                 ImageUpdatable.
> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FmpDeviceCheckImageWithStatus (
> +  IN  CONST VOID  *Image,
> +  IN  UINTN       ImageSize,
> +  OUT UINT32      *ImageUpdatable,
> +  OUT UINT32      *LastAttemptStatus
> +  )
> +{
> +    EFI_STATUS status = EFI_SUCCESS;
> +
> +    if (LastAttemptStatus == NULL) {
> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> +
> +    if (ImageUpdatable == NULL)
> +    {
> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +        status = EFI_INVALID_PARAMETER;
> +        goto cleanup;
> +    }
> +
> +    //
> +    //Set to valid and then if any tests fail it will update this flag.
> +    //
> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> +
> +    if (Image == NULL)
> +    {
> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> +        return EFI_INVALID_PARAMETER;
> +    }
> +
> +cleanup:
> +    return status;
> +}// CheckImageWithStatus()
> +
> 
>  /**
>  Checks if the firmware image is valid for the device.
> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
>  OUT UINT32                            *ImageUpdateable
>  )
>  {
> -    EFI_STATUS status = EFI_SUCCESS;
> +  UINT32  LastAttemptStatus;
> 
> -    if (ImageUpdateable == NULL)
> -    {
> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> -        status = EFI_INVALID_PARAMETER;
> -        goto cleanup;
> -    }
> -
> -    //
> -    //Set to valid and then if any tests fail it will update this flag.
> -    //
> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> -
> -    if (Image == NULL)
> -    {
> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> -        return EFI_INVALID_PARAMETER;
> -    }
> -
> -cleanup:
> -    return status;
> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
>  }// CheckImage()
> 
>  /**
> --
> 2.28.0.windows.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
  2020-10-29  1:12 ` Michael D Kinney
@ 2020-10-29  4:45   ` Michael Kubacki
  2020-11-05 20:36   ` Michael Kubacki
  1 sibling, 0 replies; 10+ messages in thread
From: Michael Kubacki @ 2020-10-29  4:45 UTC (permalink / raw)
  To: Kinney, Michael D, devel@edk2.groups.io; +Cc: Qian, Yi, Sun, Zailiang

Thank you for the test confirmation.

Regards,
Michael

On 10/28/2020 6:12 PM, Kinney, Michael D wrote:
> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
> 
> I also verified build and boot and FMP based capsule updates work as expected.
> 
> Tested-by: Michael D Kinney <Michael.d.kinney@intel.com>
> 
> Thanks,
> 
> Mike
> 
> 
>> -----Original Message-----
>> From: michael.kubacki@outlook.com <michael.kubacki@outlook.com>
>> Sent: Thursday, October 1, 2020 2:59 PM
>> To: devel@edk2.groups.io
>> Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Qian, Yi <yi.qian@intel.com>; Sun, Zailiang <zailiang.sun@intel.com>
>> Subject: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
>>
>> From: Michael Kubacki <michael.kubacki@microsoft.com>
>>
>> Makes the changes necessary for these library instances of
>> FmpDeviceLib to be compatible with new functions added recently
>> to FmpDeviceLib.
>>
>> Two new functions were introduced in FmpDeviceLib to allow a
>> library instance to return a Last Attempt Status code during
>> check image and set image operations:
>>    1. FmpDeviceCheckImageWithStatus ( )
>>    2. FmpDeviceSetImageWithStatus ( )
>>
>> FmpDxe (in FmpDevicePkg) will begin calling these new functions
>> instead of the previous functions. Therefore, this change:
>>    1. Adds these functions to Vlv2TbltDevicePkg implementations
>>    2. Moves the main functionality to these new functions
>>    3. Updates the old functions to call the new functions
>>       (for backward compatibility)
>>
>> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
>> due to:
>>    1. A required RngLib library instance not defined by the platform
>>    2. Other FMP libraries not being defined by the platform
>>       (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
>>
>> Those changes were fixed locally to test the changes in this commit
>> but maintainers should make the proper changes for those issues.
>>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Yi Qian <yi.qian@intel.com>
>> Cc: Zailiang Sun <zailiang.sun@intel.com>
>> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
>> ---
>>
>> Notes:
>>      Only build was checked, I do not have access to a
>>      VLV2 device for testing.
>>
>>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       | 299 +++++++++++++++-----
>>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c | 284 ++++++++++++++-----
>>   2 files changed, 446 insertions(+), 137 deletions(-)
>>
>> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>> index d8c9036012ad..df8a36d9854c 100644
>> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>> @@ -1,6 +1,6 @@
>>   /**
>>
>> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
>> +Copyright (c) Microsoft Corporation.<BR>
>>   Copyright (c) 2019, Intel Corporation.  All rights reserved.
>>
>>   SPDX-License-Identifier: BSD-2-Clause-Patent
>> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>>   **/
>>
>>   #include <PiDxe.h>
>> -
>> +#include <LastAttemptStatus.h>
>> +#include <Guid/SystemResourceTable.h>
>>   #include <Library/FmpDeviceLib.h>
>>
>>   #include <Library/DebugLib.h>
>> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
>>   }
>>
>>   /**
>> -  Updates the firmware image of the device.
>> -
>> -  This function updates the hardware with the new firmware image.  This function
>> -  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
>> -  firmware image is updatable, the function should perform the following minimal
>> -  validations before proceeding to do the firmware image update.
>> -    - Validate the image is a supported image for this device.  The function
>> -      returns EFI_ABORTED if the image is unsupported.  The function can
>> -      optionally provide more detailed information on why the image is not a
>> -      supported image.
>> -    - Validate the data from VendorCode if not null.  Image validation must be
>> -      performed before VendorCode data validation.  VendorCode data is ignored
>> -      or considered invalid if image validation failed.  The function returns
>> -      EFI_ABORTED if the data is invalid.
>> +  Updates a firmware device with a new firmware image.  This function returns
>> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
>> +  is updatable, the function should perform the following minimal validations
>> +  before proceeding to do the firmware image update.
>> +    - Validate that the image is a supported image for this firmware device.
>> +      Return EFI_ABORTED if the image is not supported.  Additional details
>> +      on why the image is not a supported image may be returned in AbortReason.
>> +    - Validate the data from VendorCode if is not NULL.  Firmware image
>> +      validation must be performed before VendorCode data validation.
>> +      VendorCode data is ignored or considered invalid if image validation
>> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>>
>>     VendorCode enables vendor to implement vendor-specific firmware image update
>>     policy.  Null if the caller did not specify the policy or use the default
>> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
>>     have the option to provide a more detailed description of the abort reason to
>>     the caller.
>>
>> -  @param[in]  Image             Points to the new image.
>> -  @param[in]  ImageSize         Size of the new image in bytes.
>> +  @param[in]  Image             Points to the new firmware image.
>> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
>>     @param[in]  VendorCode        This enables vendor to implement vendor-specific
>> -                                firmware image update policy. Null indicates the
>> -                                caller did not specify the policy or use the
>> +                                firmware image update policy.  NULL indicates
>> +                                the caller did not specify the policy or use the
>>                                   default policy.
>> -  @param[in]  Progress          A function used by the driver to report the
>> -                                progress of the firmware update.
>> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
>> -  @param[out] AbortReason       A pointer to a pointer to a null-terminated
>> -                                string providing more details for the aborted
>> -                                operation. The buffer is allocated by this
>> -                                function with AllocatePool(), and it is the
>> -                                caller's responsibility to free it with a call
>> -                                to FreePool().
>> +  @param[in]  Progress          A function used to report the progress of
>> +                                updating the firmware device with the new
>> +                                firmware image.
>> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
>> +                                update capsule that provided the new firmware
>> +                                image.
>> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
>> +                                Unicode string providing more details on an
>> +                                aborted operation. The buffer is allocated by
>> +                                this function with
>> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
>> +                                caller's responsibility to free this buffer with
>> +                                EFI_BOOT_SERVICES.FreePool().
>> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
>> +                                status to report back to the ESRT table in case
>> +                                of error. This value will only be checked when this
>> +                                function returns an error.
>>
>> -  @retval EFI_SUCCESS            The device was successfully updated with the
>> -                                 new image.
>> -  @retval EFI_ABORTED            The operation is aborted.
>> +                                The return status code must fall in the range of
>> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                If the value falls outside this range, it will be converted
>> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The firmware device was successfully updated
>> +                                 with the new firmware image.
>> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
>> +                                 are provided in AbortReason.
>>     @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>>     @retval EFI_UNSUPPORTED        The operation is not supported.
>>
>>   **/
>>   EFI_STATUS
>>   EFIAPI
>> -FmpDeviceSetImage (
>> +FmpDeviceSetImageWithStatus (
>>     IN  CONST VOID                                     *Image,
>>     IN  UINTN                                          ImageSize,
>> -  IN  CONST VOID                                     *VendorCode,
>> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
>> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
>>     IN  UINT32                                         CapsuleFwVersion,
>> -  OUT CHAR16                                         **AbortReason
>> +  OUT CHAR16                                         **AbortReason,
>> +  OUT UINT32                                         *LastAttemptStatus
>>     )
>>   {
>>     EFI_STATUS          Status;
>> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
>>     UINTN               BytesWritten;
>>
>>     Updateable = 0;
>> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
>> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image failed with %r.\n", Status));
>>       return Status;
>>     }
>>
>>     if (Updateable != IMAGE_UPDATABLE_VALID) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned that the Image was not valid for update.  Updatable
>> value = 0x%X.\n", Updateable));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image returned that the Image was not valid for update.
>> Updatable value = 0x%X.\n", Updateable));
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>>       return EFI_ABORTED;
>>     }
>>
>>     if (Progress == NULL) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress callback\n"));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>>       return EFI_INVALID_PARAMETER;
>>     }
>>
>>     Status = Progress (15);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>>     }
>>
>>     //
>> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
>>     //
>>     Progress (20);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>>     }
>>
>>     //
>> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
>>
>>   //    Progress (Percentage);
>>   //    if (EFI_ERROR (Status)) {
>> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
>> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>>   //    }
>>     }
>>
>> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
>> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
>>
>>     if (ARRAY_SIZE (mUpdateConfigData) == 0) {
>>       DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
>> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
>>       BytesWritten += ConfigData->Length;
>>     }
>>
>> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
>> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +  }
>>
>>     return Status;
>>   }
>>
>> +/**
>> +  Updates the firmware image of the device.
>> +
>> +  This function updates the hardware with the new firmware image.  This function
>> +  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
>> +  firmware image is updatable, the function should perform the following minimal
>> +  validations before proceeding to do the firmware image update.
>> +    - Validate the image is a supported image for this device.  The function
>> +      returns EFI_ABORTED if the image is unsupported.  The function can
>> +      optionally provide more detailed information on why the image is not a
>> +      supported image.
>> +    - Validate the data from VendorCode if not null.  Image validation must be
>> +      performed before VendorCode data validation.  VendorCode data is ignored
>> +      or considered invalid if image validation failed.  The function returns
>> +      EFI_ABORTED if the data is invalid.
>> +
>> +  VendorCode enables vendor to implement vendor-specific firmware image update
>> +  policy.  Null if the caller did not specify the policy or use the default
>> +  policy.  As an example, vendor can implement a policy to allow an option to
>> +  force a firmware image update when the abort reason is due to the new firmware
>> +  image version is older than the current firmware image version or bad image
>> +  checksum.  Sensitive operations such as those wiping the entire firmware image
>> +  and render the device to be non-functional should be encoded in the image
>> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
>> +  have the option to provide a more detailed description of the abort reason to
>> +  the caller.
>> +
>> +  @param[in]  Image             Points to the new image.
>> +  @param[in]  ImageSize         Size of the new image in bytes.
>> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
>> +                                firmware image update policy. Null indicates the
>> +                                caller did not specify the policy or use the
>> +                                default policy.
>> +  @param[in]  Progress          A function used by the driver to report the
>> +                                progress of the firmware update.
>> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
>> +  @param[out] AbortReason       A pointer to a pointer to a null-terminated
>> +                                string providing more details for the aborted
>> +                                operation. The buffer is allocated by this
>> +                                function with AllocatePool(), and it is the
>> +                                caller's responsibility to free it with a call
>> +                                to FreePool().
>> +
>> +  @retval EFI_SUCCESS            The device was successfully updated with the
>> +                                 new image.
>> +  @retval EFI_ABORTED            The operation is aborted.
>> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_UNSUPPORTED        The operation is not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceSetImage (
>> +  IN  CONST VOID                                     *Image,
>> +  IN  UINTN                                          ImageSize,
>> +  IN  CONST VOID                                     *VendorCode,
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
>> +  IN  UINT32                                         CapsuleFwVersion,
>> +  OUT CHAR16                                         **AbortReason
>> +  )
>> +{
>> +  UINT32  LastAttemptStatus;
>> +
>> +  return  FmpDeviceSetImageWithStatus (
>> +            Image,
>> +            ImageSize,
>> +            VendorCode,
>> +            Progress,
>> +            CapsuleFwVersion,
>> +            AbortReason,
>> +            &LastAttemptStatus
>> +            );
>> +}
>> +
>> +/**
>> +  Checks if a new firmware image is valid for the firmware device.  This
>> +  function allows firmware update operation to validate the firmware image
>> +  before FmpDeviceSetImage() is called.
>> +
>> +  @param[in]  Image               Points to a new firmware image.
>> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
>> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
>> +                                  a firmware update to the firmware device.  The
>> +                                  following values from the Firmware Management
>> +                                  Protocol are supported:
>> +                                    IMAGE_UPDATABLE_VALID
>> +                                    IMAGE_UPDATABLE_INVALID
>> +                                    IMAGE_UPDATABLE_INVALID_TYPE
>> +                                    IMAGE_UPDATABLE_INVALID_OLD
>> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
>> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
>> +                                  status to report back to the ESRT table in case
>> +                                  of error. This value will only be checked when this
>> +                                  function returns an error.
>> +
>> +                                  The return status code must fall in the range of
>> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                  If the value falls outside this range, it will be converted
>> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
>> +                                 status information is returned in
>> +                                 ImageUpdatable.
>> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
>> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceCheckImageWithStatus (
>> +  IN  CONST VOID  *Image,
>> +  IN  UINTN       ImageSize,
>> +  OUT UINT32      *ImageUpdatable,
>> +  OUT UINT32      *LastAttemptStatus
>> +  )
>> +{
>> +  if (LastAttemptStatus == NULL) {
>> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
>> +
>> +  if (ImageUpdatable == NULL) {
>> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  //
>> +  //Set to valid and then if any tests fail it will update this flag.
>> +  //
>> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
>> +
>> +  if (Image == NULL) {
>> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
>> +    //
>> +    // Not sure if this is needed
>> +    //
>> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  //
>> +  // Make sure the image size is correct
>> +  //
>> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
>> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>>   /**
>>   Checks if the firmware image is valid for the device.
>>
>> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
>>     OUT UINT32      *ImageUpdateable
>>     )
>>   {
>> -  if (ImageUpdateable == NULL) {
>> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> +  UINT32  LastAttemptStatus;
>>
>> -  //
>> -  //Set to valid and then if any tests fail it will update this flag.
>> -  //
>> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
>> -
>> -  if (Image == NULL) {
>> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
>> -    //
>> -    // Not sure if this is needed
>> -    //
>> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> -
>> -  //
>> -  // Make sure the image size is correct
>> -  //
>> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
>> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> -
>> -  return EFI_SUCCESS;
>> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
>>   }
>>
>>   /**
>> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>> index db0f238ea534..132b60844ad4 100644
>> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>> @@ -1,6 +1,6 @@
>>   /**
>>
>> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
>> +Copyright (c) Microsoft Corporation.<BR>
>>   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>>
>>   SPDX-License-Identifier: BSD-2-Clause-Patent
>> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>>
>>
>>   #include <PiDxe.h>
>> +#include <LastAttemptStatus.h>
>> +#include <Guid/SystemResourceTable.h>
>>   #include <Library/DebugLib.h>
>>   #include <Protocol/FirmwareManagement.h>
>>   #include <Library/BaseLib.h>
>> @@ -345,6 +347,131 @@ Return Value:
>>   }//GetImage()
>>
>>
>> +/**
>> +  Updates a firmware device with a new firmware image.  This function returns
>> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
>> +  is updatable, the function should perform the following minimal validations
>> +  before proceeding to do the firmware image update.
>> +    - Validate that the image is a supported image for this firmware device.
>> +      Return EFI_ABORTED if the image is not supported.  Additional details
>> +      on why the image is not a supported image may be returned in AbortReason.
>> +    - Validate the data from VendorCode if is not NULL.  Firmware image
>> +      validation must be performed before VendorCode data validation.
>> +      VendorCode data is ignored or considered invalid if image validation
>> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>> +
>> +  VendorCode enables vendor to implement vendor-specific firmware image update
>> +  policy.  Null if the caller did not specify the policy or use the default
>> +  policy.  As an example, vendor can implement a policy to allow an option to
>> +  force a firmware image update when the abort reason is due to the new firmware
>> +  image version is older than the current firmware image version or bad image
>> +  checksum.  Sensitive operations such as those wiping the entire firmware image
>> +  and render the device to be non-functional should be encoded in the image
>> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
>> +  have the option to provide a more detailed description of the abort reason to
>> +  the caller.
>> +
>> +  @param[in]  Image             Points to the new firmware image.
>> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
>> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
>> +                                firmware image update policy.  NULL indicates
>> +                                the caller did not specify the policy or use the
>> +                                default policy.
>> +  @param[in]  Progress          A function used to report the progress of
>> +                                updating the firmware device with the new
>> +                                firmware image.
>> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
>> +                                update capsule that provided the new firmware
>> +                                image.
>> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
>> +                                Unicode string providing more details on an
>> +                                aborted operation. The buffer is allocated by
>> +                                this function with
>> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
>> +                                caller's responsibility to free this buffer with
>> +                                EFI_BOOT_SERVICES.FreePool().
>> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
>> +                                status to report back to the ESRT table in case
>> +                                of error. This value will only be checked when this
>> +                                function returns an error.
>> +
>> +                                The return status code must fall in the range of
>> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                If the value falls outside this range, it will be converted
>> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The firmware device was successfully updated
>> +                                 with the new firmware image.
>> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
>> +                                 are provided in AbortReason.
>> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>> +  @retval EFI_UNSUPPORTED        The operation is not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceSetImageWithStatus (
>> +  IN  CONST VOID                                     *Image,
>> +  IN  UINTN                                          ImageSize,
>> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
>> +  IN  UINT32                                         CapsuleFwVersion,
>> +  OUT CHAR16                                         **AbortReason,
>> +  OUT UINT32                                         *LastAttemptStatus
>> +  )
>> +{
>> +    EFI_STATUS Status                         = EFI_SUCCESS;
>> +    UINT32 Updateable                         = 0;
>> +
>> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
>> +    if (EFI_ERROR(Status))
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed with %r.\n", Status));
>> +        goto cleanup;
>> +    }
>> +
>> +    if (Updateable != IMAGE_UPDATABLE_VALID)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image returned that the Image was not valid for update.
>> Updatable value = 0x%X.\n", Updateable));
>> +        Status = EFI_ABORTED;
>> +        goto cleanup;
>> +    }
>> +
>> +    if (Progress == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress callback\n"));
>> +        Status = EFI_INVALID_PARAMETER;
>> +        goto cleanup;
>> +    }
>> +
>> +    Status = Progress(15);
>> +    if (EFI_ERROR(Status))
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback failed with Status %r.\n", Status));
>> +    }
>> +
>> +    {
>> +      UINTN  p;
>> +
>> +      for (p = 20; p < 100; p++) {
>> +        gBS->Stall (100000);  //us  = 0.1 seconds
>> +        Progress (p);
>> +      }
>> +    }
>> +
>> +    //TODO: add support for VendorCode, and AbortReason
>> +cleanup:
>> +    if (EFI_ERROR (Status)) {
>> +      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    }
>> +
>> +    return Status;
>> +}// SetImageWithStatus()
>> +
>> +
>>   /**
>>   Updates the firmware image of the device.
>>
>> @@ -396,51 +523,98 @@ IN  UINT32                                           CapsuleFwVersion,
>>   OUT CHAR16                                           **AbortReason
>>   )
>>   {
>> -    EFI_STATUS Status                         = EFI_SUCCESS;
>> -    UINT32 Updateable                         = 0;
>> -
>> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
>> -    if (EFI_ERROR(Status))
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with %r.\n", Status));
>> -        goto cleanup;
>> -    }
>> -
>> -    if (Updateable != IMAGE_UPDATABLE_VALID)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the Image was not valid for update.  Updatable value =
>> 0x%X.\n", Updateable));
>> -        Status = EFI_ABORTED;
>> -        goto cleanup;
>> -    }
>> -
>> -    if (Progress == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
>> -        Status = EFI_INVALID_PARAMETER;
>> -        goto cleanup;
>> -    }
>> -
>> -    Status = Progress(15);
>> -    if (EFI_ERROR(Status))
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with Status %r.\n", Status));
>> -    }
>> -
>> -    {
>> -      UINTN  p;
>> -
>> -      for (p = 20; p < 100; p++) {
>> -        gBS->Stall (100000);  //us  = 0.1 seconds
>> -        Progress (p);
>> -      }
>> -    }
>> -
>> -    //TODO: add support for VendorCode, and AbortReason
>> -cleanup:
>> -    return Status;
>> +  UINT32  LastAttemptStatus;
>> +
>> +  return  FmpDeviceSetImageWithStatus (
>> +            Image,
>> +            ImageSize,
>> +            VendorCode,
>> +            Progress,
>> +            CapsuleFwVersion,
>> +            AbortReason,
>> +            &LastAttemptStatus
>> +            );
>>   }// SetImage()
>>
>>
>> +/**
>> +  Checks if a new firmware image is valid for the firmware device.  This
>> +  function allows firmware update operation to validate the firmware image
>> +  before FmpDeviceSetImage() is called.
>> +
>> +  @param[in]  Image               Points to a new firmware image.
>> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
>> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
>> +                                  a firmware update to the firmware device.  The
>> +                                  following values from the Firmware Management
>> +                                  Protocol are supported:
>> +                                    IMAGE_UPDATABLE_VALID
>> +                                    IMAGE_UPDATABLE_INVALID
>> +                                    IMAGE_UPDATABLE_INVALID_TYPE
>> +                                    IMAGE_UPDATABLE_INVALID_OLD
>> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
>> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
>> +                                  status to report back to the ESRT table in case
>> +                                  of error. This value will only be checked when this
>> +                                  function returns an error.
>> +
>> +                                  The return status code must fall in the range of
>> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                  If the value falls outside this range, it will be converted
>> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
>> +                                 status information is returned in
>> +                                 ImageUpdatable.
>> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
>> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceCheckImageWithStatus (
>> +  IN  CONST VOID  *Image,
>> +  IN  UINTN       ImageSize,
>> +  OUT UINT32      *ImageUpdatable,
>> +  OUT UINT32      *LastAttemptStatus
>> +  )
>> +{
>> +    EFI_STATUS status = EFI_SUCCESS;
>> +
>> +    if (LastAttemptStatus == NULL) {
>> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
>> +      return EFI_INVALID_PARAMETER;
>> +    }
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
>> +
>> +    if (ImageUpdatable == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
>> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +        status = EFI_INVALID_PARAMETER;
>> +        goto cleanup;
>> +    }
>> +
>> +    //
>> +    //Set to valid and then if any tests fail it will update this flag.
>> +    //
>> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
>> +
>> +    if (Image == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
>> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
>> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +        return EFI_INVALID_PARAMETER;
>> +    }
>> +
>> +cleanup:
>> +    return status;
>> +}// CheckImageWithStatus()
>> +
>>
>>   /**
>>   Checks if the firmware image is valid for the device.
>> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
>>   OUT UINT32                            *ImageUpdateable
>>   )
>>   {
>> -    EFI_STATUS status = EFI_SUCCESS;
>> +  UINT32  LastAttemptStatus;
>>
>> -    if (ImageUpdateable == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
>> -        status = EFI_INVALID_PARAMETER;
>> -        goto cleanup;
>> -    }
>> -
>> -    //
>> -    //Set to valid and then if any tests fail it will update this flag.
>> -    //
>> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
>> -
>> -    if (Image == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
>> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
>> -        return EFI_INVALID_PARAMETER;
>> -    }
>> -
>> -cleanup:
>> -    return status;
>> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
>>   }// CheckImage()
>>
>>   /**
>> --
>> 2.28.0.windows.1
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
  2020-10-29  1:12 ` Michael D Kinney
  2020-10-29  4:45   ` Michael Kubacki
@ 2020-11-05 20:36   ` Michael Kubacki
  2020-11-11  3:03     ` Michael D Kinney
  1 sibling, 1 reply; 10+ messages in thread
From: Michael Kubacki @ 2020-11-05 20:36 UTC (permalink / raw)
  To: Kinney, Michael D, devel@edk2.groups.io; +Cc: Qian, Yi, Sun, Zailiang

Hi Mike,

I saw other Vlv2TbltDevicePkg patches were merged yesterday. Do you know 
when this patch will be merged?

Thanks,
Michael

On 10/28/2020 6:12 PM, Kinney, Michael D wrote:
> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
> 
> I also verified build and boot and FMP based capsule updates work as expected.
> 
> Tested-by: Michael D Kinney <Michael.d.kinney@intel.com>
> 
> Thanks,
> 
> Mike
> 
> 
>> -----Original Message-----
>> From: michael.kubacki@outlook.com <michael.kubacki@outlook.com>
>> Sent: Thursday, October 1, 2020 2:59 PM
>> To: devel@edk2.groups.io
>> Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Qian, Yi <yi.qian@intel.com>; Sun, Zailiang <zailiang.sun@intel.com>
>> Subject: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
>>
>> From: Michael Kubacki <michael.kubacki@microsoft.com>
>>
>> Makes the changes necessary for these library instances of
>> FmpDeviceLib to be compatible with new functions added recently
>> to FmpDeviceLib.
>>
>> Two new functions were introduced in FmpDeviceLib to allow a
>> library instance to return a Last Attempt Status code during
>> check image and set image operations:
>>    1. FmpDeviceCheckImageWithStatus ( )
>>    2. FmpDeviceSetImageWithStatus ( )
>>
>> FmpDxe (in FmpDevicePkg) will begin calling these new functions
>> instead of the previous functions. Therefore, this change:
>>    1. Adds these functions to Vlv2TbltDevicePkg implementations
>>    2. Moves the main functionality to these new functions
>>    3. Updates the old functions to call the new functions
>>       (for backward compatibility)
>>
>> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
>> due to:
>>    1. A required RngLib library instance not defined by the platform
>>    2. Other FMP libraries not being defined by the platform
>>       (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
>>
>> Those changes were fixed locally to test the changes in this commit
>> but maintainers should make the proper changes for those issues.
>>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Yi Qian <yi.qian@intel.com>
>> Cc: Zailiang Sun <zailiang.sun@intel.com>
>> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
>> ---
>>
>> Notes:
>>      Only build was checked, I do not have access to a
>>      VLV2 device for testing.
>>
>>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       | 299 +++++++++++++++-----
>>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c | 284 ++++++++++++++-----
>>   2 files changed, 446 insertions(+), 137 deletions(-)
>>
>> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>> index d8c9036012ad..df8a36d9854c 100644
>> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>> @@ -1,6 +1,6 @@
>>   /**
>>
>> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
>> +Copyright (c) Microsoft Corporation.<BR>
>>   Copyright (c) 2019, Intel Corporation.  All rights reserved.
>>
>>   SPDX-License-Identifier: BSD-2-Clause-Patent
>> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>>   **/
>>
>>   #include <PiDxe.h>
>> -
>> +#include <LastAttemptStatus.h>
>> +#include <Guid/SystemResourceTable.h>
>>   #include <Library/FmpDeviceLib.h>
>>
>>   #include <Library/DebugLib.h>
>> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
>>   }
>>
>>   /**
>> -  Updates the firmware image of the device.
>> -
>> -  This function updates the hardware with the new firmware image.  This function
>> -  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
>> -  firmware image is updatable, the function should perform the following minimal
>> -  validations before proceeding to do the firmware image update.
>> -    - Validate the image is a supported image for this device.  The function
>> -      returns EFI_ABORTED if the image is unsupported.  The function can
>> -      optionally provide more detailed information on why the image is not a
>> -      supported image.
>> -    - Validate the data from VendorCode if not null.  Image validation must be
>> -      performed before VendorCode data validation.  VendorCode data is ignored
>> -      or considered invalid if image validation failed.  The function returns
>> -      EFI_ABORTED if the data is invalid.
>> +  Updates a firmware device with a new firmware image.  This function returns
>> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
>> +  is updatable, the function should perform the following minimal validations
>> +  before proceeding to do the firmware image update.
>> +    - Validate that the image is a supported image for this firmware device.
>> +      Return EFI_ABORTED if the image is not supported.  Additional details
>> +      on why the image is not a supported image may be returned in AbortReason.
>> +    - Validate the data from VendorCode if is not NULL.  Firmware image
>> +      validation must be performed before VendorCode data validation.
>> +      VendorCode data is ignored or considered invalid if image validation
>> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>>
>>     VendorCode enables vendor to implement vendor-specific firmware image update
>>     policy.  Null if the caller did not specify the policy or use the default
>> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
>>     have the option to provide a more detailed description of the abort reason to
>>     the caller.
>>
>> -  @param[in]  Image             Points to the new image.
>> -  @param[in]  ImageSize         Size of the new image in bytes.
>> +  @param[in]  Image             Points to the new firmware image.
>> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
>>     @param[in]  VendorCode        This enables vendor to implement vendor-specific
>> -                                firmware image update policy. Null indicates the
>> -                                caller did not specify the policy or use the
>> +                                firmware image update policy.  NULL indicates
>> +                                the caller did not specify the policy or use the
>>                                   default policy.
>> -  @param[in]  Progress          A function used by the driver to report the
>> -                                progress of the firmware update.
>> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
>> -  @param[out] AbortReason       A pointer to a pointer to a null-terminated
>> -                                string providing more details for the aborted
>> -                                operation. The buffer is allocated by this
>> -                                function with AllocatePool(), and it is the
>> -                                caller's responsibility to free it with a call
>> -                                to FreePool().
>> +  @param[in]  Progress          A function used to report the progress of
>> +                                updating the firmware device with the new
>> +                                firmware image.
>> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
>> +                                update capsule that provided the new firmware
>> +                                image.
>> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
>> +                                Unicode string providing more details on an
>> +                                aborted operation. The buffer is allocated by
>> +                                this function with
>> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
>> +                                caller's responsibility to free this buffer with
>> +                                EFI_BOOT_SERVICES.FreePool().
>> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
>> +                                status to report back to the ESRT table in case
>> +                                of error. This value will only be checked when this
>> +                                function returns an error.
>>
>> -  @retval EFI_SUCCESS            The device was successfully updated with the
>> -                                 new image.
>> -  @retval EFI_ABORTED            The operation is aborted.
>> +                                The return status code must fall in the range of
>> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                If the value falls outside this range, it will be converted
>> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The firmware device was successfully updated
>> +                                 with the new firmware image.
>> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
>> +                                 are provided in AbortReason.
>>     @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>>     @retval EFI_UNSUPPORTED        The operation is not supported.
>>
>>   **/
>>   EFI_STATUS
>>   EFIAPI
>> -FmpDeviceSetImage (
>> +FmpDeviceSetImageWithStatus (
>>     IN  CONST VOID                                     *Image,
>>     IN  UINTN                                          ImageSize,
>> -  IN  CONST VOID                                     *VendorCode,
>> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
>> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
>>     IN  UINT32                                         CapsuleFwVersion,
>> -  OUT CHAR16                                         **AbortReason
>> +  OUT CHAR16                                         **AbortReason,
>> +  OUT UINT32                                         *LastAttemptStatus
>>     )
>>   {
>>     EFI_STATUS          Status;
>> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
>>     UINTN               BytesWritten;
>>
>>     Updateable = 0;
>> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
>> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image failed with %r.\n", Status));
>>       return Status;
>>     }
>>
>>     if (Updateable != IMAGE_UPDATABLE_VALID) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned that the Image was not valid for update.  Updatable
>> value = 0x%X.\n", Updateable));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image returned that the Image was not valid for update.
>> Updatable value = 0x%X.\n", Updateable));
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>>       return EFI_ABORTED;
>>     }
>>
>>     if (Progress == NULL) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress callback\n"));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>>       return EFI_INVALID_PARAMETER;
>>     }
>>
>>     Status = Progress (15);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>>     }
>>
>>     //
>> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
>>     //
>>     Progress (20);
>>     if (EFI_ERROR (Status)) {
>> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
>> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>>     }
>>
>>     //
>> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
>>
>>   //    Progress (Percentage);
>>   //    if (EFI_ERROR (Status)) {
>> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
>> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
>>   //    }
>>     }
>>
>> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
>> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
>>
>>     if (ARRAY_SIZE (mUpdateConfigData) == 0) {
>>       DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
>> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
>>       BytesWritten += ConfigData->Length;
>>     }
>>
>> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
>> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +  }
>>
>>     return Status;
>>   }
>>
>> +/**
>> +  Updates the firmware image of the device.
>> +
>> +  This function updates the hardware with the new firmware image.  This function
>> +  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
>> +  firmware image is updatable, the function should perform the following minimal
>> +  validations before proceeding to do the firmware image update.
>> +    - Validate the image is a supported image for this device.  The function
>> +      returns EFI_ABORTED if the image is unsupported.  The function can
>> +      optionally provide more detailed information on why the image is not a
>> +      supported image.
>> +    - Validate the data from VendorCode if not null.  Image validation must be
>> +      performed before VendorCode data validation.  VendorCode data is ignored
>> +      or considered invalid if image validation failed.  The function returns
>> +      EFI_ABORTED if the data is invalid.
>> +
>> +  VendorCode enables vendor to implement vendor-specific firmware image update
>> +  policy.  Null if the caller did not specify the policy or use the default
>> +  policy.  As an example, vendor can implement a policy to allow an option to
>> +  force a firmware image update when the abort reason is due to the new firmware
>> +  image version is older than the current firmware image version or bad image
>> +  checksum.  Sensitive operations such as those wiping the entire firmware image
>> +  and render the device to be non-functional should be encoded in the image
>> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
>> +  have the option to provide a more detailed description of the abort reason to
>> +  the caller.
>> +
>> +  @param[in]  Image             Points to the new image.
>> +  @param[in]  ImageSize         Size of the new image in bytes.
>> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
>> +                                firmware image update policy. Null indicates the
>> +                                caller did not specify the policy or use the
>> +                                default policy.
>> +  @param[in]  Progress          A function used by the driver to report the
>> +                                progress of the firmware update.
>> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
>> +  @param[out] AbortReason       A pointer to a pointer to a null-terminated
>> +                                string providing more details for the aborted
>> +                                operation. The buffer is allocated by this
>> +                                function with AllocatePool(), and it is the
>> +                                caller's responsibility to free it with a call
>> +                                to FreePool().
>> +
>> +  @retval EFI_SUCCESS            The device was successfully updated with the
>> +                                 new image.
>> +  @retval EFI_ABORTED            The operation is aborted.
>> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_UNSUPPORTED        The operation is not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceSetImage (
>> +  IN  CONST VOID                                     *Image,
>> +  IN  UINTN                                          ImageSize,
>> +  IN  CONST VOID                                     *VendorCode,
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
>> +  IN  UINT32                                         CapsuleFwVersion,
>> +  OUT CHAR16                                         **AbortReason
>> +  )
>> +{
>> +  UINT32  LastAttemptStatus;
>> +
>> +  return  FmpDeviceSetImageWithStatus (
>> +            Image,
>> +            ImageSize,
>> +            VendorCode,
>> +            Progress,
>> +            CapsuleFwVersion,
>> +            AbortReason,
>> +            &LastAttemptStatus
>> +            );
>> +}
>> +
>> +/**
>> +  Checks if a new firmware image is valid for the firmware device.  This
>> +  function allows firmware update operation to validate the firmware image
>> +  before FmpDeviceSetImage() is called.
>> +
>> +  @param[in]  Image               Points to a new firmware image.
>> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
>> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
>> +                                  a firmware update to the firmware device.  The
>> +                                  following values from the Firmware Management
>> +                                  Protocol are supported:
>> +                                    IMAGE_UPDATABLE_VALID
>> +                                    IMAGE_UPDATABLE_INVALID
>> +                                    IMAGE_UPDATABLE_INVALID_TYPE
>> +                                    IMAGE_UPDATABLE_INVALID_OLD
>> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
>> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
>> +                                  status to report back to the ESRT table in case
>> +                                  of error. This value will only be checked when this
>> +                                  function returns an error.
>> +
>> +                                  The return status code must fall in the range of
>> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                  If the value falls outside this range, it will be converted
>> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
>> +                                 status information is returned in
>> +                                 ImageUpdatable.
>> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
>> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceCheckImageWithStatus (
>> +  IN  CONST VOID  *Image,
>> +  IN  UINTN       ImageSize,
>> +  OUT UINT32      *ImageUpdatable,
>> +  OUT UINT32      *LastAttemptStatus
>> +  )
>> +{
>> +  if (LastAttemptStatus == NULL) {
>> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
>> +
>> +  if (ImageUpdatable == NULL) {
>> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  //
>> +  //Set to valid and then if any tests fail it will update this flag.
>> +  //
>> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
>> +
>> +  if (Image == NULL) {
>> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
>> +    //
>> +    // Not sure if this is needed
>> +    //
>> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  //
>> +  // Make sure the image size is correct
>> +  //
>> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
>> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>>   /**
>>   Checks if the firmware image is valid for the device.
>>
>> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
>>     OUT UINT32      *ImageUpdateable
>>     )
>>   {
>> -  if (ImageUpdateable == NULL) {
>> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> +  UINT32  LastAttemptStatus;
>>
>> -  //
>> -  //Set to valid and then if any tests fail it will update this flag.
>> -  //
>> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
>> -
>> -  if (Image == NULL) {
>> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
>> -    //
>> -    // Not sure if this is needed
>> -    //
>> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> -
>> -  //
>> -  // Make sure the image size is correct
>> -  //
>> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
>> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
>> -    return EFI_INVALID_PARAMETER;
>> -  }
>> -
>> -  return EFI_SUCCESS;
>> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
>>   }
>>
>>   /**
>> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>> index db0f238ea534..132b60844ad4 100644
>> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>> @@ -1,6 +1,6 @@
>>   /**
>>
>> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
>> +Copyright (c) Microsoft Corporation.<BR>
>>   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>>
>>   SPDX-License-Identifier: BSD-2-Clause-Patent
>> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>>
>>
>>   #include <PiDxe.h>
>> +#include <LastAttemptStatus.h>
>> +#include <Guid/SystemResourceTable.h>
>>   #include <Library/DebugLib.h>
>>   #include <Protocol/FirmwareManagement.h>
>>   #include <Library/BaseLib.h>
>> @@ -345,6 +347,131 @@ Return Value:
>>   }//GetImage()
>>
>>
>> +/**
>> +  Updates a firmware device with a new firmware image.  This function returns
>> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
>> +  is updatable, the function should perform the following minimal validations
>> +  before proceeding to do the firmware image update.
>> +    - Validate that the image is a supported image for this firmware device.
>> +      Return EFI_ABORTED if the image is not supported.  Additional details
>> +      on why the image is not a supported image may be returned in AbortReason.
>> +    - Validate the data from VendorCode if is not NULL.  Firmware image
>> +      validation must be performed before VendorCode data validation.
>> +      VendorCode data is ignored or considered invalid if image validation
>> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>> +
>> +  VendorCode enables vendor to implement vendor-specific firmware image update
>> +  policy.  Null if the caller did not specify the policy or use the default
>> +  policy.  As an example, vendor can implement a policy to allow an option to
>> +  force a firmware image update when the abort reason is due to the new firmware
>> +  image version is older than the current firmware image version or bad image
>> +  checksum.  Sensitive operations such as those wiping the entire firmware image
>> +  and render the device to be non-functional should be encoded in the image
>> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
>> +  have the option to provide a more detailed description of the abort reason to
>> +  the caller.
>> +
>> +  @param[in]  Image             Points to the new firmware image.
>> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
>> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
>> +                                firmware image update policy.  NULL indicates
>> +                                the caller did not specify the policy or use the
>> +                                default policy.
>> +  @param[in]  Progress          A function used to report the progress of
>> +                                updating the firmware device with the new
>> +                                firmware image.
>> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
>> +                                update capsule that provided the new firmware
>> +                                image.
>> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
>> +                                Unicode string providing more details on an
>> +                                aborted operation. The buffer is allocated by
>> +                                this function with
>> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
>> +                                caller's responsibility to free this buffer with
>> +                                EFI_BOOT_SERVICES.FreePool().
>> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
>> +                                status to report back to the ESRT table in case
>> +                                of error. This value will only be checked when this
>> +                                function returns an error.
>> +
>> +                                The return status code must fall in the range of
>> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                If the value falls outside this range, it will be converted
>> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The firmware device was successfully updated
>> +                                 with the new firmware image.
>> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
>> +                                 are provided in AbortReason.
>> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>> +  @retval EFI_UNSUPPORTED        The operation is not supported.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceSetImageWithStatus (
>> +  IN  CONST VOID                                     *Image,
>> +  IN  UINTN                                          ImageSize,
>> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
>> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
>> +  IN  UINT32                                         CapsuleFwVersion,
>> +  OUT CHAR16                                         **AbortReason,
>> +  OUT UINT32                                         *LastAttemptStatus
>> +  )
>> +{
>> +    EFI_STATUS Status                         = EFI_SUCCESS;
>> +    UINT32 Updateable                         = 0;
>> +
>> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
>> +    if (EFI_ERROR(Status))
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed with %r.\n", Status));
>> +        goto cleanup;
>> +    }
>> +
>> +    if (Updateable != IMAGE_UPDATABLE_VALID)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image returned that the Image was not valid for update.
>> Updatable value = 0x%X.\n", Updateable));
>> +        Status = EFI_ABORTED;
>> +        goto cleanup;
>> +    }
>> +
>> +    if (Progress == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress callback\n"));
>> +        Status = EFI_INVALID_PARAMETER;
>> +        goto cleanup;
>> +    }
>> +
>> +    Status = Progress(15);
>> +    if (EFI_ERROR(Status))
>> +    {
>> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback failed with Status %r.\n", Status));
>> +    }
>> +
>> +    {
>> +      UINTN  p;
>> +
>> +      for (p = 20; p < 100; p++) {
>> +        gBS->Stall (100000);  //us  = 0.1 seconds
>> +        Progress (p);
>> +      }
>> +    }
>> +
>> +    //TODO: add support for VendorCode, and AbortReason
>> +cleanup:
>> +    if (EFI_ERROR (Status)) {
>> +      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +    }
>> +
>> +    return Status;
>> +}// SetImageWithStatus()
>> +
>> +
>>   /**
>>   Updates the firmware image of the device.
>>
>> @@ -396,51 +523,98 @@ IN  UINT32                                           CapsuleFwVersion,
>>   OUT CHAR16                                           **AbortReason
>>   )
>>   {
>> -    EFI_STATUS Status                         = EFI_SUCCESS;
>> -    UINT32 Updateable                         = 0;
>> -
>> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
>> -    if (EFI_ERROR(Status))
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with %r.\n", Status));
>> -        goto cleanup;
>> -    }
>> -
>> -    if (Updateable != IMAGE_UPDATABLE_VALID)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the Image was not valid for update.  Updatable value =
>> 0x%X.\n", Updateable));
>> -        Status = EFI_ABORTED;
>> -        goto cleanup;
>> -    }
>> -
>> -    if (Progress == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
>> -        Status = EFI_INVALID_PARAMETER;
>> -        goto cleanup;
>> -    }
>> -
>> -    Status = Progress(15);
>> -    if (EFI_ERROR(Status))
>> -    {
>> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with Status %r.\n", Status));
>> -    }
>> -
>> -    {
>> -      UINTN  p;
>> -
>> -      for (p = 20; p < 100; p++) {
>> -        gBS->Stall (100000);  //us  = 0.1 seconds
>> -        Progress (p);
>> -      }
>> -    }
>> -
>> -    //TODO: add support for VendorCode, and AbortReason
>> -cleanup:
>> -    return Status;
>> +  UINT32  LastAttemptStatus;
>> +
>> +  return  FmpDeviceSetImageWithStatus (
>> +            Image,
>> +            ImageSize,
>> +            VendorCode,
>> +            Progress,
>> +            CapsuleFwVersion,
>> +            AbortReason,
>> +            &LastAttemptStatus
>> +            );
>>   }// SetImage()
>>
>>
>> +/**
>> +  Checks if a new firmware image is valid for the firmware device.  This
>> +  function allows firmware update operation to validate the firmware image
>> +  before FmpDeviceSetImage() is called.
>> +
>> +  @param[in]  Image               Points to a new firmware image.
>> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
>> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
>> +                                  a firmware update to the firmware device.  The
>> +                                  following values from the Firmware Management
>> +                                  Protocol are supported:
>> +                                    IMAGE_UPDATABLE_VALID
>> +                                    IMAGE_UPDATABLE_INVALID
>> +                                    IMAGE_UPDATABLE_INVALID_TYPE
>> +                                    IMAGE_UPDATABLE_INVALID_OLD
>> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
>> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
>> +                                  status to report back to the ESRT table in case
>> +                                  of error. This value will only be checked when this
>> +                                  function returns an error.
>> +
>> +                                  The return status code must fall in the range of
>> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>> +
>> +                                  If the value falls outside this range, it will be converted
>> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>> +
>> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
>> +                                 status information is returned in
>> +                                 ImageUpdatable.
>> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
>> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
>> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FmpDeviceCheckImageWithStatus (
>> +  IN  CONST VOID  *Image,
>> +  IN  UINTN       ImageSize,
>> +  OUT UINT32      *ImageUpdatable,
>> +  OUT UINT32      *LastAttemptStatus
>> +  )
>> +{
>> +    EFI_STATUS status = EFI_SUCCESS;
>> +
>> +    if (LastAttemptStatus == NULL) {
>> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
>> +      return EFI_INVALID_PARAMETER;
>> +    }
>> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
>> +
>> +    if (ImageUpdatable == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
>> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +        status = EFI_INVALID_PARAMETER;
>> +        goto cleanup;
>> +    }
>> +
>> +    //
>> +    //Set to valid and then if any tests fail it will update this flag.
>> +    //
>> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
>> +
>> +    if (Image == NULL)
>> +    {
>> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
>> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
>> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>> +        return EFI_INVALID_PARAMETER;
>> +    }
>> +
>> +cleanup:
>> +    return status;
>> +}// CheckImageWithStatus()
>> +
>>
>>   /**
>>   Checks if the firmware image is valid for the device.
>> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
>>   OUT UINT32                            *ImageUpdateable
>>   )
>>   {
>> -    EFI_STATUS status = EFI_SUCCESS;
>> +  UINT32  LastAttemptStatus;
>>
>> -    if (ImageUpdateable == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
>> -        status = EFI_INVALID_PARAMETER;
>> -        goto cleanup;
>> -    }
>> -
>> -    //
>> -    //Set to valid and then if any tests fail it will update this flag.
>> -    //
>> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
>> -
>> -    if (Image == NULL)
>> -    {
>> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
>> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
>> -        return EFI_INVALID_PARAMETER;
>> -    }
>> -
>> -cleanup:
>> -    return status;
>> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
>>   }// CheckImage()
>>
>>   /**
>> --
>> 2.28.0.windows.1
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
  2020-11-05 20:36   ` Michael Kubacki
@ 2020-11-11  3:03     ` Michael D Kinney
  2020-11-11  4:16       ` [edk2-devel] " Kilian Kegel
  0 siblings, 1 reply; 10+ messages in thread
From: Michael D Kinney @ 2020-11-11  3:03 UTC (permalink / raw)
  To: Michael Kubacki, devel@edk2.groups.io, Kinney, Michael D
  Cc: Qian, Yi, Sun, Zailiang

Hi Michael,

This patch has been merged.

Thanks,

Mike

> -----Original Message-----
> From: Michael Kubacki <michael.kubacki@outlook.com>
> Sent: Thursday, November 5, 2020 12:36 PM
> To: Kinney, Michael D <michael.d.kinney@intel.com>; devel@edk2.groups.io
> Cc: Qian, Yi <yi.qian@intel.com>; Sun, Zailiang <zailiang.sun@intel.com>
> Subject: Re: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
> 
> Hi Mike,
> 
> I saw other Vlv2TbltDevicePkg patches were merged yesterday. Do you know
> when this patch will be merged?
> 
> Thanks,
> Michael
> 
> On 10/28/2020 6:12 PM, Kinney, Michael D wrote:
> > Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
> >
> > I also verified build and boot and FMP based capsule updates work as expected.
> >
> > Tested-by: Michael D Kinney <Michael.d.kinney@intel.com>
> >
> > Thanks,
> >
> > Mike
> >
> >
> >> -----Original Message-----
> >> From: michael.kubacki@outlook.com <michael.kubacki@outlook.com>
> >> Sent: Thursday, October 1, 2020 2:59 PM
> >> To: devel@edk2.groups.io
> >> Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Qian, Yi <yi.qian@intel.com>; Sun, Zailiang
> <zailiang.sun@intel.com>
> >> Subject: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
> >>
> >> From: Michael Kubacki <michael.kubacki@microsoft.com>
> >>
> >> Makes the changes necessary for these library instances of
> >> FmpDeviceLib to be compatible with new functions added recently
> >> to FmpDeviceLib.
> >>
> >> Two new functions were introduced in FmpDeviceLib to allow a
> >> library instance to return a Last Attempt Status code during
> >> check image and set image operations:
> >>    1. FmpDeviceCheckImageWithStatus ( )
> >>    2. FmpDeviceSetImageWithStatus ( )
> >>
> >> FmpDxe (in FmpDevicePkg) will begin calling these new functions
> >> instead of the previous functions. Therefore, this change:
> >>    1. Adds these functions to Vlv2TbltDevicePkg implementations
> >>    2. Moves the main functionality to these new functions
> >>    3. Updates the old functions to call the new functions
> >>       (for backward compatibility)
> >>
> >> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
> >> due to:
> >>    1. A required RngLib library instance not defined by the platform
> >>    2. Other FMP libraries not being defined by the platform
> >>       (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
> >>
> >> Those changes were fixed locally to test the changes in this commit
> >> but maintainers should make the proper changes for those issues.
> >>
> >> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> >> Cc: Yi Qian <yi.qian@intel.com>
> >> Cc: Zailiang Sun <zailiang.sun@intel.com>
> >> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
> >> ---
> >>
> >> Notes:
> >>      Only build was checked, I do not have access to a
> >>      VLV2 device for testing.
> >>
> >>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       | 299 +++++++++++++++-----
> >>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c | 284 ++++++++++++++-----
> >>   2 files changed, 446 insertions(+), 137 deletions(-)
> >>
> >> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> index d8c9036012ad..df8a36d9854c 100644
> >> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> @@ -1,6 +1,6 @@
> >>   /**
> >>
> >> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
> >> +Copyright (c) Microsoft Corporation.<BR>
> >>   Copyright (c) 2019, Intel Corporation.  All rights reserved.
> >>
> >>   SPDX-License-Identifier: BSD-2-Clause-Patent
> >> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> >>   **/
> >>
> >>   #include <PiDxe.h>
> >> -
> >> +#include <LastAttemptStatus.h>
> >> +#include <Guid/SystemResourceTable.h>
> >>   #include <Library/FmpDeviceLib.h>
> >>
> >>   #include <Library/DebugLib.h>
> >> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
> >>   }
> >>
> >>   /**
> >> -  Updates the firmware image of the device.
> >> -
> >> -  This function updates the hardware with the new firmware image.  This function
> >> -  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> >> -  firmware image is updatable, the function should perform the following minimal
> >> -  validations before proceeding to do the firmware image update.
> >> -    - Validate the image is a supported image for this device.  The function
> >> -      returns EFI_ABORTED if the image is unsupported.  The function can
> >> -      optionally provide more detailed information on why the image is not a
> >> -      supported image.
> >> -    - Validate the data from VendorCode if not null.  Image validation must be
> >> -      performed before VendorCode data validation.  VendorCode data is ignored
> >> -      or considered invalid if image validation failed.  The function returns
> >> -      EFI_ABORTED if the data is invalid.
> >> +  Updates a firmware device with a new firmware image.  This function returns
> >> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> >> +  is updatable, the function should perform the following minimal validations
> >> +  before proceeding to do the firmware image update.
> >> +    - Validate that the image is a supported image for this firmware device.
> >> +      Return EFI_ABORTED if the image is not supported.  Additional details
> >> +      on why the image is not a supported image may be returned in AbortReason.
> >> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> >> +      validation must be performed before VendorCode data validation.
> >> +      VendorCode data is ignored or considered invalid if image validation
> >> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> >>
> >>     VendorCode enables vendor to implement vendor-specific firmware image update
> >>     policy.  Null if the caller did not specify the policy or use the default
> >> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
> >>     have the option to provide a more detailed description of the abort reason to
> >>     the caller.
> >>
> >> -  @param[in]  Image             Points to the new image.
> >> -  @param[in]  ImageSize         Size of the new image in bytes.
> >> +  @param[in]  Image             Points to the new firmware image.
> >> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
> >>     @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> -                                firmware image update policy. Null indicates the
> >> -                                caller did not specify the policy or use the
> >> +                                firmware image update policy.  NULL indicates
> >> +                                the caller did not specify the policy or use the
> >>                                   default policy.
> >> -  @param[in]  Progress          A function used by the driver to report the
> >> -                                progress of the firmware update.
> >> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> >> -  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> >> -                                string providing more details for the aborted
> >> -                                operation. The buffer is allocated by this
> >> -                                function with AllocatePool(), and it is the
> >> -                                caller's responsibility to free it with a call
> >> -                                to FreePool().
> >> +  @param[in]  Progress          A function used to report the progress of
> >> +                                updating the firmware device with the new
> >> +                                firmware image.
> >> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> >> +                                update capsule that provided the new firmware
> >> +                                image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> >> +                                Unicode string providing more details on an
> >> +                                aborted operation. The buffer is allocated by
> >> +                                this function with
> >> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> >> +                                caller's responsibility to free this buffer with
> >> +                                EFI_BOOT_SERVICES.FreePool().
> >> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> >> +                                status to report back to the ESRT table in case
> >> +                                of error. This value will only be checked when this
> >> +                                function returns an error.
> >>
> >> -  @retval EFI_SUCCESS            The device was successfully updated with the
> >> -                                 new image.
> >> -  @retval EFI_ABORTED            The operation is aborted.
> >> +                                The return status code must fall in the range of
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                If the value falls outside this range, it will be converted
> >> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> >> +                                 with the new firmware image.
> >> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> >> +                                 are provided in AbortReason.
> >>     @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
> >>     @retval EFI_UNSUPPORTED        The operation is not supported.
> >>
> >>   **/
> >>   EFI_STATUS
> >>   EFIAPI
> >> -FmpDeviceSetImage (
> >> +FmpDeviceSetImageWithStatus (
> >>     IN  CONST VOID                                     *Image,
> >>     IN  UINTN                                          ImageSize,
> >> -  IN  CONST VOID                                     *VendorCode,
> >> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> >> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
> >>     IN  UINT32                                         CapsuleFwVersion,
> >> -  OUT CHAR16                                         **AbortReason
> >> +  OUT CHAR16                                         **AbortReason,
> >> +  OUT UINT32                                         *LastAttemptStatus
> >>     )
> >>   {
> >>     EFI_STATUS          Status;
> >> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
> >>     UINTN               BytesWritten;
> >>
> >>     Updateable = 0;
> >> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
> >> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image failed with %r.\n", Status));
> >>       return Status;
> >>     }
> >>
> >>     if (Updateable != IMAGE_UPDATABLE_VALID) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned that the Image was not valid for update.  Updatable
> >> value = 0x%X.\n", Updateable));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image returned that the Image was not valid for update.
> >> Updatable value = 0x%X.\n", Updateable));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >>       return EFI_ABORTED;
> >>     }
> >>
> >>     if (Progress == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress callback\n"));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >>       return EFI_INVALID_PARAMETER;
> >>     }
> >>
> >>     Status = Progress (15);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>     }
> >>
> >>     //
> >> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
> >>     //
> >>     Progress (20);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>     }
> >>
> >>     //
> >> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
> >>
> >>   //    Progress (Percentage);
> >>   //    if (EFI_ERROR (Status)) {
> >> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>   //    }
> >>     }
> >>
> >> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> >> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> >>
> >>     if (ARRAY_SIZE (mUpdateConfigData) == 0) {
> >>       DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
> >> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
> >>       BytesWritten += ConfigData->Length;
> >>     }
> >>
> >> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
> >> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
> >> +
> >> +  if (EFI_ERROR (Status)) {
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +  }
> >>
> >>     return Status;
> >>   }
> >>
> >> +/**
> >> +  Updates the firmware image of the device.
> >> +
> >> +  This function updates the hardware with the new firmware image.  This function
> >> +  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> >> +  firmware image is updatable, the function should perform the following minimal
> >> +  validations before proceeding to do the firmware image update.
> >> +    - Validate the image is a supported image for this device.  The function
> >> +      returns EFI_ABORTED if the image is unsupported.  The function can
> >> +      optionally provide more detailed information on why the image is not a
> >> +      supported image.
> >> +    - Validate the data from VendorCode if not null.  Image validation must be
> >> +      performed before VendorCode data validation.  VendorCode data is ignored
> >> +      or considered invalid if image validation failed.  The function returns
> >> +      EFI_ABORTED if the data is invalid.
> >> +
> >> +  VendorCode enables vendor to implement vendor-specific firmware image update
> >> +  policy.  Null if the caller did not specify the policy or use the default
> >> +  policy.  As an example, vendor can implement a policy to allow an option to
> >> +  force a firmware image update when the abort reason is due to the new firmware
> >> +  image version is older than the current firmware image version or bad image
> >> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> >> +  and render the device to be non-functional should be encoded in the image
> >> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> >> +  have the option to provide a more detailed description of the abort reason to
> >> +  the caller.
> >> +
> >> +  @param[in]  Image             Points to the new image.
> >> +  @param[in]  ImageSize         Size of the new image in bytes.
> >> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> +                                firmware image update policy. Null indicates the
> >> +                                caller did not specify the policy or use the
> >> +                                default policy.
> >> +  @param[in]  Progress          A function used by the driver to report the
> >> +                                progress of the firmware update.
> >> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> >> +                                string providing more details for the aborted
> >> +                                operation. The buffer is allocated by this
> >> +                                function with AllocatePool(), and it is the
> >> +                                caller's responsibility to free it with a call
> >> +                                to FreePool().
> >> +
> >> +  @retval EFI_SUCCESS            The device was successfully updated with the
> >> +                                 new image.
> >> +  @retval EFI_ABORTED            The operation is aborted.
> >> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceSetImage (
> >> +  IN  CONST VOID                                     *Image,
> >> +  IN  UINTN                                          ImageSize,
> >> +  IN  CONST VOID                                     *VendorCode,
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> >> +  IN  UINT32                                         CapsuleFwVersion,
> >> +  OUT CHAR16                                         **AbortReason
> >> +  )
> >> +{
> >> +  UINT32  LastAttemptStatus;
> >> +
> >> +  return  FmpDeviceSetImageWithStatus (
> >> +            Image,
> >> +            ImageSize,
> >> +            VendorCode,
> >> +            Progress,
> >> +            CapsuleFwVersion,
> >> +            AbortReason,
> >> +            &LastAttemptStatus
> >> +            );
> >> +}
> >> +
> >> +/**
> >> +  Checks if a new firmware image is valid for the firmware device.  This
> >> +  function allows firmware update operation to validate the firmware image
> >> +  before FmpDeviceSetImage() is called.
> >> +
> >> +  @param[in]  Image               Points to a new firmware image.
> >> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> >> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> >> +                                  a firmware update to the firmware device.  The
> >> +                                  following values from the Firmware Management
> >> +                                  Protocol are supported:
> >> +                                    IMAGE_UPDATABLE_VALID
> >> +                                    IMAGE_UPDATABLE_INVALID
> >> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> >> +                                    IMAGE_UPDATABLE_INVALID_OLD
> >> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> >> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> >> +                                  status to report back to the ESRT table in case
> >> +                                  of error. This value will only be checked when this
> >> +                                  function returns an error.
> >> +
> >> +                                  The return status code must fall in the range of
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                  If the value falls outside this range, it will be converted
> >> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> >> +                                 status information is returned in
> >> +                                 ImageUpdatable.
> >> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceCheckImageWithStatus (
> >> +  IN  CONST VOID  *Image,
> >> +  IN  UINTN       ImageSize,
> >> +  OUT UINT32      *ImageUpdatable,
> >> +  OUT UINT32      *LastAttemptStatus
> >> +  )
> >> +{
> >> +  if (LastAttemptStatus == NULL) {
> >> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> >> +
> >> +  if (ImageUpdatable == NULL) {
> >> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  //
> >> +  //Set to valid and then if any tests fail it will update this flag.
> >> +  //
> >> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> >> +
> >> +  if (Image == NULL) {
> >> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> >> +    //
> >> +    // Not sure if this is needed
> >> +    //
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  //
> >> +  // Make sure the image size is correct
> >> +  //
> >> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  return EFI_SUCCESS;
> >> +}
> >> +
> >>   /**
> >>   Checks if the firmware image is valid for the device.
> >>
> >> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
> >>     OUT UINT32      *ImageUpdateable
> >>     )
> >>   {
> >> -  if (ImageUpdateable == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> +  UINT32  LastAttemptStatus;
> >>
> >> -  //
> >> -  //Set to valid and then if any tests fail it will update this flag.
> >> -  //
> >> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> >> -
> >> -  if (Image == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> >> -    //
> >> -    // Not sure if this is needed
> >> -    //
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> -
> >> -  //
> >> -  // Make sure the image size is correct
> >> -  //
> >> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> -
> >> -  return EFI_SUCCESS;
> >> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
> >>   }
> >>
> >>   /**
> >> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> index db0f238ea534..132b60844ad4 100644
> >> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> @@ -1,6 +1,6 @@
> >>   /**
> >>
> >> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
> >> +Copyright (c) Microsoft Corporation.<BR>
> >>   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> >>
> >>   SPDX-License-Identifier: BSD-2-Clause-Patent
> >> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> >>
> >>
> >>   #include <PiDxe.h>
> >> +#include <LastAttemptStatus.h>
> >> +#include <Guid/SystemResourceTable.h>
> >>   #include <Library/DebugLib.h>
> >>   #include <Protocol/FirmwareManagement.h>
> >>   #include <Library/BaseLib.h>
> >> @@ -345,6 +347,131 @@ Return Value:
> >>   }//GetImage()
> >>
> >>
> >> +/**
> >> +  Updates a firmware device with a new firmware image.  This function returns
> >> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> >> +  is updatable, the function should perform the following minimal validations
> >> +  before proceeding to do the firmware image update.
> >> +    - Validate that the image is a supported image for this firmware device.
> >> +      Return EFI_ABORTED if the image is not supported.  Additional details
> >> +      on why the image is not a supported image may be returned in AbortReason.
> >> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> >> +      validation must be performed before VendorCode data validation.
> >> +      VendorCode data is ignored or considered invalid if image validation
> >> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> >> +
> >> +  VendorCode enables vendor to implement vendor-specific firmware image update
> >> +  policy.  Null if the caller did not specify the policy or use the default
> >> +  policy.  As an example, vendor can implement a policy to allow an option to
> >> +  force a firmware image update when the abort reason is due to the new firmware
> >> +  image version is older than the current firmware image version or bad image
> >> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> >> +  and render the device to be non-functional should be encoded in the image
> >> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> >> +  have the option to provide a more detailed description of the abort reason to
> >> +  the caller.
> >> +
> >> +  @param[in]  Image             Points to the new firmware image.
> >> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
> >> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> +                                firmware image update policy.  NULL indicates
> >> +                                the caller did not specify the policy or use the
> >> +                                default policy.
> >> +  @param[in]  Progress          A function used to report the progress of
> >> +                                updating the firmware device with the new
> >> +                                firmware image.
> >> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> >> +                                update capsule that provided the new firmware
> >> +                                image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> >> +                                Unicode string providing more details on an
> >> +                                aborted operation. The buffer is allocated by
> >> +                                this function with
> >> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> >> +                                caller's responsibility to free this buffer with
> >> +                                EFI_BOOT_SERVICES.FreePool().
> >> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> >> +                                status to report back to the ESRT table in case
> >> +                                of error. This value will only be checked when this
> >> +                                function returns an error.
> >> +
> >> +                                The return status code must fall in the range of
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                If the value falls outside this range, it will be converted
> >> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> >> +                                 with the new firmware image.
> >> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> >> +                                 are provided in AbortReason.
> >> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
> >> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceSetImageWithStatus (
> >> +  IN  CONST VOID                                     *Image,
> >> +  IN  UINTN                                          ImageSize,
> >> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
> >> +  IN  UINT32                                         CapsuleFwVersion,
> >> +  OUT CHAR16                                         **AbortReason,
> >> +  OUT UINT32                                         *LastAttemptStatus
> >> +  )
> >> +{
> >> +    EFI_STATUS Status                         = EFI_SUCCESS;
> >> +    UINT32 Updateable                         = 0;
> >> +
> >> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
> >> +    if (EFI_ERROR(Status))
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed with %r.\n", Status));
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    if (Updateable != IMAGE_UPDATABLE_VALID)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image returned that the Image was not valid for update.
> >> Updatable value = 0x%X.\n", Updateable));
> >> +        Status = EFI_ABORTED;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    if (Progress == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress callback\n"));
> >> +        Status = EFI_INVALID_PARAMETER;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    Status = Progress(15);
> >> +    if (EFI_ERROR(Status))
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback failed with Status %r.\n", Status));
> >> +    }
> >> +
> >> +    {
> >> +      UINTN  p;
> >> +
> >> +      for (p = 20; p < 100; p++) {
> >> +        gBS->Stall (100000);  //us  = 0.1 seconds
> >> +        Progress (p);
> >> +      }
> >> +    }
> >> +
> >> +    //TODO: add support for VendorCode, and AbortReason
> >> +cleanup:
> >> +    if (EFI_ERROR (Status)) {
> >> +      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    }
> >> +
> >> +    return Status;
> >> +}// SetImageWithStatus()
> >> +
> >> +
> >>   /**
> >>   Updates the firmware image of the device.
> >>
> >> @@ -396,51 +523,98 @@ IN  UINT32                                           CapsuleFwVersion,
> >>   OUT CHAR16                                           **AbortReason
> >>   )
> >>   {
> >> -    EFI_STATUS Status                         = EFI_SUCCESS;
> >> -    UINT32 Updateable                         = 0;
> >> -
> >> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
> >> -    if (EFI_ERROR(Status))
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with %r.\n", Status));
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    if (Updateable != IMAGE_UPDATABLE_VALID)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the Image was not valid for update.  Updatable value
> =
> >> 0x%X.\n", Updateable));
> >> -        Status = EFI_ABORTED;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    if (Progress == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
> >> -        Status = EFI_INVALID_PARAMETER;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    Status = Progress(15);
> >> -    if (EFI_ERROR(Status))
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with Status %r.\n", Status));
> >> -    }
> >> -
> >> -    {
> >> -      UINTN  p;
> >> -
> >> -      for (p = 20; p < 100; p++) {
> >> -        gBS->Stall (100000);  //us  = 0.1 seconds
> >> -        Progress (p);
> >> -      }
> >> -    }
> >> -
> >> -    //TODO: add support for VendorCode, and AbortReason
> >> -cleanup:
> >> -    return Status;
> >> +  UINT32  LastAttemptStatus;
> >> +
> >> +  return  FmpDeviceSetImageWithStatus (
> >> +            Image,
> >> +            ImageSize,
> >> +            VendorCode,
> >> +            Progress,
> >> +            CapsuleFwVersion,
> >> +            AbortReason,
> >> +            &LastAttemptStatus
> >> +            );
> >>   }// SetImage()
> >>
> >>
> >> +/**
> >> +  Checks if a new firmware image is valid for the firmware device.  This
> >> +  function allows firmware update operation to validate the firmware image
> >> +  before FmpDeviceSetImage() is called.
> >> +
> >> +  @param[in]  Image               Points to a new firmware image.
> >> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> >> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> >> +                                  a firmware update to the firmware device.  The
> >> +                                  following values from the Firmware Management
> >> +                                  Protocol are supported:
> >> +                                    IMAGE_UPDATABLE_VALID
> >> +                                    IMAGE_UPDATABLE_INVALID
> >> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> >> +                                    IMAGE_UPDATABLE_INVALID_OLD
> >> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> >> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> >> +                                  status to report back to the ESRT table in case
> >> +                                  of error. This value will only be checked when this
> >> +                                  function returns an error.
> >> +
> >> +                                  The return status code must fall in the range of
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                  If the value falls outside this range, it will be converted
> >> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> >> +                                 status information is returned in
> >> +                                 ImageUpdatable.
> >> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceCheckImageWithStatus (
> >> +  IN  CONST VOID  *Image,
> >> +  IN  UINTN       ImageSize,
> >> +  OUT UINT32      *ImageUpdatable,
> >> +  OUT UINT32      *LastAttemptStatus
> >> +  )
> >> +{
> >> +    EFI_STATUS status = EFI_SUCCESS;
> >> +
> >> +    if (LastAttemptStatus == NULL) {
> >> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> >> +      return EFI_INVALID_PARAMETER;
> >> +    }
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> >> +
> >> +    if (ImageUpdatable == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> >> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +        status = EFI_INVALID_PARAMETER;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    //
> >> +    //Set to valid and then if any tests fail it will update this flag.
> >> +    //
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> >> +
> >> +    if (Image == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> >> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> >> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +        return EFI_INVALID_PARAMETER;
> >> +    }
> >> +
> >> +cleanup:
> >> +    return status;
> >> +}// CheckImageWithStatus()
> >> +
> >>
> >>   /**
> >>   Checks if the firmware image is valid for the device.
> >> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
> >>   OUT UINT32                            *ImageUpdateable
> >>   )
> >>   {
> >> -    EFI_STATUS status = EFI_SUCCESS;
> >> +  UINT32  LastAttemptStatus;
> >>
> >> -    if (ImageUpdateable == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> >> -        status = EFI_INVALID_PARAMETER;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    //
> >> -    //Set to valid and then if any tests fail it will update this flag.
> >> -    //
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> >> -
> >> -    if (Image == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> >> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> >> -        return EFI_INVALID_PARAMETER;
> >> -    }
> >> -
> >> -cleanup:
> >> -    return status;
> >> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
> >>   }// CheckImage()
> >>
> >>   /**
> >> --
> >> 2.28.0.windows.1
> >

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
  2020-11-11  3:03     ` Michael D Kinney
@ 2020-11-11  4:16       ` Kilian Kegel
  2020-11-11  5:17         ` Michael Kubacki
  2020-11-11 17:17         ` Michael D Kinney
  0 siblings, 2 replies; 10+ messages in thread
From: Kilian Kegel @ 2020-11-11  4:16 UTC (permalink / raw)
  To: devel@edk2.groups.io, michael.d.kinney@intel.com, Michael Kubacki
  Cc: Qian, Yi, Sun, Zailiang

[-- Attachment #1: Type: text/plain, Size: 40358 bytes --]

Hi all,

if this patch also affects https://bugzilla.tianocore.org/show_bug.cgi?id=2983, please close it.

Thanks,
Kilian

Von: Michael D Kinney<mailto:michael.d.kinney@intel.com>
Gesendet: Wednesday, November 11, 2020 4:03 AM
An: Michael Kubacki<mailto:michael.kubacki@outlook.com>; devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Kinney, Michael D<mailto:michael.d.kinney@intel.com>
Cc: Qian, Yi<mailto:yi.qian@intel.com>; Sun, Zailiang<mailto:zailiang.sun@intel.com>
Betreff: Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility

Hi Michael,

This patch has been merged.

Thanks,

Mike

> -----Original Message-----
> From: Michael Kubacki <michael.kubacki@outlook.com>
> Sent: Thursday, November 5, 2020 12:36 PM
> To: Kinney, Michael D <michael.d.kinney@intel.com>; devel@edk2.groups.io
> Cc: Qian, Yi <yi.qian@intel.com>; Sun, Zailiang <zailiang.sun@intel.com>
> Subject: Re: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
>
> Hi Mike,
>
> I saw other Vlv2TbltDevicePkg patches were merged yesterday. Do you know
> when this patch will be merged?
>
> Thanks,
> Michael
>
> On 10/28/2020 6:12 PM, Kinney, Michael D wrote:
> > Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
> >
> > I also verified build and boot and FMP based capsule updates work as expected.
> >
> > Tested-by: Michael D Kinney <Michael.d.kinney@intel.com>
> >
> > Thanks,
> >
> > Mike
> >
> >
> >> -----Original Message-----
> >> From: michael.kubacki@outlook.com <michael.kubacki@outlook.com>
> >> Sent: Thursday, October 1, 2020 2:59 PM
> >> To: devel@edk2.groups.io
> >> Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Qian, Yi <yi.qian@intel.com>; Sun, Zailiang
> <zailiang.sun@intel.com>
> >> Subject: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
> >>
> >> From: Michael Kubacki <michael.kubacki@microsoft.com>
> >>
> >> Makes the changes necessary for these library instances of
> >> FmpDeviceLib to be compatible with new functions added recently
> >> to FmpDeviceLib.
> >>
> >> Two new functions were introduced in FmpDeviceLib to allow a
> >> library instance to return a Last Attempt Status code during
> >> check image and set image operations:
> >>    1. FmpDeviceCheckImageWithStatus ( )
> >>    2. FmpDeviceSetImageWithStatus ( )
> >>
> >> FmpDxe (in FmpDevicePkg) will begin calling these new functions
> >> instead of the previous functions. Therefore, this change:
> >>    1. Adds these functions to Vlv2TbltDevicePkg implementations
> >>    2. Moves the main functionality to these new functions
> >>    3. Updates the old functions to call the new functions
> >>       (for backward compatibility)
> >>
> >> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
> >> due to:
> >>    1. A required RngLib library instance not defined by the platform
> >>    2. Other FMP libraries not being defined by the platform
> >>       (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
> >>
> >> Those changes were fixed locally to test the changes in this commit
> >> but maintainers should make the proper changes for those issues.
> >>
> >> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> >> Cc: Yi Qian <yi.qian@intel.com>
> >> Cc: Zailiang Sun <zailiang.sun@intel.com>
> >> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
> >> ---
> >>
> >> Notes:
> >>      Only build was checked, I do not have access to a
> >>      VLV2 device for testing.
> >>
> >>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       | 299 +++++++++++++++-----
> >>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c | 284 ++++++++++++++-----
> >>   2 files changed, 446 insertions(+), 137 deletions(-)
> >>
> >> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> index d8c9036012ad..df8a36d9854c 100644
> >> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> @@ -1,6 +1,6 @@
> >>   /**
> >>
> >> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
> >> +Copyright (c) Microsoft Corporation.<BR>
> >>   Copyright (c) 2019, Intel Corporation.  All rights reserved.
> >>
> >>   SPDX-License-Identifier: BSD-2-Clause-Patent
> >> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> >>   **/
> >>
> >>   #include <PiDxe.h>
> >> -
> >> +#include <LastAttemptStatus.h>
> >> +#include <Guid/SystemResourceTable.h>
> >>   #include <Library/FmpDeviceLib.h>
> >>
> >>   #include <Library/DebugLib.h>
> >> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
> >>   }
> >>
> >>   /**
> >> -  Updates the firmware image of the device.
> >> -
> >> -  This function updates the hardware with the new firmware image.  This function
> >> -  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> >> -  firmware image is updatable, the function should perform the following minimal
> >> -  validations before proceeding to do the firmware image update.
> >> -    - Validate the image is a supported image for this device.  The function
> >> -      returns EFI_ABORTED if the image is unsupported.  The function can
> >> -      optionally provide more detailed information on why the image is not a
> >> -      supported image.
> >> -    - Validate the data from VendorCode if not null.  Image validation must be
> >> -      performed before VendorCode data validation.  VendorCode data is ignored
> >> -      or considered invalid if image validation failed.  The function returns
> >> -      EFI_ABORTED if the data is invalid.
> >> +  Updates a firmware device with a new firmware image.  This function returns
> >> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> >> +  is updatable, the function should perform the following minimal validations
> >> +  before proceeding to do the firmware image update.
> >> +    - Validate that the image is a supported image for this firmware device.
> >> +      Return EFI_ABORTED if the image is not supported.  Additional details
> >> +      on why the image is not a supported image may be returned in AbortReason.
> >> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> >> +      validation must be performed before VendorCode data validation.
> >> +      VendorCode data is ignored or considered invalid if image validation
> >> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> >>
> >>     VendorCode enables vendor to implement vendor-specific firmware image update
> >>     policy.  Null if the caller did not specify the policy or use the default
> >> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
> >>     have the option to provide a more detailed description of the abort reason to
> >>     the caller.
> >>
> >> -  @param[in]  Image             Points to the new image.
> >> -  @param[in]  ImageSize         Size of the new image in bytes.
> >> +  @param[in]  Image             Points to the new firmware image.
> >> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
> >>     @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> -                                firmware image update policy. Null indicates the
> >> -                                caller did not specify the policy or use the
> >> +                                firmware image update policy.  NULL indicates
> >> +                                the caller did not specify the policy or use the
> >>                                   default policy.
> >> -  @param[in]  Progress          A function used by the driver to report the
> >> -                                progress of the firmware update.
> >> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> >> -  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> >> -                                string providing more details for the aborted
> >> -                                operation. The buffer is allocated by this
> >> -                                function with AllocatePool(), and it is the
> >> -                                caller's responsibility to free it with a call
> >> -                                to FreePool().
> >> +  @param[in]  Progress          A function used to report the progress of
> >> +                                updating the firmware device with the new
> >> +                                firmware image.
> >> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> >> +                                update capsule that provided the new firmware
> >> +                                image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> >> +                                Unicode string providing more details on an
> >> +                                aborted operation. The buffer is allocated by
> >> +                                this function with
> >> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> >> +                                caller's responsibility to free this buffer with
> >> +                                EFI_BOOT_SERVICES.FreePool().
> >> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> >> +                                status to report back to the ESRT table in case
> >> +                                of error. This value will only be checked when this
> >> +                                function returns an error.
> >>
> >> -  @retval EFI_SUCCESS            The device was successfully updated with the
> >> -                                 new image.
> >> -  @retval EFI_ABORTED            The operation is aborted.
> >> +                                The return status code must fall in the range of
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                If the value falls outside this range, it will be converted
> >> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> >> +                                 with the new firmware image.
> >> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> >> +                                 are provided in AbortReason.
> >>     @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
> >>     @retval EFI_UNSUPPORTED        The operation is not supported.
> >>
> >>   **/
> >>   EFI_STATUS
> >>   EFIAPI
> >> -FmpDeviceSetImage (
> >> +FmpDeviceSetImageWithStatus (
> >>     IN  CONST VOID                                     *Image,
> >>     IN  UINTN                                          ImageSize,
> >> -  IN  CONST VOID                                     *VendorCode,
> >> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> >> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
> >>     IN  UINT32                                         CapsuleFwVersion,
> >> -  OUT CHAR16                                         **AbortReason
> >> +  OUT CHAR16                                         **AbortReason,
> >> +  OUT UINT32                                         *LastAttemptStatus
> >>     )
> >>   {
> >>     EFI_STATUS          Status;
> >> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
> >>     UINTN               BytesWritten;
> >>
> >>     Updateable = 0;
> >> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
> >> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image failed with %r.\n", Status));
> >>       return Status;
> >>     }
> >>
> >>     if (Updateable != IMAGE_UPDATABLE_VALID) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned that the Image was not valid for update.  Updatable
> >> value = 0x%X.\n", Updateable));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image returned that the Image was not valid for update.
> >> Updatable value = 0x%X.\n", Updateable));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >>       return EFI_ABORTED;
> >>     }
> >>
> >>     if (Progress == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress callback\n"));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >>       return EFI_INVALID_PARAMETER;
> >>     }
> >>
> >>     Status = Progress (15);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>     }
> >>
> >>     //
> >> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
> >>     //
> >>     Progress (20);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>     }
> >>
> >>     //
> >> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
> >>
> >>   //    Progress (Percentage);
> >>   //    if (EFI_ERROR (Status)) {
> >> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>   //    }
> >>     }
> >>
> >> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> >> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> >>
> >>     if (ARRAY_SIZE (mUpdateConfigData) == 0) {
> >>       DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
> >> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
> >>       BytesWritten += ConfigData->Length;
> >>     }
> >>
> >> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
> >> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
> >> +
> >> +  if (EFI_ERROR (Status)) {
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +  }
> >>
> >>     return Status;
> >>   }
> >>
> >> +/**
> >> +  Updates the firmware image of the device.
> >> +
> >> +  This function updates the hardware with the new firmware image.  This function
> >> +  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> >> +  firmware image is updatable, the function should perform the following minimal
> >> +  validations before proceeding to do the firmware image update.
> >> +    - Validate the image is a supported image for this device.  The function
> >> +      returns EFI_ABORTED if the image is unsupported.  The function can
> >> +      optionally provide more detailed information on why the image is not a
> >> +      supported image.
> >> +    - Validate the data from VendorCode if not null.  Image validation must be
> >> +      performed before VendorCode data validation.  VendorCode data is ignored
> >> +      or considered invalid if image validation failed.  The function returns
> >> +      EFI_ABORTED if the data is invalid.
> >> +
> >> +  VendorCode enables vendor to implement vendor-specific firmware image update
> >> +  policy.  Null if the caller did not specify the policy or use the default
> >> +  policy.  As an example, vendor can implement a policy to allow an option to
> >> +  force a firmware image update when the abort reason is due to the new firmware
> >> +  image version is older than the current firmware image version or bad image
> >> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> >> +  and render the device to be non-functional should be encoded in the image
> >> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> >> +  have the option to provide a more detailed description of the abort reason to
> >> +  the caller.
> >> +
> >> +  @param[in]  Image             Points to the new image.
> >> +  @param[in]  ImageSize         Size of the new image in bytes.
> >> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> +                                firmware image update policy. Null indicates the
> >> +                                caller did not specify the policy or use the
> >> +                                default policy.
> >> +  @param[in]  Progress          A function used by the driver to report the
> >> +                                progress of the firmware update.
> >> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> >> +                                string providing more details for the aborted
> >> +                                operation. The buffer is allocated by this
> >> +                                function with AllocatePool(), and it is the
> >> +                                caller's responsibility to free it with a call
> >> +                                to FreePool().
> >> +
> >> +  @retval EFI_SUCCESS            The device was successfully updated with the
> >> +                                 new image.
> >> +  @retval EFI_ABORTED            The operation is aborted.
> >> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceSetImage (
> >> +  IN  CONST VOID                                     *Image,
> >> +  IN  UINTN                                          ImageSize,
> >> +  IN  CONST VOID                                     *VendorCode,
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> >> +  IN  UINT32                                         CapsuleFwVersion,
> >> +  OUT CHAR16                                         **AbortReason
> >> +  )
> >> +{
> >> +  UINT32  LastAttemptStatus;
> >> +
> >> +  return  FmpDeviceSetImageWithStatus (
> >> +            Image,
> >> +            ImageSize,
> >> +            VendorCode,
> >> +            Progress,
> >> +            CapsuleFwVersion,
> >> +            AbortReason,
> >> +            &LastAttemptStatus
> >> +            );
> >> +}
> >> +
> >> +/**
> >> +  Checks if a new firmware image is valid for the firmware device.  This
> >> +  function allows firmware update operation to validate the firmware image
> >> +  before FmpDeviceSetImage() is called.
> >> +
> >> +  @param[in]  Image               Points to a new firmware image.
> >> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> >> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> >> +                                  a firmware update to the firmware device.  The
> >> +                                  following values from the Firmware Management
> >> +                                  Protocol are supported:
> >> +                                    IMAGE_UPDATABLE_VALID
> >> +                                    IMAGE_UPDATABLE_INVALID
> >> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> >> +                                    IMAGE_UPDATABLE_INVALID_OLD
> >> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> >> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> >> +                                  status to report back to the ESRT table in case
> >> +                                  of error. This value will only be checked when this
> >> +                                  function returns an error.
> >> +
> >> +                                  The return status code must fall in the range of
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                  If the value falls outside this range, it will be converted
> >> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> >> +                                 status information is returned in
> >> +                                 ImageUpdatable.
> >> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceCheckImageWithStatus (
> >> +  IN  CONST VOID  *Image,
> >> +  IN  UINTN       ImageSize,
> >> +  OUT UINT32      *ImageUpdatable,
> >> +  OUT UINT32      *LastAttemptStatus
> >> +  )
> >> +{
> >> +  if (LastAttemptStatus == NULL) {
> >> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> >> +
> >> +  if (ImageUpdatable == NULL) {
> >> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  //
> >> +  //Set to valid and then if any tests fail it will update this flag.
> >> +  //
> >> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> >> +
> >> +  if (Image == NULL) {
> >> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> >> +    //
> >> +    // Not sure if this is needed
> >> +    //
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  //
> >> +  // Make sure the image size is correct
> >> +  //
> >> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  return EFI_SUCCESS;
> >> +}
> >> +
> >>   /**
> >>   Checks if the firmware image is valid for the device.
> >>
> >> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
> >>     OUT UINT32      *ImageUpdateable
> >>     )
> >>   {
> >> -  if (ImageUpdateable == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> +  UINT32  LastAttemptStatus;
> >>
> >> -  //
> >> -  //Set to valid and then if any tests fail it will update this flag.
> >> -  //
> >> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> >> -
> >> -  if (Image == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> >> -    //
> >> -    // Not sure if this is needed
> >> -    //
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> -
> >> -  //
> >> -  // Make sure the image size is correct
> >> -  //
> >> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> -
> >> -  return EFI_SUCCESS;
> >> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
> >>   }
> >>
> >>   /**
> >> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> index db0f238ea534..132b60844ad4 100644
> >> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> @@ -1,6 +1,6 @@
> >>   /**
> >>
> >> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
> >> +Copyright (c) Microsoft Corporation.<BR>
> >>   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> >>
> >>   SPDX-License-Identifier: BSD-2-Clause-Patent
> >> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> >>
> >>
> >>   #include <PiDxe.h>
> >> +#include <LastAttemptStatus.h>
> >> +#include <Guid/SystemResourceTable.h>
> >>   #include <Library/DebugLib.h>
> >>   #include <Protocol/FirmwareManagement.h>
> >>   #include <Library/BaseLib.h>
> >> @@ -345,6 +347,131 @@ Return Value:
> >>   }//GetImage()
> >>
> >>
> >> +/**
> >> +  Updates a firmware device with a new firmware image.  This function returns
> >> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> >> +  is updatable, the function should perform the following minimal validations
> >> +  before proceeding to do the firmware image update.
> >> +    - Validate that the image is a supported image for this firmware device.
> >> +      Return EFI_ABORTED if the image is not supported.  Additional details
> >> +      on why the image is not a supported image may be returned in AbortReason.
> >> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> >> +      validation must be performed before VendorCode data validation.
> >> +      VendorCode data is ignored or considered invalid if image validation
> >> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> >> +
> >> +  VendorCode enables vendor to implement vendor-specific firmware image update
> >> +  policy.  Null if the caller did not specify the policy or use the default
> >> +  policy.  As an example, vendor can implement a policy to allow an option to
> >> +  force a firmware image update when the abort reason is due to the new firmware
> >> +  image version is older than the current firmware image version or bad image
> >> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> >> +  and render the device to be non-functional should be encoded in the image
> >> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> >> +  have the option to provide a more detailed description of the abort reason to
> >> +  the caller.
> >> +
> >> +  @param[in]  Image             Points to the new firmware image.
> >> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
> >> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> +                                firmware image update policy.  NULL indicates
> >> +                                the caller did not specify the policy or use the
> >> +                                default policy.
> >> +  @param[in]  Progress          A function used to report the progress of
> >> +                                updating the firmware device with the new
> >> +                                firmware image.
> >> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> >> +                                update capsule that provided the new firmware
> >> +                                image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> >> +                                Unicode string providing more details on an
> >> +                                aborted operation. The buffer is allocated by
> >> +                                this function with
> >> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> >> +                                caller's responsibility to free this buffer with
> >> +                                EFI_BOOT_SERVICES.FreePool().
> >> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> >> +                                status to report back to the ESRT table in case
> >> +                                of error. This value will only be checked when this
> >> +                                function returns an error.
> >> +
> >> +                                The return status code must fall in the range of
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                If the value falls outside this range, it will be converted
> >> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> >> +                                 with the new firmware image.
> >> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> >> +                                 are provided in AbortReason.
> >> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
> >> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceSetImageWithStatus (
> >> +  IN  CONST VOID                                     *Image,
> >> +  IN  UINTN                                          ImageSize,
> >> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
> >> +  IN  UINT32                                         CapsuleFwVersion,
> >> +  OUT CHAR16                                         **AbortReason,
> >> +  OUT UINT32                                         *LastAttemptStatus
> >> +  )
> >> +{
> >> +    EFI_STATUS Status                         = EFI_SUCCESS;
> >> +    UINT32 Updateable                         = 0;
> >> +
> >> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
> >> +    if (EFI_ERROR(Status))
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed with %r.\n", Status));
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    if (Updateable != IMAGE_UPDATABLE_VALID)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image returned that the Image was not valid for update.
> >> Updatable value = 0x%X.\n", Updateable));
> >> +        Status = EFI_ABORTED;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    if (Progress == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress callback\n"));
> >> +        Status = EFI_INVALID_PARAMETER;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    Status = Progress(15);
> >> +    if (EFI_ERROR(Status))
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback failed with Status %r.\n", Status));
> >> +    }
> >> +
> >> +    {
> >> +      UINTN  p;
> >> +
> >> +      for (p = 20; p < 100; p++) {
> >> +        gBS->Stall (100000);  //us  = 0.1 seconds
> >> +        Progress (p);
> >> +      }
> >> +    }
> >> +
> >> +    //TODO: add support for VendorCode, and AbortReason
> >> +cleanup:
> >> +    if (EFI_ERROR (Status)) {
> >> +      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    }
> >> +
> >> +    return Status;
> >> +}// SetImageWithStatus()
> >> +
> >> +
> >>   /**
> >>   Updates the firmware image of the device.
> >>
> >> @@ -396,51 +523,98 @@ IN  UINT32                                           CapsuleFwVersion,
> >>   OUT CHAR16                                           **AbortReason
> >>   )
> >>   {
> >> -    EFI_STATUS Status                         = EFI_SUCCESS;
> >> -    UINT32 Updateable                         = 0;
> >> -
> >> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
> >> -    if (EFI_ERROR(Status))
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with %r.\n", Status));
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    if (Updateable != IMAGE_UPDATABLE_VALID)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the Image was not valid for update.  Updatable value
> =
> >> 0x%X.\n", Updateable));
> >> -        Status = EFI_ABORTED;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    if (Progress == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
> >> -        Status = EFI_INVALID_PARAMETER;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    Status = Progress(15);
> >> -    if (EFI_ERROR(Status))
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with Status %r.\n", Status));
> >> -    }
> >> -
> >> -    {
> >> -      UINTN  p;
> >> -
> >> -      for (p = 20; p < 100; p++) {
> >> -        gBS->Stall (100000);  //us  = 0.1 seconds
> >> -        Progress (p);
> >> -      }
> >> -    }
> >> -
> >> -    //TODO: add support for VendorCode, and AbortReason
> >> -cleanup:
> >> -    return Status;
> >> +  UINT32  LastAttemptStatus;
> >> +
> >> +  return  FmpDeviceSetImageWithStatus (
> >> +            Image,
> >> +            ImageSize,
> >> +            VendorCode,
> >> +            Progress,
> >> +            CapsuleFwVersion,
> >> +            AbortReason,
> >> +            &LastAttemptStatus
> >> +            );
> >>   }// SetImage()
> >>
> >>
> >> +/**
> >> +  Checks if a new firmware image is valid for the firmware device.  This
> >> +  function allows firmware update operation to validate the firmware image
> >> +  before FmpDeviceSetImage() is called.
> >> +
> >> +  @param[in]  Image               Points to a new firmware image.
> >> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> >> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> >> +                                  a firmware update to the firmware device.  The
> >> +                                  following values from the Firmware Management
> >> +                                  Protocol are supported:
> >> +                                    IMAGE_UPDATABLE_VALID
> >> +                                    IMAGE_UPDATABLE_INVALID
> >> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> >> +                                    IMAGE_UPDATABLE_INVALID_OLD
> >> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> >> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> >> +                                  status to report back to the ESRT table in case
> >> +                                  of error. This value will only be checked when this
> >> +                                  function returns an error.
> >> +
> >> +                                  The return status code must fall in the range of
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                  If the value falls outside this range, it will be converted
> >> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> >> +                                 status information is returned in
> >> +                                 ImageUpdatable.
> >> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceCheckImageWithStatus (
> >> +  IN  CONST VOID  *Image,
> >> +  IN  UINTN       ImageSize,
> >> +  OUT UINT32      *ImageUpdatable,
> >> +  OUT UINT32      *LastAttemptStatus
> >> +  )
> >> +{
> >> +    EFI_STATUS status = EFI_SUCCESS;
> >> +
> >> +    if (LastAttemptStatus == NULL) {
> >> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> >> +      return EFI_INVALID_PARAMETER;
> >> +    }
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> >> +
> >> +    if (ImageUpdatable == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> >> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +        status = EFI_INVALID_PARAMETER;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    //
> >> +    //Set to valid and then if any tests fail it will update this flag.
> >> +    //
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> >> +
> >> +    if (Image == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> >> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> >> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +        return EFI_INVALID_PARAMETER;
> >> +    }
> >> +
> >> +cleanup:
> >> +    return status;
> >> +}// CheckImageWithStatus()
> >> +
> >>
> >>   /**
> >>   Checks if the firmware image is valid for the device.
> >> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
> >>   OUT UINT32                            *ImageUpdateable
> >>   )
> >>   {
> >> -    EFI_STATUS status = EFI_SUCCESS;
> >> +  UINT32  LastAttemptStatus;
> >>
> >> -    if (ImageUpdateable == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> >> -        status = EFI_INVALID_PARAMETER;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    //
> >> -    //Set to valid and then if any tests fail it will update this flag.
> >> -    //
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> >> -
> >> -    if (Image == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> >> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> >> -        return EFI_INVALID_PARAMETER;
> >> -    }
> >> -
> >> -cleanup:
> >> -    return status;
> >> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
> >>   }// CheckImage()
> >>
> >>   /**
> >> --
> >> 2.28.0.windows.1
> >






[-- Attachment #2: Type: text/html, Size: 84322 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
  2020-11-11  4:16       ` [edk2-devel] " Kilian Kegel
@ 2020-11-11  5:17         ` Michael Kubacki
  2020-11-11 17:17         ` Michael D Kinney
  1 sibling, 0 replies; 10+ messages in thread
From: Michael Kubacki @ 2020-11-11  5:17 UTC (permalink / raw)
  To: Kilian Kegel, devel@edk2.groups.io, michael.d.kinney@intel.com
  Cc: Qian, Yi, Sun, Zailiang

Hi Kilian,

That was broken due to FmpDevicePkg changes unrelated to these Last 
Attempt Status changes. I ran into the same isues as you when attempting 
to test this.


I believe Mike made those fixes in the following two commits:
1. 2fcfe4763022c1665be8e6a11f80aa69f0a58dce
2. b0de06c7d8494d05b315fb4a2574664f151e108d

Thanks,
Michael

On 11/10/2020 8:16 PM, Kilian Kegel wrote:
> Hi all,
> 
> if this patch also affects 
> https://bugzilla.tianocore.org/show_bug.cgi?id=2983 
> <https://bugzilla.tianocore.org/show_bug.cgi?id=2983>, please close it.
> 
> Thanks,
> 
> Kilian
> 
> *Von: *Michael D Kinney <mailto:michael.d.kinney@intel.com>
> *Gesendet: *Wednesday, November 11, 2020 4:03 AM
> *An: *Michael Kubacki <mailto:michael.kubacki@outlook.com>; 
> devel@edk2.groups.io <mailto:devel@edk2.groups.io>; Kinney, Michael D 
> <mailto:michael.d.kinney@intel.com>
> *Cc: *Qian, Yi <mailto:yi.qian@intel.com>; Sun, Zailiang 
> <mailto:zailiang.sun@intel.com>
> *Betreff: *Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] 
> Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
> 
> Hi Michael,
> 
> This patch has been merged.
> 
> Thanks,
> 
> Mike
> 
>  > -----Original Message-----
>  > From: Michael Kubacki <michael.kubacki@outlook.com>
>  > Sent: Thursday, November 5, 2020 12:36 PM
>  > To: Kinney, Michael D <michael.d.kinney@intel.com>; devel@edk2.groups.io
>  > Cc: Qian, Yi <yi.qian@intel.com>; Sun, Zailiang <zailiang.sun@intel.com>
>  > Subject: Re: [edk2-platforms][PATCH v1 1/1] 
> Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
>  >
>  > Hi Mike,
>  >
>  > I saw other Vlv2TbltDevicePkg patches were merged yesterday. Do you know
>  > when this patch will be merged?
>  >
>  > Thanks,
>  > Michael
>  >
>  > On 10/28/2020 6:12 PM, Kinney, Michael D wrote:
>  > > Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
>  > >
>  > > I also verified build and boot and FMP based capsule updates work 
> as expected.
>  > >
>  > > Tested-by: Michael D Kinney <Michael.d.kinney@intel.com>
>  > >
>  > > Thanks,
>  > >
>  > > Mike
>  > >
>  > >
>  > >> -----Original Message-----
>  > >> From: michael.kubacki@outlook.com <michael.kubacki@outlook.com>
>  > >> Sent: Thursday, October 1, 2020 2:59 PM
>  > >> To: devel@edk2.groups.io
>  > >> Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Qian, Yi 
> <yi.qian@intel.com>; Sun, Zailiang
>  > <zailiang.sun@intel.com>
>  > >> Subject: [edk2-platforms][PATCH v1 1/1] 
> Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
>  > >>
>  > >> From: Michael Kubacki <michael.kubacki@microsoft.com>
>  > >>
>  > >> Makes the changes necessary for these library instances of
>  > >> FmpDeviceLib to be compatible with new functions added recently
>  > >> to FmpDeviceLib.
>  > >>
>  > >> Two new functions were introduced in FmpDeviceLib to allow a
>  > >> library instance to return a Last Attempt Status code during
>  > >> check image and set image operations:
>  > >>    1. FmpDeviceCheckImageWithStatus ( )
>  > >>    2. FmpDeviceSetImageWithStatus ( )
>  > >>
>  > >> FmpDxe (in FmpDevicePkg) will begin calling these new functions
>  > >> instead of the previous functions. Therefore, this change:
>  > >>    1. Adds these functions to Vlv2TbltDevicePkg implementations
>  > >>    2. Moves the main functionality to these new functions
>  > >>    3. Updates the old functions to call the new functions
>  > >>       (for backward compatibility)
>  > >>
>  > >> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
>  > >> due to:
>  > >>    1. A required RngLib library instance not defined by the platform
>  > >>    2. Other FMP libraries not being defined by the platform
>  > >>       (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
>  > >>
>  > >> Those changes were fixed locally to test the changes in this commit
>  > >> but maintainers should make the proper changes for those issues.
>  > >>
>  > >> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>  > >> Cc: Yi Qian <yi.qian@intel.com>
>  > >> Cc: Zailiang Sun <zailiang.sun@intel.com>
>  > >> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
>  > >> ---
>  > >>
>  > >> Notes:
>  > >>      Only build was checked, I do not have access to a
>  > >>      VLV2 device for testing.
>  > >>
>  > >>   
> Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       
> | 299 +++++++++++++++-----
>  > >>   
> Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c 
> | 284 ++++++++++++++-----
>  > >>   2 files changed, 446 insertions(+), 137 deletions(-)
>  > >>
>  > >> diff --git 
> a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>  > >> 
> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>  > >> index d8c9036012ad..df8a36d9854c 100644
>  > >> --- 
> a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>  > >> +++ 
> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
>  > >> @@ -1,6 +1,6 @@
>  > >>   /**
>  > >>
>  > >> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
>  > >> +Copyright (c) Microsoft Corporation.<BR>
>  > >>   Copyright (c) 2019, Intel Corporation.  All rights reserved.
>  > >>
>  > >>   SPDX-License-Identifier: BSD-2-Clause-Patent
>  > >> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>  > >>   **/
>  > >>
>  > >>   #include <PiDxe.h>
>  > >> -
>  > >> +#include <LastAttemptStatus.h>
>  > >> +#include <Guid/SystemResourceTable.h>
>  > >>   #include <Library/FmpDeviceLib.h>
>  > >>
>  > >>   #include <Library/DebugLib.h>
>  > >> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
>  > >>   }
>  > >>
>  > >>   /**
>  > >> -  Updates the firmware image of the device.
>  > >> -
>  > >> -  This function updates the hardware with the new firmware 
> image.  This function
>  > >> -  returns EFI_UNSUPPORTED if the firmware image is not 
> updatable.  If the
>  > >> -  firmware image is updatable, the function should perform the 
> following minimal
>  > >> -  validations before proceeding to do the firmware image update.
>  > >> -    - Validate the image is a supported image for this device.
> The function
>  > >> -      returns EFI_ABORTED if the image is unsupported.  The 
> function can
>  > >> -      optionally provide more detailed information on why the 
> image is not a
>  > >> -      supported image.
>  > >> -    - Validate the data from VendorCode if not null.  Image 
> validation must be
>  > >> -      performed before VendorCode data validation.  VendorCode 
> data is ignored
>  > >> -      or considered invalid if image validation failed.  The 
> function returns
>  > >> -      EFI_ABORTED if the data is invalid.
>  > >> +  Updates a firmware device with a new firmware image.  This 
> function returns
>  > >> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the 
> firmware image
>  > >> +  is updatable, the function should perform the following minimal 
> validations
>  > >> +  before proceeding to do the firmware image update.
>  > >> +    - Validate that the image is a supported image for this 
> firmware device.
>  > >> +      Return EFI_ABORTED if the image is not supported.
> Additional details
>  > >> +      on why the image is not a supported image may be returned 
> in AbortReason.
>  > >> +    - Validate the data from VendorCode if is not NULL.  Firmware 
> image
>  > >> +      validation must be performed before VendorCode data validation.
>  > >> +      VendorCode data is ignored or considered invalid if image 
> validation
>  > >> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>  > >>
>  > >>     VendorCode enables vendor to implement vendor-specific 
> firmware image update
>  > >>     policy.  Null if the caller did not specify the policy or use 
> the default
>  > >> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
>  > >>     have the option to provide a more detailed description of the 
> abort reason to
>  > >>     the caller.
>  > >>
>  > >> -  @param[in]  Image             Points to the new image.
>  > >> -  @param[in]  ImageSize         Size of the new image in bytes.
>  > >> +  @param[in]  Image             Points to the new firmware image.
>  > >> +  @param[in]  ImageSize         Size, in bytes, of the new 
> firmware image.
>  > >>     @param[in]  VendorCode        This enables vendor to implement 
> vendor-specific
>  > >> -                                firmware image update policy. 
> Null indicates the
>  > >> -                                caller did not specify the policy 
> or use the
>  > >> +                                firmware image update policy.
> NULL indicates
>  > >> +                                the caller did not specify the 
> policy or use the
>  > >>                                   default policy.
>  > >> -  @param[in]  Progress          A function used by the driver to 
> report the
>  > >> -                                progress of the firmware update.
>  > >> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the 
> image.
>  > >> -  @param[out] AbortReason       A pointer to a pointer to a 
> null-terminated
>  > >> -                                string providing more details for 
> the aborted
>  > >> -                                operation. The buffer is 
> allocated by this
>  > >> -                                function with AllocatePool(), and 
> it is the
>  > >> -                                caller's responsibility to free 
> it with a call
>  > >> -                                to FreePool().
>  > >> +  @param[in]  Progress          A function used to report the 
> progress of
>  > >> +                                updating the firmware device with 
> the new
>  > >> +                                firmware image.
>  > >> +  @param[in]  CapsuleFwVersion  The version of the new firmware 
> image from the
>  > >> +                                update capsule that provided the 
> new firmware
>  > >> +                                image.
>  > >> +  @param[out] AbortReason       A pointer to a pointer to a 
> Null-terminated
>  > >> +                                Unicode string providing more 
> details on an
>  > >> +                                aborted operation. The buffer is 
> allocated by
>  > >> +                                this function with
>  > >> +
> EFI_BOOT_SERVICES.AllocatePool().  It is the
>  > >> +                                caller's responsibility to free 
> this buffer with
>  > >> +                                EFI_BOOT_SERVICES.FreePool().
>  > >> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds 
> the last attempt
>  > >> +                                status to report back to the ESRT 
> table in case
>  > >> +                                of error. This value will only be 
> checked when this
>  > >> +                                function returns an error.
>  > >>
>  > >> -  @retval EFI_SUCCESS            The device was successfully 
> updated with the
>  > >> -                                 new image.
>  > >> -  @retval EFI_ABORTED            The operation is aborted.
>  > >> +                                The return status code must fall 
> in the range of
>  > >> +
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>  > >> +
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>  > >> +
>  > >> +                                If the value falls outside this 
> range, it will be converted
>  > >> +                                to 
> LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>  > >> +
>  > >> +  @retval EFI_SUCCESS            The firmware device was 
> successfully updated
>  > >> +                                 with the new firmware image.
>  > >> +  @retval EFI_ABORTED            The operation is aborted.
> Additional details
>  > >> +                                 are provided in AbortReason.
>  > >>     @retval EFI_INVALID_PARAMETER  The Image was NULL.
>  > >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>  > >>     @retval EFI_UNSUPPORTED        The operation is not supported.
>  > >>
>  > >>   **/
>  > >>   EFI_STATUS
>  > >>   EFIAPI
>  > >> -FmpDeviceSetImage (
>  > >> +FmpDeviceSetImageWithStatus (
>  > >>     IN  CONST VOID                                     *Image,
>  > >>     IN  UINTN                                          ImageSize,
>  > >> -  IN  CONST VOID                                     *VendorCode,
>  > >> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
>  > >> +  IN  CONST VOID                                     
> *VendorCode,       OPTIONAL
>  > >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS
> Progress,          OPTIONAL
>  > >>     IN  UINT32                                         
> CapsuleFwVersion,
>  > >> -  OUT CHAR16                                         **AbortReason
>  > >> +  OUT CHAR16                                         **AbortReason,
>  > >> +  OUT UINT32                                         
> *LastAttemptStatus
>  > >>     )
>  > >>   {
>  > >>     EFI_STATUS          Status;
>  > >> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
>  > >>     UINTN               BytesWritten;
>  > >>
>  > >>     Updateable = 0;
>  > >> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
>  > >> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, 
> &Updateable, LastAttemptStatus);
>  > >>     if (EFI_ERROR (Status)) {
>  > >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed 
> with %r.\n", Status));
>  > >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check 
> Image failed with %r.\n", Status));
>  > >>       return Status;
>  > >>     }
>  > >>
>  > >>     if (Updateable != IMAGE_UPDATABLE_VALID) {
>  > >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned 
> that the Image was not valid for update.  Updatable
>  > >> value = 0x%X.\n", Updateable));
>  > >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check 
> Image returned that the Image was not valid for update.
>  > >> Updatable value = 0x%X.\n", Updateable));
>  > >> +    *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >>       return EFI_ABORTED;
>  > >>     }
>  > >>
>  > >>     if (Progress == NULL) {
>  > >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress 
> callback\n"));
>  > >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid 
> progress callback\n"));
>  > >> +    *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >>       return EFI_INVALID_PARAMETER;
>  > >>     }
>  > >>
>  > >>     Status = Progress (15);
>  > >>     if (EFI_ERROR (Status)) {
>  > >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback 
> failed with Status %r.\n", Status));
>  > >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress 
> Callback failed with Status %r.\n", Status));
>  > >>     }
>  > >>
>  > >>     //
>  > >> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
>  > >>     //
>  > >>     Progress (20);
>  > >>     if (EFI_ERROR (Status)) {
>  > >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback 
> failed with Status %r.\n", Status));
>  > >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress 
> Callback failed with Status %r.\n", Status));
>  > >>     }
>  > >>
>  > >>     //
>  > >> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
>  > >>
>  > >>   //    Progress (Percentage);
>  > >>   //    if (EFI_ERROR (Status)) {
>  > >> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress 
> Callback failed with Status %r.\n", Status));
>  > >> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - 
> Progress Callback failed with Status %r.\n", Status));
>  > >>   //    }
>  > >>     }
>  > >>
>  > >> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", 
> ARRAY_SIZE (mUpdateConfigData)));
>  > >> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images 
> ...\n", ARRAY_SIZE (mUpdateConfigData)));
>  > >>
>  > >>     if (ARRAY_SIZE (mUpdateConfigData) == 0) {
>  > >>       DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx 
> ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
>  > >> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
>  > >>       BytesWritten += ConfigData->Length;
>  > >>     }
>  > >>
>  > >> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
>  > >> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
>  > >> +
>  > >> +  if (EFI_ERROR (Status)) {
>  > >> +    *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >> +  }
>  > >>
>  > >>     return Status;
>  > >>   }
>  > >>
>  > >> +/**
>  > >> +  Updates the firmware image of the device.
>  > >> +
>  > >> +  This function updates the hardware with the new firmware 
> image.  This function
>  > >> +  returns EFI_UNSUPPORTED if the firmware image is not 
> updatable.  If the
>  > >> +  firmware image is updatable, the function should perform the 
> following minimal
>  > >> +  validations before proceeding to do the firmware image update.
>  > >> +    - Validate the image is a supported image for this device.
> The function
>  > >> +      returns EFI_ABORTED if the image is unsupported.  The 
> function can
>  > >> +      optionally provide more detailed information on why the 
> image is not a
>  > >> +      supported image.
>  > >> +    - Validate the data from VendorCode if not null.  Image 
> validation must be
>  > >> +      performed before VendorCode data validation.  VendorCode 
> data is ignored
>  > >> +      or considered invalid if image validation failed.  The 
> function returns
>  > >> +      EFI_ABORTED if the data is invalid.
>  > >> +
>  > >> +  VendorCode enables vendor to implement vendor-specific firmware 
> image update
>  > >> +  policy.  Null if the caller did not specify the policy or use 
> the default
>  > >> +  policy.  As an example, vendor can implement a policy to allow 
> an option to
>  > >> +  force a firmware image update when the abort reason is due to 
> the new firmware
>  > >> +  image version is older than the current firmware image version 
> or bad image
>  > >> +  checksum.  Sensitive operations such as those wiping the entire 
> firmware image
>  > >> +  and render the device to be non-functional should be encoded in 
> the image
>  > >> +  itself rather than passed with the VendorCode.  AbortReason 
> enables vendor to
>  > >> +  have the option to provide a more detailed description of the 
> abort reason to
>  > >> +  the caller.
>  > >> +
>  > >> +  @param[in]  Image             Points to the new image.
>  > >> +  @param[in]  ImageSize         Size of the new image in bytes.
>  > >> +  @param[in]  VendorCode        This enables vendor to implement 
> vendor-specific
>  > >> +                                firmware image update policy. 
> Null indicates the
>  > >> +                                caller did not specify the policy 
> or use the
>  > >> +                                default policy.
>  > >> +  @param[in]  Progress          A function used by the driver to 
> report the
>  > >> +                                progress of the firmware update.
>  > >> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the 
> image.
>  > >> +  @param[out] AbortReason       A pointer to a pointer to a 
> null-terminated
>  > >> +                                string providing more details for 
> the aborted
>  > >> +                                operation. The buffer is 
> allocated by this
>  > >> +                                function with AllocatePool(), and 
> it is the
>  > >> +                                caller's responsibility to free 
> it with a call
>  > >> +                                to FreePool().
>  > >> +
>  > >> +  @retval EFI_SUCCESS            The device was successfully 
> updated with the
>  > >> +                                 new image.
>  > >> +  @retval EFI_ABORTED            The operation is aborted.
>  > >> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
>  > >> +  @retval EFI_UNSUPPORTED        The operation is not supported.
>  > >> +
>  > >> +**/
>  > >> +EFI_STATUS
>  > >> +EFIAPI
>  > >> +FmpDeviceSetImage (
>  > >> +  IN  CONST VOID                                     *Image,
>  > >> +  IN  UINTN                                          ImageSize,
>  > >> +  IN  CONST VOID                                     *VendorCode,
>  > >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
>  > >> +  IN  UINT32                                         
> CapsuleFwVersion,
>  > >> +  OUT CHAR16                                         **AbortReason
>  > >> +  )
>  > >> +{
>  > >> +  UINT32  LastAttemptStatus;
>  > >> +
>  > >> +  return  FmpDeviceSetImageWithStatus (
>  > >> +            Image,
>  > >> +            ImageSize,
>  > >> +            VendorCode,
>  > >> +            Progress,
>  > >> +            CapsuleFwVersion,
>  > >> +            AbortReason,
>  > >> +            &LastAttemptStatus
>  > >> +            );
>  > >> +}
>  > >> +
>  > >> +/**
>  > >> +  Checks if a new firmware image is valid for the firmware 
> device.  This
>  > >> +  function allows firmware update operation to validate the 
> firmware image
>  > >> +  before FmpDeviceSetImage() is called.
>  > >> +
>  > >> +  @param[in]  Image               Points to a new firmware image.
>  > >> +  @param[in]  ImageSize           Size, in bytes, of a new 
> firmware image.
>  > >> +  @param[out] ImageUpdatable      Indicates if a new firmware 
> image is valid for
>  > >> +                                  a firmware update to the 
> firmware device.  The
>  > >> +                                  following values from the 
> Firmware Management
>  > >> +                                  Protocol are supported:
>  > >> +                                    IMAGE_UPDATABLE_VALID
>  > >> +                                    IMAGE_UPDATABLE_INVALID
>  > >> +                                    IMAGE_UPDATABLE_INVALID_TYPE
>  > >> +                                    IMAGE_UPDATABLE_INVALID_OLD
>  > >> +
> IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
>  > >> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that 
> holds the last attempt
>  > >> +                                  status to report back to the 
> ESRT table in case
>  > >> +                                  of error. This value will only 
> be checked when this
>  > >> +                                  function returns an error.
>  > >> +
>  > >> +                                  The return status code must 
> fall in the range of
>  > >> +
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>  > >> +
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>  > >> +
>  > >> +                                  If the value falls outside this 
> range, it will be converted
>  > >> +                                  to 
> LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>  > >> +
>  > >> +  @retval EFI_SUCCESS            The image was successfully 
> checked.  Additional
>  > >> +                                 status information is returned in
>  > >> +                                 ImageUpdatable.
>  > >> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
>  > >> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
>  > >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
>  > >> +
>  > >> +**/
>  > >> +EFI_STATUS
>  > >> +EFIAPI
>  > >> +FmpDeviceCheckImageWithStatus (
>  > >> +  IN  CONST VOID  *Image,
>  > >> +  IN  UINTN       ImageSize,
>  > >> +  OUT UINT32      *ImageUpdatable,
>  > >> +  OUT UINT32      *LastAttemptStatus
>  > >> +  )
>  > >> +{
>  > >> +  if (LastAttemptStatus == NULL) {
>  > >> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - 
> LastAttemptStatus Pointer Parameter is NULL.\n"));
>  > >> +    return EFI_INVALID_PARAMETER;
>  > >> +  }
>  > >> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
>  > >> +
>  > >> +  if (ImageUpdatable == NULL) {
>  > >> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable 
> Pointer Parameter is NULL.\n"));
>  > >> +    *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >> +    return EFI_INVALID_PARAMETER;
>  > >> +  }
>  > >> +
>  > >> +  //
>  > >> +  //Set to valid and then if any tests fail it will update this flag.
>  > >> +  //
>  > >> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
>  > >> +
>  > >> +  if (Image == NULL) {
>  > >> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer 
> Parameter is NULL.\n"));
>  > >> +    //
>  > >> +    // Not sure if this is needed
>  > >> +    //
>  > >> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
>  > >> +    *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >> +    return EFI_INVALID_PARAMETER;
>  > >> +  }
>  > >> +
>  > >> +  //
>  > >> +  // Make sure the image size is correct
>  > >> +  //
>  > >> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
>  > >> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
>  > >> +    *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >> +    return EFI_INVALID_PARAMETER;
>  > >> +  }
>  > >> +
>  > >> +  return EFI_SUCCESS;
>  > >> +}
>  > >> +
>  > >>   /**
>  > >>   Checks if the firmware image is valid for the device.
>  > >>
>  > >> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
>  > >>     OUT UINT32      *ImageUpdateable
>  > >>     )
>  > >>   {
>  > >> -  if (ImageUpdateable == NULL) {
>  > >> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer 
> Parameter is NULL.\n"));
>  > >> -    return EFI_INVALID_PARAMETER;
>  > >> -  }
>  > >> +  UINT32  LastAttemptStatus;
>  > >>
>  > >> -  //
>  > >> -  //Set to valid and then if any tests fail it will update this flag.
>  > >> -  //
>  > >> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
>  > >> -
>  > >> -  if (Image == NULL) {
>  > >> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is 
> NULL.\n"));
>  > >> -    //
>  > >> -    // Not sure if this is needed
>  > >> -    //
>  > >> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
>  > >> -    return EFI_INVALID_PARAMETER;
>  > >> -  }
>  > >> -
>  > >> -  //
>  > >> -  // Make sure the image size is correct
>  > >> -  //
>  > >> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
>  > >> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
>  > >> -    return EFI_INVALID_PARAMETER;
>  > >> -  }
>  > >> -
>  > >> -  return EFI_SUCCESS;
>  > >> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, 
> ImageUpdateable, &LastAttemptStatus);
>  > >>   }
>  > >>
>  > >>   /**
>  > >> diff --git 
> a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>  > >> 
> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>  > >> index db0f238ea534..132b60844ad4 100644
>  > >> --- 
> a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>  > >> +++ 
> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
>  > >> @@ -1,6 +1,6 @@
>  > >>   /**
>  > >>
>  > >> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
>  > >> +Copyright (c) Microsoft Corporation.<BR>
>  > >>   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>  > >>
>  > >>   SPDX-License-Identifier: BSD-2-Clause-Patent
>  > >> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>  > >>
>  > >>
>  > >>   #include <PiDxe.h>
>  > >> +#include <LastAttemptStatus.h>
>  > >> +#include <Guid/SystemResourceTable.h>
>  > >>   #include <Library/DebugLib.h>
>  > >>   #include <Protocol/FirmwareManagement.h>
>  > >>   #include <Library/BaseLib.h>
>  > >> @@ -345,6 +347,131 @@ Return Value:
>  > >>   }//GetImage()
>  > >>
>  > >>
>  > >> +/**
>  > >> +  Updates a firmware device with a new firmware image.  This 
> function returns
>  > >> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the 
> firmware image
>  > >> +  is updatable, the function should perform the following minimal 
> validations
>  > >> +  before proceeding to do the firmware image update.
>  > >> +    - Validate that the image is a supported image for this 
> firmware device.
>  > >> +      Return EFI_ABORTED if the image is not supported.
> Additional details
>  > >> +      on why the image is not a supported image may be returned 
> in AbortReason.
>  > >> +    - Validate the data from VendorCode if is not NULL.  Firmware 
> image
>  > >> +      validation must be performed before VendorCode data validation.
>  > >> +      VendorCode data is ignored or considered invalid if image 
> validation
>  > >> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
>  > >> +
>  > >> +  VendorCode enables vendor to implement vendor-specific firmware 
> image update
>  > >> +  policy.  Null if the caller did not specify the policy or use 
> the default
>  > >> +  policy.  As an example, vendor can implement a policy to allow 
> an option to
>  > >> +  force a firmware image update when the abort reason is due to 
> the new firmware
>  > >> +  image version is older than the current firmware image version 
> or bad image
>  > >> +  checksum.  Sensitive operations such as those wiping the entire 
> firmware image
>  > >> +  and render the device to be non-functional should be encoded in 
> the image
>  > >> +  itself rather than passed with the VendorCode.  AbortReason 
> enables vendor to
>  > >> +  have the option to provide a more detailed description of the 
> abort reason to
>  > >> +  the caller.
>  > >> +
>  > >> +  @param[in]  Image             Points to the new firmware image.
>  > >> +  @param[in]  ImageSize         Size, in bytes, of the new 
> firmware image.
>  > >> +  @param[in]  VendorCode        This enables vendor to implement 
> vendor-specific
>  > >> +                                firmware image update policy.
> NULL indicates
>  > >> +                                the caller did not specify the 
> policy or use the
>  > >> +                                default policy.
>  > >> +  @param[in]  Progress          A function used to report the 
> progress of
>  > >> +                                updating the firmware device with 
> the new
>  > >> +                                firmware image.
>  > >> +  @param[in]  CapsuleFwVersion  The version of the new firmware 
> image from the
>  > >> +                                update capsule that provided the 
> new firmware
>  > >> +                                image.
>  > >> +  @param[out] AbortReason       A pointer to a pointer to a 
> Null-terminated
>  > >> +                                Unicode string providing more 
> details on an
>  > >> +                                aborted operation. The buffer is 
> allocated by
>  > >> +                                this function with
>  > >> +
> EFI_BOOT_SERVICES.AllocatePool().  It is the
>  > >> +                                caller's responsibility to free 
> this buffer with
>  > >> +                                EFI_BOOT_SERVICES.FreePool().
>  > >> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds 
> the last attempt
>  > >> +                                status to report back to the ESRT 
> table in case
>  > >> +                                of error. This value will only be 
> checked when this
>  > >> +                                function returns an error.
>  > >> +
>  > >> +                                The return status code must fall 
> in the range of
>  > >> +
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>  > >> +
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>  > >> +
>  > >> +                                If the value falls outside this 
> range, it will be converted
>  > >> +                                to 
> LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>  > >> +
>  > >> +  @retval EFI_SUCCESS            The firmware device was 
> successfully updated
>  > >> +                                 with the new firmware image.
>  > >> +  @retval EFI_ABORTED            The operation is aborted.
> Additional details
>  > >> +                                 are provided in AbortReason.
>  > >> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
>  > >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
>  > >> +  @retval EFI_UNSUPPORTED        The operation is not supported.
>  > >> +
>  > >> +**/
>  > >> +EFI_STATUS
>  > >> +EFIAPI
>  > >> +FmpDeviceSetImageWithStatus (
>  > >> +  IN  CONST VOID                                     *Image,
>  > >> +  IN  UINTN                                          ImageSize,
>  > >> +  IN  CONST VOID                                     
> *VendorCode,       OPTIONAL
>  > >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS
> Progress,          OPTIONAL
>  > >> +  IN  UINT32                                         
> CapsuleFwVersion,
>  > >> +  OUT CHAR16                                         **AbortReason,
>  > >> +  OUT UINT32                                         
> *LastAttemptStatus
>  > >> +  )
>  > >> +{
>  > >> +    EFI_STATUS Status                         = EFI_SUCCESS;
>  > >> +    UINT32 Updateable                         = 0;
>  > >> +
>  > >> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, 
> &Updateable, LastAttemptStatus);
>  > >> +    if (EFI_ERROR(Status))
>  > >> +    {
>  > >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image 
> failed with %r.\n", Status));
>  > >> +        goto cleanup;
>  > >> +    }
>  > >> +
>  > >> +    if (Updateable != IMAGE_UPDATABLE_VALID)
>  > >> +    {
>  > >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image 
> returned that the Image was not valid for update.
>  > >> Updatable value = 0x%X.\n", Updateable));
>  > >> +        Status = EFI_ABORTED;
>  > >> +        goto cleanup;
>  > >> +    }
>  > >> +
>  > >> +    if (Progress == NULL)
>  > >> +    {
>  > >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid 
> progress callback\n"));
>  > >> +        Status = EFI_INVALID_PARAMETER;
>  > >> +        goto cleanup;
>  > >> +    }
>  > >> +
>  > >> +    Status = Progress(15);
>  > >> +    if (EFI_ERROR(Status))
>  > >> +    {
>  > >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress 
> Callback failed with Status %r.\n", Status));
>  > >> +    }
>  > >> +
>  > >> +    {
>  > >> +      UINTN  p;
>  > >> +
>  > >> +      for (p = 20; p < 100; p++) {
>  > >> +        gBS->Stall (100000);  //us  = 0.1 seconds
>  > >> +        Progress (p);
>  > >> +      }
>  > >> +    }
>  > >> +
>  > >> +    //TODO: add support for VendorCode, and AbortReason
>  > >> +cleanup:
>  > >> +    if (EFI_ERROR (Status)) {
>  > >> +      *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >> +    }
>  > >> +
>  > >> +    return Status;
>  > >> +}// SetImageWithStatus()
>  > >> +
>  > >> +
>  > >>   /**
>  > >>   Updates the firmware image of the device.
>  > >>
>  > >> @@ -396,51 +523,98 @@ IN
> UINT32                                           CapsuleFwVersion,
>  > >>   OUT CHAR16                                           **AbortReason
>  > >>   )
>  > >>   {
>  > >> -    EFI_STATUS Status                         = EFI_SUCCESS;
>  > >> -    UINT32 Updateable                         = 0;
>  > >> -
>  > >> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
>  > >> -    if (EFI_ERROR(Status))
>  > >> -    {
>  > >> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with 
> %r.\n", Status));
>  > >> -        goto cleanup;
>  > >> -    }
>  > >> -
>  > >> -    if (Updateable != IMAGE_UPDATABLE_VALID)
>  > >> -    {
>  > >> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that 
> the Image was not valid for update.  Updatable value
>  > =
>  > >> 0x%X.\n", Updateable));
>  > >> -        Status = EFI_ABORTED;
>  > >> -        goto cleanup;
>  > >> -    }
>  > >> -
>  > >> -    if (Progress == NULL)
>  > >> -    {
>  > >> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress 
> callback\n"));
>  > >> -        Status = EFI_INVALID_PARAMETER;
>  > >> -        goto cleanup;
>  > >> -    }
>  > >> -
>  > >> -    Status = Progress(15);
>  > >> -    if (EFI_ERROR(Status))
>  > >> -    {
>  > >> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed 
> with Status %r.\n", Status));
>  > >> -    }
>  > >> -
>  > >> -    {
>  > >> -      UINTN  p;
>  > >> -
>  > >> -      for (p = 20; p < 100; p++) {
>  > >> -        gBS->Stall (100000);  //us  = 0.1 seconds
>  > >> -        Progress (p);
>  > >> -      }
>  > >> -    }
>  > >> -
>  > >> -    //TODO: add support for VendorCode, and AbortReason
>  > >> -cleanup:
>  > >> -    return Status;
>  > >> +  UINT32  LastAttemptStatus;
>  > >> +
>  > >> +  return  FmpDeviceSetImageWithStatus (
>  > >> +            Image,
>  > >> +            ImageSize,
>  > >> +            VendorCode,
>  > >> +            Progress,
>  > >> +            CapsuleFwVersion,
>  > >> +            AbortReason,
>  > >> +            &LastAttemptStatus
>  > >> +            );
>  > >>   }// SetImage()
>  > >>
>  > >>
>  > >> +/**
>  > >> +  Checks if a new firmware image is valid for the firmware 
> device.  This
>  > >> +  function allows firmware update operation to validate the 
> firmware image
>  > >> +  before FmpDeviceSetImage() is called.
>  > >> +
>  > >> +  @param[in]  Image               Points to a new firmware image.
>  > >> +  @param[in]  ImageSize           Size, in bytes, of a new 
> firmware image.
>  > >> +  @param[out] ImageUpdatable      Indicates if a new firmware 
> image is valid for
>  > >> +                                  a firmware update to the 
> firmware device.  The
>  > >> +                                  following values from the 
> Firmware Management
>  > >> +                                  Protocol are supported:
>  > >> +                                    IMAGE_UPDATABLE_VALID
>  > >> +                                    IMAGE_UPDATABLE_INVALID
>  > >> +                                    IMAGE_UPDATABLE_INVALID_TYPE
>  > >> +                                    IMAGE_UPDATABLE_INVALID_OLD
>  > >> +
> IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
>  > >> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that 
> holds the last attempt
>  > >> +                                  status to report back to the 
> ESRT table in case
>  > >> +                                  of error. This value will only 
> be checked when this
>  > >> +                                  function returns an error.
>  > >> +
>  > >> +                                  The return status code must 
> fall in the range of
>  > >> +
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
>  > >> +
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
>  > >> +
>  > >> +                                  If the value falls outside this 
> range, it will be converted
>  > >> +                                  to 
> LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
>  > >> +
>  > >> +  @retval EFI_SUCCESS            The image was successfully 
> checked.  Additional
>  > >> +                                 status information is returned in
>  > >> +                                 ImageUpdatable.
>  > >> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
>  > >> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
>  > >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
>  > >> +
>  > >> +**/
>  > >> +EFI_STATUS
>  > >> +EFIAPI
>  > >> +FmpDeviceCheckImageWithStatus (
>  > >> +  IN  CONST VOID  *Image,
>  > >> +  IN  UINTN       ImageSize,
>  > >> +  OUT UINT32      *ImageUpdatable,
>  > >> +  OUT UINT32      *LastAttemptStatus
>  > >> +  )
>  > >> +{
>  > >> +    EFI_STATUS status = EFI_SUCCESS;
>  > >> +
>  > >> +    if (LastAttemptStatus == NULL) {
>  > >> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - 
> LastAttemptStatus Pointer Parameter is NULL.\n"));
>  > >> +      return EFI_INVALID_PARAMETER;
>  > >> +    }
>  > >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
>  > >> +
>  > >> +    if (ImageUpdatable == NULL)
>  > >> +    {
>  > >> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - 
> ImageUpdatable Pointer Parameter is NULL.\n"));
>  > >> +        *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >> +        status = EFI_INVALID_PARAMETER;
>  > >> +        goto cleanup;
>  > >> +    }
>  > >> +
>  > >> +    //
>  > >> +    //Set to valid and then if any tests fail it will update this 
> flag.
>  > >> +    //
>  > >> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
>  > >> +
>  > >> +    if (Image == NULL)
>  > >> +    {
>  > >> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer 
> Parameter is NULL.\n"));
>  > >> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if 
> this is needed
>  > >> +        *LastAttemptStatus = 
> LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
>  > >> +        return EFI_INVALID_PARAMETER;
>  > >> +    }
>  > >> +
>  > >> +cleanup:
>  > >> +    return status;
>  > >> +}// CheckImageWithStatus()
>  > >> +
>  > >>
>  > >>   /**
>  > >>   Checks if the firmware image is valid for the device.
>  > >> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
>  > >>   OUT UINT32                            *ImageUpdateable
>  > >>   )
>  > >>   {
>  > >> -    EFI_STATUS status = EFI_SUCCESS;
>  > >> +  UINT32  LastAttemptStatus;
>  > >>
>  > >> -    if (ImageUpdateable == NULL)
>  > >> -    {
>  > >> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer 
> Parameter is NULL.\n"));
>  > >> -        status = EFI_INVALID_PARAMETER;
>  > >> -        goto cleanup;
>  > >> -    }
>  > >> -
>  > >> -    //
>  > >> -    //Set to valid and then if any tests fail it will update this 
> flag.
>  > >> -    //
>  > >> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
>  > >> -
>  > >> -    if (Image == NULL)
>  > >> -    {
>  > >> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter 
> is NULL.\n"));
>  > >> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if 
> this is needed
>  > >> -        return EFI_INVALID_PARAMETER;
>  > >> -    }
>  > >> -
>  > >> -cleanup:
>  > >> -    return status;
>  > >> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, 
> ImageUpdateable, &LastAttemptStatus);
>  > >>   }// CheckImage()
>  > >>
>  > >>   /**
>  > >> --
>  > >> 2.28.0.windows.1
>  > >
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
  2020-11-11  4:16       ` [edk2-devel] " Kilian Kegel
  2020-11-11  5:17         ` Michael Kubacki
@ 2020-11-11 17:17         ` Michael D Kinney
  1 sibling, 0 replies; 10+ messages in thread
From: Michael D Kinney @ 2020-11-11 17:17 UTC (permalink / raw)
  To: devel@edk2.groups.io, KILIAN_KEGEL@OUTLOOK.COM, Michael Kubacki,
	Kinney, Michael D
  Cc: Qian, Yi, Sun, Zailiang

[-- Attachment #1: Type: text/plain, Size: 41535 bytes --]

Hi Kilian,

2983 was resolved by a previous commit.  Thank you for the reminder to update the BZ with the details.  It is closed now.

Mike

From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Kilian Kegel
Sent: Tuesday, November 10, 2020 8:17 PM
To: devel@edk2.groups.io; Kinney, Michael D <michael.d.kinney@intel.com>; Michael Kubacki <michael.kubacki@outlook.com>
Cc: Qian, Yi <yi.qian@intel.com>; Sun, Zailiang <zailiang.sun@intel.com>
Subject: Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility

Hi all,

if this patch also affects https://bugzilla.tianocore.org/show_bug.cgi?id=2983, please close it.

Thanks,
Kilian

Von: Michael D Kinney<mailto:michael.d.kinney@intel.com>
Gesendet: Wednesday, November 11, 2020 4:03 AM
An: Michael Kubacki<mailto:michael.kubacki@outlook.com>; devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Kinney, Michael D<mailto:michael.d.kinney@intel.com>
Cc: Qian, Yi<mailto:yi.qian@intel.com>; Sun, Zailiang<mailto:zailiang.sun@intel.com>
Betreff: Re: [edk2-devel] [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility

Hi Michael,

This patch has been merged.

Thanks,

Mike

> -----Original Message-----
> From: Michael Kubacki <michael.kubacki@outlook.com<mailto:michael.kubacki@outlook.com>>
> Sent: Thursday, November 5, 2020 12:36 PM
> To: Kinney, Michael D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>; devel@edk2.groups.io<mailto:devel@edk2.groups.io>
> Cc: Qian, Yi <yi.qian@intel.com<mailto:yi.qian@intel.com>>; Sun, Zailiang <zailiang.sun@intel.com<mailto:zailiang.sun@intel.com>>
> Subject: Re: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
>
> Hi Mike,
>
> I saw other Vlv2TbltDevicePkg patches were merged yesterday. Do you know
> when this patch will be merged?
>
> Thanks,
> Michael
>
> On 10/28/2020 6:12 PM, Kinney, Michael D wrote:
> > Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
> >
> > I also verified build and boot and FMP based capsule updates work as expected.
> >
> > Tested-by: Michael D Kinney <Michael.d.kinney@intel.com<mailto:Michael.d.kinney@intel.com>>
> >
> > Thanks,
> >
> > Mike
> >
> >
> >> -----Original Message-----
> >> From: michael.kubacki@outlook.com<mailto:michael.kubacki@outlook.com> <michael.kubacki@outlook.com<mailto:michael.kubacki@outlook.com>>
> >> Sent: Thursday, October 1, 2020 2:59 PM
> >> To: devel@edk2.groups.io<mailto:devel@edk2.groups.io>
> >> Cc: Kinney, Michael D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>; Qian, Yi <yi.qian@intel.com<mailto:yi.qian@intel.com>>; Sun, Zailiang
> <zailiang.sun@intel.com<mailto:zailiang.sun@intel.com>>
> >> Subject: [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility
> >>
> >> From: Michael Kubacki <michael.kubacki@microsoft.com<mailto:michael.kubacki@microsoft.com>>
> >>
> >> Makes the changes necessary for these library instances of
> >> FmpDeviceLib to be compatible with new functions added recently
> >> to FmpDeviceLib.
> >>
> >> Two new functions were introduced in FmpDeviceLib to allow a
> >> library instance to return a Last Attempt Status code during
> >> check image and set image operations:
> >>    1. FmpDeviceCheckImageWithStatus ( )
> >>    2. FmpDeviceSetImageWithStatus ( )
> >>
> >> FmpDxe (in FmpDevicePkg) will begin calling these new functions
> >> instead of the previous functions. Therefore, this change:
> >>    1. Adds these functions to Vlv2TbltDevicePkg implementations
> >>    2. Moves the main functionality to these new functions
> >>    3. Updates the old functions to call the new functions
> >>       (for backward compatibility)
> >>
> >> Note: As of this commit, the Vlv2TbltDevicePkg build is broken
> >> due to:
> >>    1. A required RngLib library instance not defined by the platform
> >>    2. Other FMP libraries not being defined by the platform
> >>       (e.g. FmpDependencyLib, FmpDependencyCheckLib, etc.)
> >>
> >> Those changes were fixed locally to test the changes in this commit
> >> but maintainers should make the proper changes for those issues.
> >>
> >> Cc: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
> >> Cc: Yi Qian <yi.qian@intel.com<mailto:yi.qian@intel.com>>
> >> Cc: Zailiang Sun <zailiang.sun@intel.com<mailto:zailiang.sun@intel.com>>
> >> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com<mailto:michael.kubacki@microsoft.com>>
> >> ---
> >>
> >> Notes:
> >>      Only build was checked, I do not have access to a
> >>      VLV2 device for testing.
> >>
> >>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c       | 299 +++++++++++++++-----
> >>   Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c | 284 ++++++++++++++-----
> >>   2 files changed, 446 insertions(+), 137 deletions(-)
> >>
> >> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> index d8c9036012ad..df8a36d9854c 100644
> >> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
> >> @@ -1,6 +1,6 @@
> >>   /**
> >>
> >> -Copyright (c) 2016, Microsoft Corporation.  All rights reserved.
> >> +Copyright (c) Microsoft Corporation.<BR>
> >>   Copyright (c) 2019, Intel Corporation.  All rights reserved.
> >>
> >>   SPDX-License-Identifier: BSD-2-Clause-Patent
> >> @@ -8,7 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> >>   **/
> >>
> >>   #include <PiDxe.h>
> >> -
> >> +#include <LastAttemptStatus.h>
> >> +#include <Guid/SystemResourceTable.h>
> >>   #include <Library/FmpDeviceLib.h>
> >>
> >>   #include <Library/DebugLib.h>
> >> @@ -444,20 +445,17 @@ FmpDeviceGetImage (
> >>   }
> >>
> >>   /**
> >> -  Updates the firmware image of the device.
> >> -
> >> -  This function updates the hardware with the new firmware image.  This function
> >> -  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> >> -  firmware image is updatable, the function should perform the following minimal
> >> -  validations before proceeding to do the firmware image update.
> >> -    - Validate the image is a supported image for this device.  The function
> >> -      returns EFI_ABORTED if the image is unsupported.  The function can
> >> -      optionally provide more detailed information on why the image is not a
> >> -      supported image.
> >> -    - Validate the data from VendorCode if not null.  Image validation must be
> >> -      performed before VendorCode data validation.  VendorCode data is ignored
> >> -      or considered invalid if image validation failed.  The function returns
> >> -      EFI_ABORTED if the data is invalid.
> >> +  Updates a firmware device with a new firmware image.  This function returns
> >> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> >> +  is updatable, the function should perform the following minimal validations
> >> +  before proceeding to do the firmware image update.
> >> +    - Validate that the image is a supported image for this firmware device.
> >> +      Return EFI_ABORTED if the image is not supported.  Additional details
> >> +      on why the image is not a supported image may be returned in AbortReason.
> >> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> >> +      validation must be performed before VendorCode data validation.
> >> +      VendorCode data is ignored or considered invalid if image validation
> >> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> >>
> >>     VendorCode enables vendor to implement vendor-specific firmware image update
> >>     policy.  Null if the caller did not specify the policy or use the default
> >> @@ -470,38 +468,56 @@ FmpDeviceGetImage (
> >>     have the option to provide a more detailed description of the abort reason to
> >>     the caller.
> >>
> >> -  @param[in]  Image             Points to the new image.
> >> -  @param[in]  ImageSize         Size of the new image in bytes.
> >> +  @param[in]  Image             Points to the new firmware image.
> >> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
> >>     @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> -                                firmware image update policy. Null indicates the
> >> -                                caller did not specify the policy or use the
> >> +                                firmware image update policy.  NULL indicates
> >> +                                the caller did not specify the policy or use the
> >>                                   default policy.
> >> -  @param[in]  Progress          A function used by the driver to report the
> >> -                                progress of the firmware update.
> >> -  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> >> -  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> >> -                                string providing more details for the aborted
> >> -                                operation. The buffer is allocated by this
> >> -                                function with AllocatePool(), and it is the
> >> -                                caller's responsibility to free it with a call
> >> -                                to FreePool().
> >> +  @param[in]  Progress          A function used to report the progress of
> >> +                                updating the firmware device with the new
> >> +                                firmware image.
> >> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> >> +                                update capsule that provided the new firmware
> >> +                                image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> >> +                                Unicode string providing more details on an
> >> +                                aborted operation. The buffer is allocated by
> >> +                                this function with
> >> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> >> +                                caller's responsibility to free this buffer with
> >> +                                EFI_BOOT_SERVICES.FreePool().
> >> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> >> +                                status to report back to the ESRT table in case
> >> +                                of error. This value will only be checked when this
> >> +                                function returns an error.
> >>
> >> -  @retval EFI_SUCCESS            The device was successfully updated with the
> >> -                                 new image.
> >> -  @retval EFI_ABORTED            The operation is aborted.
> >> +                                The return status code must fall in the range of
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                If the value falls outside this range, it will be converted
> >> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> >> +                                 with the new firmware image.
> >> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> >> +                                 are provided in AbortReason.
> >>     @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
> >>     @retval EFI_UNSUPPORTED        The operation is not supported.
> >>
> >>   **/
> >>   EFI_STATUS
> >>   EFIAPI
> >> -FmpDeviceSetImage (
> >> +FmpDeviceSetImageWithStatus (
> >>     IN  CONST VOID                                     *Image,
> >>     IN  UINTN                                          ImageSize,
> >> -  IN  CONST VOID                                     *VendorCode,
> >> -  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> >> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
> >>     IN  UINT32                                         CapsuleFwVersion,
> >> -  OUT CHAR16                                         **AbortReason
> >> +  OUT CHAR16                                         **AbortReason,
> >> +  OUT UINT32                                         *LastAttemptStatus
> >>     )
> >>   {
> >>     EFI_STATUS          Status;
> >> @@ -513,25 +529,27 @@ FmpDeviceSetImage (
> >>     UINTN               BytesWritten;
> >>
> >>     Updateable = 0;
> >> -  Status = FmpDeviceCheckImage (Image, ImageSize, &Updateable);
> >> +  Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image failed with %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image failed with %r.\n", Status));
> >>       return Status;
> >>     }
> >>
> >>     if (Updateable != IMAGE_UPDATABLE_VALID) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Check Image returned that the Image was not valid for update.  Updatable
> >> value = 0x%X.\n", Updateable));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Check Image returned that the Image was not valid for update.
> >> Updatable value = 0x%X.\n", Updateable));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >>       return EFI_ABORTED;
> >>     }
> >>
> >>     if (Progress == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Invalid progress callback\n"));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >>       return EFI_INVALID_PARAMETER;
> >>     }
> >>
> >>     Status = Progress (15);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>     }
> >>
> >>     //
> >> @@ -539,7 +557,7 @@ FmpDeviceSetImage (
> >>     //
> >>     Progress (20);
> >>     if (EFI_ERROR (Status)) {
> >> -    DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +    DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>     }
> >>
> >>     //
> >> @@ -553,11 +571,11 @@ FmpDeviceSetImage (
> >>
> >>   //    Progress (Percentage);
> >>   //    if (EFI_ERROR (Status)) {
> >> -//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImage - Progress Callback failed with Status %r.\n", Status));
> >> +//      DEBUG((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Progress Callback failed with Status %r.\n", Status));
> >>   //    }
> >>     }
> >>
> >> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> >> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
> >>
> >>     if (ARRAY_SIZE (mUpdateConfigData) == 0) {
> >>       DEBUG((DEBUG_INFO, "PlatformUpdate: BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n", 0, 0, ImageSize));
> >> @@ -605,11 +623,173 @@ FmpDeviceSetImage (
> >>       BytesWritten += ConfigData->Length;
> >>     }
> >>
> >> -  DEBUG ((DEBUG_INFO, "FmpDeviceSetImage - %r\n", Status));
> >> +  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
> >> +
> >> +  if (EFI_ERROR (Status)) {
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +  }
> >>
> >>     return Status;
> >>   }
> >>
> >> +/**
> >> +  Updates the firmware image of the device.
> >> +
> >> +  This function updates the hardware with the new firmware image.  This function
> >> +  returns EFI_UNSUPPORTED if the firmware image is not updatable.  If the
> >> +  firmware image is updatable, the function should perform the following minimal
> >> +  validations before proceeding to do the firmware image update.
> >> +    - Validate the image is a supported image for this device.  The function
> >> +      returns EFI_ABORTED if the image is unsupported.  The function can
> >> +      optionally provide more detailed information on why the image is not a
> >> +      supported image.
> >> +    - Validate the data from VendorCode if not null.  Image validation must be
> >> +      performed before VendorCode data validation.  VendorCode data is ignored
> >> +      or considered invalid if image validation failed.  The function returns
> >> +      EFI_ABORTED if the data is invalid.
> >> +
> >> +  VendorCode enables vendor to implement vendor-specific firmware image update
> >> +  policy.  Null if the caller did not specify the policy or use the default
> >> +  policy.  As an example, vendor can implement a policy to allow an option to
> >> +  force a firmware image update when the abort reason is due to the new firmware
> >> +  image version is older than the current firmware image version or bad image
> >> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> >> +  and render the device to be non-functional should be encoded in the image
> >> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> >> +  have the option to provide a more detailed description of the abort reason to
> >> +  the caller.
> >> +
> >> +  @param[in]  Image             Points to the new image.
> >> +  @param[in]  ImageSize         Size of the new image in bytes.
> >> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> +                                firmware image update policy. Null indicates the
> >> +                                caller did not specify the policy or use the
> >> +                                default policy.
> >> +  @param[in]  Progress          A function used by the driver to report the
> >> +                                progress of the firmware update.
> >> +  @param[in]  CapsuleFwVersion  FMP Payload Header version of the image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a null-terminated
> >> +                                string providing more details for the aborted
> >> +                                operation. The buffer is allocated by this
> >> +                                function with AllocatePool(), and it is the
> >> +                                caller's responsibility to free it with a call
> >> +                                to FreePool().
> >> +
> >> +  @retval EFI_SUCCESS            The device was successfully updated with the
> >> +                                 new image.
> >> +  @retval EFI_ABORTED            The operation is aborted.
> >> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceSetImage (
> >> +  IN  CONST VOID                                     *Image,
> >> +  IN  UINTN                                          ImageSize,
> >> +  IN  CONST VOID                                     *VendorCode,
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
> >> +  IN  UINT32                                         CapsuleFwVersion,
> >> +  OUT CHAR16                                         **AbortReason
> >> +  )
> >> +{
> >> +  UINT32  LastAttemptStatus;
> >> +
> >> +  return  FmpDeviceSetImageWithStatus (
> >> +            Image,
> >> +            ImageSize,
> >> +            VendorCode,
> >> +            Progress,
> >> +            CapsuleFwVersion,
> >> +            AbortReason,
> >> +            &LastAttemptStatus
> >> +            );
> >> +}
> >> +
> >> +/**
> >> +  Checks if a new firmware image is valid for the firmware device.  This
> >> +  function allows firmware update operation to validate the firmware image
> >> +  before FmpDeviceSetImage() is called.
> >> +
> >> +  @param[in]  Image               Points to a new firmware image.
> >> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> >> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> >> +                                  a firmware update to the firmware device.  The
> >> +                                  following values from the Firmware Management
> >> +                                  Protocol are supported:
> >> +                                    IMAGE_UPDATABLE_VALID
> >> +                                    IMAGE_UPDATABLE_INVALID
> >> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> >> +                                    IMAGE_UPDATABLE_INVALID_OLD
> >> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> >> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> >> +                                  status to report back to the ESRT table in case
> >> +                                  of error. This value will only be checked when this
> >> +                                  function returns an error.
> >> +
> >> +                                  The return status code must fall in the range of
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                  If the value falls outside this range, it will be converted
> >> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> >> +                                 status information is returned in
> >> +                                 ImageUpdatable.
> >> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceCheckImageWithStatus (
> >> +  IN  CONST VOID  *Image,
> >> +  IN  UINTN       ImageSize,
> >> +  OUT UINT32      *ImageUpdatable,
> >> +  OUT UINT32      *LastAttemptStatus
> >> +  )
> >> +{
> >> +  if (LastAttemptStatus == NULL) {
> >> +    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> >> +
> >> +  if (ImageUpdatable == NULL) {
> >> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  //
> >> +  //Set to valid and then if any tests fail it will update this flag.
> >> +  //
> >> +  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> >> +
> >> +  if (Image == NULL) {
> >> +    DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> >> +    //
> >> +    // Not sure if this is needed
> >> +    //
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  //
> >> +  // Make sure the image size is correct
> >> +  //
> >> +  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    return EFI_INVALID_PARAMETER;
> >> +  }
> >> +
> >> +  return EFI_SUCCESS;
> >> +}
> >> +
> >>   /**
> >>   Checks if the firmware image is valid for the device.
> >>
> >> @@ -633,34 +813,9 @@ FmpDeviceCheckImage (
> >>     OUT UINT32      *ImageUpdateable
> >>     )
> >>   {
> >> -  if (ImageUpdateable == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> +  UINT32  LastAttemptStatus;
> >>
> >> -  //
> >> -  //Set to valid and then if any tests fail it will update this flag.
> >> -  //
> >> -  *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> >> -
> >> -  if (Image == NULL) {
> >> -    DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> >> -    //
> >> -    // Not sure if this is needed
> >> -    //
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> -
> >> -  //
> >> -  // Make sure the image size is correct
> >> -  //
> >> -  if (ImageSize != PcdGet32 (PcdBiosRomSize)) {
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
> >> -    return EFI_INVALID_PARAMETER;
> >> -  }
> >> -
> >> -  return EFI_SUCCESS;
> >> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
> >>   }
> >>
> >>   /**
> >> diff --git a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> index db0f238ea534..132b60844ad4 100644
> >> --- a/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> +++ b/Platform/Intel/Vlv2TbltDevicePkg/Feature/Capsule/Library/FmpDeviceLibSample/FmpDeviceLib.c
> >> @@ -1,6 +1,6 @@
> >>   /**
> >>
> >> -Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
> >> +Copyright (c) Microsoft Corporation.<BR>
> >>   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> >>
> >>   SPDX-License-Identifier: BSD-2-Clause-Patent
> >> @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> >>
> >>
> >>   #include <PiDxe.h>
> >> +#include <LastAttemptStatus.h>
> >> +#include <Guid/SystemResourceTable.h>
> >>   #include <Library/DebugLib.h>
> >>   #include <Protocol/FirmwareManagement.h>
> >>   #include <Library/BaseLib.h>
> >> @@ -345,6 +347,131 @@ Return Value:
> >>   }//GetImage()
> >>
> >>
> >> +/**
> >> +  Updates a firmware device with a new firmware image.  This function returns
> >> +  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
> >> +  is updatable, the function should perform the following minimal validations
> >> +  before proceeding to do the firmware image update.
> >> +    - Validate that the image is a supported image for this firmware device.
> >> +      Return EFI_ABORTED if the image is not supported.  Additional details
> >> +      on why the image is not a supported image may be returned in AbortReason.
> >> +    - Validate the data from VendorCode if is not NULL.  Firmware image
> >> +      validation must be performed before VendorCode data validation.
> >> +      VendorCode data is ignored or considered invalid if image validation
> >> +      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
> >> +
> >> +  VendorCode enables vendor to implement vendor-specific firmware image update
> >> +  policy.  Null if the caller did not specify the policy or use the default
> >> +  policy.  As an example, vendor can implement a policy to allow an option to
> >> +  force a firmware image update when the abort reason is due to the new firmware
> >> +  image version is older than the current firmware image version or bad image
> >> +  checksum.  Sensitive operations such as those wiping the entire firmware image
> >> +  and render the device to be non-functional should be encoded in the image
> >> +  itself rather than passed with the VendorCode.  AbortReason enables vendor to
> >> +  have the option to provide a more detailed description of the abort reason to
> >> +  the caller.
> >> +
> >> +  @param[in]  Image             Points to the new firmware image.
> >> +  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
> >> +  @param[in]  VendorCode        This enables vendor to implement vendor-specific
> >> +                                firmware image update policy.  NULL indicates
> >> +                                the caller did not specify the policy or use the
> >> +                                default policy.
> >> +  @param[in]  Progress          A function used to report the progress of
> >> +                                updating the firmware device with the new
> >> +                                firmware image.
> >> +  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
> >> +                                update capsule that provided the new firmware
> >> +                                image.
> >> +  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
> >> +                                Unicode string providing more details on an
> >> +                                aborted operation. The buffer is allocated by
> >> +                                this function with
> >> +                                EFI_BOOT_SERVICES.AllocatePool().  It is the
> >> +                                caller's responsibility to free this buffer with
> >> +                                EFI_BOOT_SERVICES.FreePool().
> >> +  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
> >> +                                status to report back to the ESRT table in case
> >> +                                of error. This value will only be checked when this
> >> +                                function returns an error.
> >> +
> >> +                                The return status code must fall in the range of
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                If the value falls outside this range, it will be converted
> >> +                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The firmware device was successfully updated
> >> +                                 with the new firmware image.
> >> +  @retval EFI_ABORTED            The operation is aborted.  Additional details
> >> +                                 are provided in AbortReason.
> >> +  @retval EFI_INVALID_PARAMETER  The Image was NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus was NULL.
> >> +  @retval EFI_UNSUPPORTED        The operation is not supported.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceSetImageWithStatus (
> >> +  IN  CONST VOID                                     *Image,
> >> +  IN  UINTN                                          ImageSize,
> >> +  IN  CONST VOID                                     *VendorCode,       OPTIONAL
> >> +  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,          OPTIONAL
> >> +  IN  UINT32                                         CapsuleFwVersion,
> >> +  OUT CHAR16                                         **AbortReason,
> >> +  OUT UINT32                                         *LastAttemptStatus
> >> +  )
> >> +{
> >> +    EFI_STATUS Status                         = EFI_SUCCESS;
> >> +    UINT32 Updateable                         = 0;
> >> +
> >> +    Status = FmpDeviceCheckImageWithStatus (Image, ImageSize, &Updateable, LastAttemptStatus);
> >> +    if (EFI_ERROR(Status))
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image failed with %r.\n", Status));
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    if (Updateable != IMAGE_UPDATABLE_VALID)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Check Image returned that the Image was not valid for update.
> >> Updatable value = 0x%X.\n", Updateable));
> >> +        Status = EFI_ABORTED;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    if (Progress == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Invalid progress callback\n"));
> >> +        Status = EFI_INVALID_PARAMETER;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    Status = Progress(15);
> >> +    if (EFI_ERROR(Status))
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "SetImageWithStatus  - Progress Callback failed with Status %r.\n", Status));
> >> +    }
> >> +
> >> +    {
> >> +      UINTN  p;
> >> +
> >> +      for (p = 20; p < 100; p++) {
> >> +        gBS->Stall (100000);  //us  = 0.1 seconds
> >> +        Progress (p);
> >> +      }
> >> +    }
> >> +
> >> +    //TODO: add support for VendorCode, and AbortReason
> >> +cleanup:
> >> +    if (EFI_ERROR (Status)) {
> >> +      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +    }
> >> +
> >> +    return Status;
> >> +}// SetImageWithStatus()
> >> +
> >> +
> >>   /**
> >>   Updates the firmware image of the device.
> >>
> >> @@ -396,51 +523,98 @@ IN  UINT32                                           CapsuleFwVersion,
> >>   OUT CHAR16                                           **AbortReason
> >>   )
> >>   {
> >> -    EFI_STATUS Status                         = EFI_SUCCESS;
> >> -    UINT32 Updateable                         = 0;
> >> -
> >> -    Status = FmpDeviceCheckImage(Image, ImageSize, &Updateable);
> >> -    if (EFI_ERROR(Status))
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image failed with %r.\n", Status));
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    if (Updateable != IMAGE_UPDATABLE_VALID)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Check Image returned that the Image was not valid for update.  Updatable value
> =
> >> 0x%X.\n", Updateable));
> >> -        Status = EFI_ABORTED;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    if (Progress == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Invalid progress callback\n"));
> >> -        Status = EFI_INVALID_PARAMETER;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    Status = Progress(15);
> >> -    if (EFI_ERROR(Status))
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "SetImage - Progress Callback failed with Status %r.\n", Status));
> >> -    }
> >> -
> >> -    {
> >> -      UINTN  p;
> >> -
> >> -      for (p = 20; p < 100; p++) {
> >> -        gBS->Stall (100000);  //us  = 0.1 seconds
> >> -        Progress (p);
> >> -      }
> >> -    }
> >> -
> >> -    //TODO: add support for VendorCode, and AbortReason
> >> -cleanup:
> >> -    return Status;
> >> +  UINT32  LastAttemptStatus;
> >> +
> >> +  return  FmpDeviceSetImageWithStatus (
> >> +            Image,
> >> +            ImageSize,
> >> +            VendorCode,
> >> +            Progress,
> >> +            CapsuleFwVersion,
> >> +            AbortReason,
> >> +            &LastAttemptStatus
> >> +            );
> >>   }// SetImage()
> >>
> >>
> >> +/**
> >> +  Checks if a new firmware image is valid for the firmware device.  This
> >> +  function allows firmware update operation to validate the firmware image
> >> +  before FmpDeviceSetImage() is called.
> >> +
> >> +  @param[in]  Image               Points to a new firmware image.
> >> +  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
> >> +  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
> >> +                                  a firmware update to the firmware device.  The
> >> +                                  following values from the Firmware Management
> >> +                                  Protocol are supported:
> >> +                                    IMAGE_UPDATABLE_VALID
> >> +                                    IMAGE_UPDATABLE_INVALID
> >> +                                    IMAGE_UPDATABLE_INVALID_TYPE
> >> +                                    IMAGE_UPDATABLE_INVALID_OLD
> >> +                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
> >> +  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
> >> +                                  status to report back to the ESRT table in case
> >> +                                  of error. This value will only be checked when this
> >> +                                  function returns an error.
> >> +
> >> +                                  The return status code must fall in the range of
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
> >> +                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
> >> +
> >> +                                  If the value falls outside this range, it will be converted
> >> +                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
> >> +
> >> +  @retval EFI_SUCCESS            The image was successfully checked.  Additional
> >> +                                 status information is returned in
> >> +                                 ImageUpdatable.
> >> +  @retval EFI_INVALID_PARAMETER  Image is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
> >> +  @retval EFI_INVALID_PARAMETER  LastAttemptStatus is NULL.
> >> +
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +FmpDeviceCheckImageWithStatus (
> >> +  IN  CONST VOID  *Image,
> >> +  IN  UINTN       ImageSize,
> >> +  OUT UINT32      *ImageUpdatable,
> >> +  OUT UINT32      *LastAttemptStatus
> >> +  )
> >> +{
> >> +    EFI_STATUS status = EFI_SUCCESS;
> >> +
> >> +    if (LastAttemptStatus == NULL) {
> >> +      DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
> >> +      return EFI_INVALID_PARAMETER;
> >> +    }
> >> +    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
> >> +
> >> +    if (ImageUpdatable == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
> >> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +        status = EFI_INVALID_PARAMETER;
> >> +        goto cleanup;
> >> +    }
> >> +
> >> +    //
> >> +    //Set to valid and then if any tests fail it will update this flag.
> >> +    //
> >> +    *ImageUpdatable = IMAGE_UPDATABLE_VALID;
> >> +
> >> +    if (Image == NULL)
> >> +    {
> >> +        DEBUG((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
> >> +        *ImageUpdatable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> >> +        *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
> >> +        return EFI_INVALID_PARAMETER;
> >> +    }
> >> +
> >> +cleanup:
> >> +    return status;
> >> +}// CheckImageWithStatus()
> >> +
> >>
> >>   /**
> >>   Checks if the firmware image is valid for the device.
> >> @@ -465,29 +639,9 @@ IN  UINTN                             ImageSize,
> >>   OUT UINT32                            *ImageUpdateable
> >>   )
> >>   {
> >> -    EFI_STATUS status = EFI_SUCCESS;
> >> +  UINT32  LastAttemptStatus;
> >>
> >> -    if (ImageUpdateable == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "CheckImage - ImageUpdateable Pointer Parameter is NULL.\n"));
> >> -        status = EFI_INVALID_PARAMETER;
> >> -        goto cleanup;
> >> -    }
> >> -
> >> -    //
> >> -    //Set to valid and then if any tests fail it will update this flag.
> >> -    //
> >> -    *ImageUpdateable = IMAGE_UPDATABLE_VALID;
> >> -
> >> -    if (Image == NULL)
> >> -    {
> >> -        DEBUG((DEBUG_ERROR, "CheckImage - Image Pointer Parameter is NULL.\n"));
> >> -        *ImageUpdateable = IMAGE_UPDATABLE_INVALID; //not sure if this is needed
> >> -        return EFI_INVALID_PARAMETER;
> >> -    }
> >> -
> >> -cleanup:
> >> -    return status;
> >> +  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdateable, &LastAttemptStatus);
> >>   }// CheckImage()
> >>
> >>   /**
> >> --
> >> 2.28.0.windows.1
> >






[-- Attachment #2: Type: text/html, Size: 123724 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-11-11 17:17 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-10-01 21:58 [edk2-platforms][PATCH v1 1/1] Vlv2TbltDevicePkg/FmpDeviceLib: Add LastAttemptStatus compatibility Michael Kubacki
2020-10-29  1:12 ` Michael D Kinney
2020-10-29  4:45   ` Michael Kubacki
2020-11-05 20:36   ` Michael Kubacki
2020-11-11  3:03     ` Michael D Kinney
2020-11-11  4:16       ` [edk2-devel] " Kilian Kegel
2020-11-11  5:17         ` Michael Kubacki
2020-11-11 17:17         ` Michael D Kinney
     [not found] <1639FD37CA1FD9A2.6392@groups.io>
2020-10-15 21:27 ` Michael Kubacki
     [not found] ` <bf090dba-75d3-520e-7414-bcdb8314562b@outlook.com>
2020-10-27  0:50   ` Michael Kubacki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox