]> git.proxmox.com Git - mirror_edk2.git/blobdiff - FmpDevicePkg/FmpDxe/FmpDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / FmpDevicePkg / FmpDxe / FmpDxe.c
index 3cda86f6c46cca73b49b9d4e4f605437f94749a3..1e7ec4a09e1611c9bef2abe6170d1fa699664e86 100644 (file)
@@ -3,8 +3,8 @@
   image stored in a firmware device with platform and firmware device specific\r
   information provided through PCDs and libraries.\r
 \r
-  Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>\r
-  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) Microsoft Corporation.<BR>\r
+  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
 \r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
@@ -40,8 +40,8 @@ EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  mFmpProgress;
 // Protocol instance\r
 //\r
 const FIRMWARE_MANAGEMENT_PRIVATE_DATA  mFirmwareManagementPrivateDataTemplate = {\r
-  FIRMWARE_MANAGEMENT_PRIVATE_DATA_SIGNATURE,  // Signature\r
-  NULL,                                        // Handle\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA_SIGNATURE, // Signature\r
+  NULL,                                       // Handle\r
   {                                            // Fmp\r
     GetTheImageInfo,\r
     GetTheImage,\r
@@ -50,13 +50,14 @@ const FIRMWARE_MANAGEMENT_PRIVATE_DATA  mFirmwareManagementPrivateDataTemplate =
     GetPackageInfo,\r
     SetPackageInfo\r
   },\r
-  FALSE,                                       // DescriptorPopulated\r
-  {                                            // Desc\r
-    1,     // ImageIndex\r
+  FALSE,            // DescriptorPopulated\r
+  {                 // Desc\r
+    1,              // ImageIndex\r
     //\r
     // ImageTypeId\r
     //\r
-    { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },\r
+    { 0x00000000,   0x0000,0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }\r
+    },\r
     1,     // ImageId\r
     NULL,  // ImageIdName\r
     0,     // Version\r
@@ -70,17 +71,18 @@ const FIRMWARE_MANAGEMENT_PRIVATE_DATA  mFirmwareManagementPrivateDataTemplate =
     0,     // LastAttemptStatus\r
     0      // HardwareInstance\r
   },\r
-  NULL,                                        // ImageIdName\r
-  NULL,                                        // VersionName\r
-  TRUE,                                        // RuntimeVersionSupported\r
-  NULL,                                        // FmpDeviceLockEvent\r
-  FALSE,                                       // FmpDeviceLocked\r
-  NULL,                                        // FmpDeviceContext\r
-  NULL,                                        // VersionVariableName\r
-  NULL,                                        // LsvVariableName\r
-  NULL,                                        // LastAttemptStatusVariableName\r
-  NULL,                                        // LastAttemptVersionVariableName\r
-  NULL                                         // FmpStateVariableName\r
+  NULL,             // ImageIdName\r
+  NULL,             // VersionName\r
+  TRUE,             // RuntimeVersionSupported\r
+  NULL,             // FmpDeviceLockEvent\r
+  FALSE,            // FmpDeviceLocked\r
+  NULL,             // FmpDeviceContext\r
+  NULL,             // VersionVariableName\r
+  NULL,             // LsvVariableName\r
+  NULL,             // LastAttemptStatusVariableName\r
+  NULL,             // LastAttemptVersionVariableName\r
+  NULL,             // FmpStateVariableName\r
+  TRUE              // DependenciesSatisfied\r
 };\r
 \r
 ///\r
@@ -124,7 +126,7 @@ FmpDxeProgress (
   IN UINTN  Completion\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  EFI_STATUS  Status;\r
 \r
   Status = EFI_UNSUPPORTED;\r
 \r
@@ -147,7 +149,9 @@ FmpDxeProgress (
 /**\r
   Returns a pointer to the ImageTypeId GUID value.  An attempt is made to get\r
   the GUID value from the FmpDeviceLib. If the FmpDeviceLib does not provide\r
-  a GUID value, then gEfiCallerIdGuid is returned.\r
+  a GUID value, then PcdFmpDeviceImageTypeIdGuid is used.  If the size of\r
+  PcdFmpDeviceImageTypeIdGuid is not the size of EFI_GUID, then gEfiCallerIdGuid\r
+  is returned.\r
 \r
   @retval  The ImageTypeId GUID\r
 \r
@@ -159,19 +163,29 @@ GetImageTypeIdGuid (
 {\r
   EFI_STATUS  Status;\r
   EFI_GUID    *FmpDeviceLibGuid;\r
+  UINTN       ImageTypeIdGuidSize;\r
 \r
   FmpDeviceLibGuid = NULL;\r
-  Status = FmpDeviceGetImageTypeIdGuidPtr (&FmpDeviceLibGuid);\r
+  Status           = FmpDeviceGetImageTypeIdGuidPtr (&FmpDeviceLibGuid);\r
   if (EFI_ERROR (Status)) {\r
     if (Status != EFI_UNSUPPORTED) {\r
       DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid error %r\n", mImageIdName, Status));\r
     }\r
-    return &gEfiCallerIdGuid;\r
-  }\r
-  if (FmpDeviceLibGuid == NULL) {\r
+  } else if (FmpDeviceLibGuid == NULL) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid GUID\n", mImageIdName));\r
-    return &gEfiCallerIdGuid;\r
+    Status = EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    ImageTypeIdGuidSize = PcdGetSize (PcdFmpDeviceImageTypeIdGuid);\r
+    if (ImageTypeIdGuidSize == sizeof (EFI_GUID)) {\r
+      FmpDeviceLibGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceImageTypeIdGuid);\r
+    } else {\r
+      DEBUG ((DEBUG_WARN, "FmpDxe(%s): Fall back to ImageTypeIdGuid of gEfiCallerIdGuid\n", mImageIdName));\r
+      FmpDeviceLibGuid = &gEfiCallerIdGuid;\r
+    }\r
   }\r
+\r
   return FmpDeviceLibGuid;\r
 }\r
 \r
@@ -228,7 +242,7 @@ GetLowestSupportedVersion (
   // Check the FmpDeviceLib\r
   //\r
   DeviceLibLowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;\r
-  Status = FmpDeviceGetLowestSupportedVersion (&DeviceLibLowestSupportedVersion);\r
+  Status                          = FmpDeviceGetLowestSupportedVersion (&DeviceLibLowestSupportedVersion);\r
   if (EFI_ERROR (Status)) {\r
     DeviceLibLowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;\r
   }\r
@@ -265,15 +279,21 @@ PopulateDescriptor (
   )\r
 {\r
   EFI_STATUS  Status;\r
+  UINT32      DependenciesSize;\r
+\r
+  if (Private == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): PopulateDescriptor() - Private is NULL.\n", mImageIdName));\r
+    return;\r
+  }\r
 \r
   if (Private->DescriptorPopulated) {\r
     return;\r
   }\r
 \r
   Private->Descriptor.ImageIndex = 1;\r
-  CopyGuid (&Private->Descriptor.ImageTypeId, GetImageTypeIdGuid());\r
+  CopyGuid (&Private->Descriptor.ImageTypeId, GetImageTypeIdGuid ());\r
   Private->Descriptor.ImageId     = Private->Descriptor.ImageIndex;\r
-  Private->Descriptor.ImageIdName = GetImageTypeNameString();\r
+  Private->Descriptor.ImageIdName = GetImageTypeNameString ();\r
 \r
   //\r
   // Get the hardware instance from FmpDeviceLib\r
@@ -297,12 +317,12 @@ PopulateDescriptor (
   Status = FmpDeviceGetVersion (&Private->Descriptor.Version);\r
   if (Status == EFI_UNSUPPORTED) {\r
     Private->RuntimeVersionSupported = FALSE;\r
-    Private->Descriptor.Version = GetVersionFromVariable (Private);\r
+    Private->Descriptor.Version      = GetVersionFromVariable (Private);\r
   } else if (EFI_ERROR (Status)) {\r
     //\r
     // Unexpected error.   Use default version.\r
     //\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetVersion() from FmpDeviceLib (%s) returned %r\n", mImageIdName, GetImageTypeNameString(), Status));\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetVersion() from FmpDeviceLib (%s) returned %r\n", mImageIdName, GetImageTypeNameString (), Status));\r
     Private->Descriptor.Version = DEFAULT_VERSION;\r
   }\r
 \r
@@ -368,6 +388,18 @@ PopulateDescriptor (
   Private->Descriptor.LastAttemptVersion = GetLastAttemptVersionFromVariable (Private);\r
   Private->Descriptor.LastAttemptStatus  = GetLastAttemptStatusFromVariable (Private);\r
 \r
+  //\r
+  // Get the dependency from the FmpDependencyDeviceLib.\r
+  //\r
+  Private->Descriptor.Dependencies = NULL;\r
+\r
+  //\r
+  // Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY\r
+  //\r
+  if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
+    Private->Descriptor.Dependencies = GetFmpDependency (&DependenciesSize);\r
+  }\r
+\r
   Private->DescriptorPopulated = TRUE;\r
 }\r
 \r
@@ -427,6 +459,12 @@ GetTheImageInfo (
 \r
   Status = EFI_SUCCESS;\r
 \r
+  if (This == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImageInfo() - This is NULL.\n", mImageIdName));\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto cleanup;\r
+  }\r
+\r
   //\r
   // Retrieve the private context structure\r
   //\r
@@ -456,8 +494,9 @@ GetTheImageInfo (
   //\r
   // Confirm that buffer isn't null\r
   //\r
-  if ( (ImageInfo == NULL) || (DescriptorVersion == NULL) || (DescriptorCount == NULL) || (DescriptorSize == NULL)\r
-       || (PackageVersion == NULL)) {\r
+  if (  (ImageInfo == NULL) || (DescriptorVersion == NULL) || (DescriptorCount == NULL) || (DescriptorSize == NULL)\r
+     || (PackageVersion == NULL))\r
+  {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImageInfo() - Pointer Parameter is NULL.\n", mImageIdName));\r
     Status = EFI_INVALID_PARAMETER;\r
     goto cleanup;\r
@@ -479,8 +518,8 @@ GetTheImageInfo (
   CopyMem (ImageInfo, &Private->Descriptor, sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR));\r
 \r
   *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;\r
-  *DescriptorCount = 1;\r
-  *DescriptorSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);\r
+  *DescriptorCount   = 1;\r
+  *DescriptorSize    = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);\r
   //\r
   // means unsupported\r
   //\r
@@ -531,8 +570,18 @@ GetTheImage (
   FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
   UINTN                             Size;\r
 \r
+  if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
   Status = EFI_SUCCESS;\r
 \r
+  if (This == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - This is NULL.\n", mImageIdName));\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto cleanup;\r
+  }\r
+\r
   //\r
   // Retrieve the private context structure\r
   //\r
@@ -561,6 +610,7 @@ GetTheImage (
   if (EFI_ERROR (Status)) {\r
     Size = 0;\r
   }\r
+\r
   if (*ImageSize < Size) {\r
     *ImageSize = Size;\r
     DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): GetImage() - ImageSize is to small.\n", mImageIdName));\r
@@ -584,9 +634,11 @@ cleanup:
   Helper function to safely retrieve the FMP header from\r
   within an EFI_FIRMWARE_IMAGE_AUTHENTICATION structure.\r
 \r
-  @param[in]   Image        Pointer to the image.\r
-  @param[in]   ImageSize    Size of the image.\r
-  @param[out]  PayloadSize\r
+  @param[in]   Image                 Pointer to the image.\r
+  @param[in]   ImageSize             Size of the image.\r
+  @param[in]   AdditionalHeaderSize  Size of any headers that cannot be calculated by this function.\r
+  @param[out]  PayloadSize           An optional pointer to a UINTN that holds the size of the payload\r
+                                     (image size minus headers)\r
 \r
   @retval  !NULL  Valid pointer to the header.\r
   @retval  NULL   Structure is bad and pointer cannot be found.\r
@@ -596,22 +648,27 @@ VOID *
 GetFmpHeader (\r
   IN  CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION  *Image,\r
   IN  CONST UINTN                              ImageSize,\r
-  OUT UINTN                                    *PayloadSize\r
+  IN  CONST UINTN                              AdditionalHeaderSize,\r
+  OUT UINTN                                    *PayloadSize OPTIONAL\r
   )\r
 {\r
   //\r
   // Check to make sure that operation can be safely performed.\r
   //\r
-  if (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) < (UINTN)Image || \\r
-      ((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) >= (UINTN)Image + ImageSize) {\r
+  if ((((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) + AdditionalHeaderSize < (UINTN)Image) || \\r
+      (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) + AdditionalHeaderSize >= (UINTN)Image + ImageSize))\r
+  {\r
     //\r
     // Pointer overflow. Invalid image.\r
     //\r
     return NULL;\r
   }\r
 \r
-  *PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);\r
-  return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);\r
+  if (PayloadSize != NULL) {\r
+    *PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength + AdditionalHeaderSize);\r
+  }\r
+\r
+  return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength  + AdditionalHeaderSize);\r
 }\r
 \r
 /**\r
@@ -633,6 +690,11 @@ GetAllHeaderSize (
 {\r
   UINT32  CalculatedSize;\r
 \r
+  if (Image == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetAllHeaderSize() - Image is NULL.\n", mImageIdName));\r
+    return 0;\r
+  }\r
+\r
   CalculatedSize = sizeof (Image->MonotonicCount) +\r
                    AdditionalHeaderSize +\r
                    Image->AuthInfo.Hdr.dwLength;\r
@@ -640,9 +702,10 @@ GetAllHeaderSize (
   //\r
   // Check to make sure that operation can be safely performed.\r
   //\r
-  if (CalculatedSize < sizeof (Image->MonotonicCount) ||\r
-      CalculatedSize < AdditionalHeaderSize           ||\r
-      CalculatedSize < Image->AuthInfo.Hdr.dwLength      ) {\r
+  if ((CalculatedSize < sizeof (Image->MonotonicCount)) ||\r
+      (CalculatedSize < AdditionalHeaderSize) ||\r
+      (CalculatedSize < Image->AuthInfo.Hdr.dwLength))\r
+  {\r
     //\r
     // Integer overflow. Invalid image.\r
     //\r
@@ -665,6 +728,23 @@ GetAllHeaderSize (
   @param[in]  ImageSize          Size of the new image in bytes.\r
   @param[out] ImageUpdatable     Indicates if the new image is valid for update. It also provides,\r
                                  if available, additional information if the image is invalid.\r
+  @param[out] LastAttemptStatus  A pointer to a UINT32 that holds the last attempt status to report\r
+                                 back to the ESRT table in case of error.  If an error does not occur,\r
+                                 this function will set the value to LAST_ATTEMPT_STATUS_SUCCESS.\r
+\r
+                                 This function will return error codes that occur within this function\r
+                                 implementation within a driver range of last attempt error codes from\r
+                                 LAST_ATTEMPT_STATUS_DRIVER_MIN_ERROR_CODE_VALUE\r
+                                 to LAST_ATTEMPT_STATUS_DRIVER_MAX_ERROR_CODE_VALUE.\r
+\r
+                                 This function might also return error codes that occur within libraries\r
+                                 linked against this module that return last attempt error codes such as:\r
+\r
+                                 LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_LIB_MIN_ERROR_CODE_VALUE to\r
+                                 LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_LIB_MAX_ERROR_CODE_VALUE\r
+\r
+                                 LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_CHECK_LIB_MIN_ERROR_CODE_VALUE to\r
+                                 LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_CHECK_LIB_MAX_ERROR_CODE_VALUE\r
 \r
   @retval EFI_SUCCESS            The image was successfully checked.\r
   @retval EFI_ABORTED            The operation is aborted.\r
@@ -675,15 +755,17 @@ GetAllHeaderSize (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-CheckTheImage (\r
+CheckTheImageInternal (\r
   IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,\r
   IN  UINT8                             ImageIndex,\r
   IN  CONST VOID                        *Image,\r
   IN  UINTN                             ImageSize,\r
-  OUT UINT32                            *ImageUpdatable\r
+  OUT UINT32                            *ImageUpdatable,\r
+  OUT UINT32                            *LastAttemptStatus\r
   )\r
 {\r
   EFI_STATUS                        Status;\r
+  UINT32                            LocalLastAttemptStatus;\r
   FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
   UINTN                             RawSize;\r
   VOID                              *FmpPayloadHeader;\r
@@ -696,14 +778,42 @@ CheckTheImage (
   UINTN                             PublicKeyDataLength;\r
   UINT8                             *PublicKeyDataXdr;\r
   UINT8                             *PublicKeyDataXdrEnd;\r
+  EFI_FIRMWARE_IMAGE_DEP            *Dependencies;\r
+  UINT32                            DependenciesSize;\r
+\r
+  Status                 = EFI_SUCCESS;\r
+  LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+  RawSize                = 0;\r
+  FmpPayloadHeader       = NULL;\r
+  FmpPayloadSize         = 0;\r
+  Version                = 0;\r
+  FmpHeaderSize          = 0;\r
+  AllHeaderSize          = 0;\r
+  Dependencies           = NULL;\r
+  DependenciesSize       = 0;\r
+\r
+  if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (LastAttemptStatus == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImageInternal() - LastAttemptStatus is NULL.\n", mImageIdName));\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto cleanup;\r
+  }\r
+\r
+  //\r
+  // A last attempt status error code will always override the success\r
+  // value before returning from the function\r
+  //\r
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
 \r
-  Status           = EFI_SUCCESS;\r
-  RawSize          = 0;\r
-  FmpPayloadHeader = NULL;\r
-  FmpPayloadSize   = 0;\r
-  Version          = 0;\r
-  FmpHeaderSize    = 0;\r
-  AllHeaderSize    = 0;\r
+  if (This == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - This is NULL.\n", mImageIdName));\r
+    Status             = EFI_INVALID_PARAMETER;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_PROTOCOL_ARG_MISSING;\r
+    goto cleanup;\r
+  }\r
 \r
   //\r
   // Retrieve the private context structure\r
@@ -718,30 +828,38 @@ CheckTheImage (
 \r
   if (ImageUpdatable == NULL) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - ImageUpdatable Pointer Parameter is NULL.\n", mImageIdName));\r
-    Status = EFI_INVALID_PARAMETER;\r
+    Status             = EFI_INVALID_PARAMETER;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_IMAGE_NOT_UPDATABLE;\r
     goto cleanup;\r
   }\r
 \r
   //\r
-  //Set to valid and then if any tests fail it will update this flag.\r
+  // Set to valid and then if any tests fail it will update this flag.\r
   //\r
   *ImageUpdatable = IMAGE_UPDATABLE_VALID;\r
 \r
+  //\r
+  // Set to satisfied and then if dependency evaluates to false it will update this flag.\r
+  //\r
+  Private->DependenciesSatisfied = TRUE;\r
+\r
   if (Image == NULL) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Pointer Parameter is NULL.\n", mImageIdName));\r
     //\r
     // not sure if this is needed\r
     //\r
-    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
+    *ImageUpdatable    = IMAGE_UPDATABLE_INVALID;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_IMAGE_NOT_PROVIDED;\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   PublicKeyDataXdr    = PcdGetPtr (PcdFmpDevicePkcs7CertBufferXdr);\r
   PublicKeyDataXdrEnd = PublicKeyDataXdr + PcdGetSize (PcdFmpDevicePkcs7CertBufferXdr);\r
 \r
-  if (PublicKeyDataXdr == NULL || (PublicKeyDataXdr == PublicKeyDataXdrEnd)) {\r
+  if ((PublicKeyDataXdr == NULL) || (PublicKeyDataXdr == PublicKeyDataXdrEnd)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Invalid certificate, skipping it.\n", mImageIdName));\r
-    Status = EFI_ABORTED;\r
+    Status                 = EFI_ABORTED;\r
+    LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_CERTIFICATE;\r
   } else {\r
     //\r
     // Try each key from PcdFmpDevicePkcs7CertBufferXdr\r
@@ -750,11 +868,11 @@ CheckTheImage (
       Index++;\r
       DEBUG (\r
         (DEBUG_INFO,\r
-        "FmpDxe(%s): Certificate #%d [%p..%p].\n",\r
-        mImageIdName,\r
-        Index,\r
-        PublicKeyDataXdr,\r
-        PublicKeyDataXdrEnd\r
+         "FmpDxe(%s): Certificate #%d [%p..%p].\n",\r
+         mImageIdName,\r
+         Index,\r
+         PublicKeyDataXdr,\r
+         PublicKeyDataXdrEnd\r
         )\r
         );\r
 \r
@@ -763,9 +881,11 @@ CheckTheImage (
         // Key data extends beyond end of PCD\r
         //\r
         DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Certificate size extends beyond end of PCD, skipping it.\n", mImageIdName));\r
-        Status = EFI_ABORTED;\r
+        Status                 = EFI_ABORTED;\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_KEY_LENGTH_VALUE;\r
         break;\r
       }\r
+\r
       //\r
       // Read key length stored in big-endian format\r
       //\r
@@ -779,26 +899,35 @@ CheckTheImage (
         // Key data extends beyond end of PCD\r
         //\r
         DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Certificate extends beyond end of PCD, skipping it.\n", mImageIdName));\r
-        Status = EFI_ABORTED;\r
+        Status                 = EFI_ABORTED;\r
+        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_KEY_LENGTH;\r
         break;\r
       }\r
+\r
       PublicKeyData = PublicKeyDataXdr;\r
-      Status = AuthenticateFmpImage (\r
-                 (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image,\r
-                 ImageSize,\r
-                 PublicKeyData,\r
-                 PublicKeyDataLength\r
-                 );\r
+      Status        = AuthenticateFmpImage (\r
+                        (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image,\r
+                        ImageSize,\r
+                        PublicKeyData,\r
+                        PublicKeyDataLength\r
+                        );\r
       if (!EFI_ERROR (Status)) {\r
         break;\r
       }\r
+\r
       PublicKeyDataXdr += PublicKeyDataLength;\r
-      PublicKeyDataXdr = (UINT8 *)ALIGN_POINTER (PublicKeyDataXdr, sizeof (UINT32));\r
+      PublicKeyDataXdr  = (UINT8 *)ALIGN_POINTER (PublicKeyDataXdr, sizeof (UINT32));\r
     }\r
   }\r
 \r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Authentication Failed %r.\n", mImageIdName, Status));\r
+    if (LocalLastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) {\r
+      *LastAttemptStatus = LocalLastAttemptStatus;\r
+    } else {\r
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_IMAGE_AUTH_FAILURE;\r
+    }\r
+\r
     goto cleanup;\r
   }\r
 \r
@@ -807,26 +936,43 @@ CheckTheImage (
   //\r
   if (ImageIndex != 1) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Index Invalid.\n", mImageIdName));\r
-    *ImageUpdatable = IMAGE_UPDATABLE_INVALID_TYPE;\r
-    Status = EFI_SUCCESS;\r
+    *ImageUpdatable    = IMAGE_UPDATABLE_INVALID_TYPE;\r
+    Status             = EFI_INVALID_PARAMETER;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_IMAGE_INDEX;\r
     goto cleanup;\r
   }\r
 \r
+  //\r
+  // Get the dependency from Image.\r
+  //\r
+  Dependencies =  GetImageDependency (\r
+                    (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image,\r
+                    ImageSize,\r
+                    &DependenciesSize,\r
+                    LastAttemptStatus\r
+                    );\r
+  if (*LastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) {\r
+    Status = EFI_ABORTED;\r
+    goto cleanup;\r
+  }\r
 \r
   //\r
   // Check the FmpPayloadHeader\r
   //\r
-  FmpPayloadHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );\r
+  FmpPayloadHeader = GetFmpHeader ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, DependenciesSize, &FmpPayloadSize);\r
   if (FmpPayloadHeader == NULL) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpHeader failed.\n", mImageIdName));\r
-    Status = EFI_ABORTED;\r
+    Status             = EFI_ABORTED;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER;\r
     goto cleanup;\r
   }\r
+\r
   Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status));\r
-    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
-    Status = EFI_SUCCESS;\r
+    *ImageUpdatable    = IMAGE_UPDATABLE_INVALID;\r
+    Status             = EFI_SUCCESS;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER_VERSION;\r
     goto cleanup;\r
   }\r
 \r
@@ -836,11 +982,30 @@ CheckTheImage (
   if (Version < Private->Descriptor.LowestSupportedImageVersion) {\r
     DEBUG (\r
       (DEBUG_ERROR,\r
-      "FmpDxe(%s): CheckTheImage() - Version Lower than lowest supported version. 0x%08X < 0x%08X\n",\r
-      mImageIdName, Version, Private->Descriptor.LowestSupportedImageVersion)\r
+       "FmpDxe(%s): CheckTheImage() - Version Lower than lowest supported version. 0x%08X < 0x%08X\n",\r
+       mImageIdName, Version, Private->Descriptor.LowestSupportedImageVersion)\r
       );\r
-    *ImageUpdatable = IMAGE_UPDATABLE_INVALID_OLD;\r
-    Status = EFI_SUCCESS;\r
+    *ImageUpdatable    = IMAGE_UPDATABLE_INVALID_OLD;\r
+    Status             = EFI_SUCCESS;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_VERSION_TOO_LOW;\r
+    goto cleanup;\r
+  }\r
+\r
+  //\r
+  // Evaluate dependency expression\r
+  //\r
+  Private->DependenciesSatisfied =  CheckFmpDependency (\r
+                                      Private->Descriptor.ImageTypeId,\r
+                                      Version,\r
+                                      Dependencies,\r
+                                      DependenciesSize,\r
+                                      &LocalLastAttemptStatus\r
+                                      );\r
+  if (!Private->DependenciesSatisfied) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency check failed.\n", mImageIdName));\r
+    *ImageUpdatable    = IMAGE_UPDATABLE_INVALID;\r
+    Status             = EFI_SUCCESS;\r
+    *LastAttemptStatus = LocalLastAttemptStatus;\r
     goto cleanup;\r
   }\r
 \r
@@ -850,8 +1015,9 @@ CheckTheImage (
   Status = GetFmpPayloadHeaderSize (FmpPayloadHeader, FmpPayloadSize, &FmpHeaderSize);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpPayloadHeaderSize failed %r.\n", Status));\r
-    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
-    Status = EFI_SUCCESS;\r
+    *ImageUpdatable    = IMAGE_UPDATABLE_INVALID;\r
+    Status             = EFI_SUCCESS;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER_SIZE;\r
     goto cleanup;\r
   }\r
 \r
@@ -859,26 +1025,91 @@ CheckTheImage (
   // Call FmpDevice Lib Check Image on the\r
   // Raw payload.  So all headers need stripped off\r
   //\r
-  AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );\r
+  AllHeaderSize = GetAllHeaderSize ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize + DependenciesSize);\r
   if (AllHeaderSize == 0) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\r
-    Status = EFI_ABORTED;\r
+    Status             = EFI_ABORTED;\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_ALL_HEADER_SIZE;\r
     goto cleanup;\r
   }\r
+\r
   RawSize = ImageSize - AllHeaderSize;\r
 \r
   //\r
   // FmpDeviceLib CheckImage function to do any specific checks\r
   //\r
-  Status = FmpDeviceCheckImage ((((UINT8 *)Image) + AllHeaderSize), RawSize, ImageUpdatable);\r
+  Status = FmpDeviceCheckImageWithStatus ((((UINT8 *)Image) + AllHeaderSize), RawSize, ImageUpdatable, LastAttemptStatus);\r
   if (EFI_ERROR (Status)) {\r
+    // The image cannot be valid if an error occurred checking the image\r
+    if (*ImageUpdatable == IMAGE_UPDATABLE_VALID) {\r
+      *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
+    }\r
+\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - FmpDeviceLib CheckImage failed. Status = %r\n", mImageIdName, Status));\r
   }\r
 \r
+  //\r
+  // Only validate the library last attempt status code if the image is not updatable.\r
+  // This specifically avoids converting LAST_ATTEMPT_STATUS_SUCCESS if it set for an updatable image.\r
+  //\r
+  if (*ImageUpdatable != IMAGE_UPDATABLE_VALID) {\r
+    //\r
+    // LastAttemptStatus returned from the device library should fall within the designated error range\r
+    // [LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE, LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE]\r
+    //\r
+    if ((*LastAttemptStatus < LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE) ||\r
+        (*LastAttemptStatus > LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE))\r
+    {\r
+      DEBUG ((\r
+        DEBUG_ERROR,\r
+        "FmpDxe(%s): CheckTheImage() - LastAttemptStatus %d from FmpDeviceCheckImageWithStatus() is invalid.\n",\r
+        mImageIdName,\r
+        *LastAttemptStatus\r
+        ));\r
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+    }\r
+  }\r
+\r
 cleanup:\r
   return Status;\r
 }\r
 \r
+/**\r
+  Checks if the firmware image is valid for the device.\r
+\r
+  This function allows firmware update application to validate the firmware image without\r
+  invoking the SetImage() first.\r
+\r
+  @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.\r
+  @param[in]  ImageIndex         A unique number identifying the firmware image(s) within the device.\r
+                                 The number is between 1 and DescriptorCount.\r
+  @param[in]  Image              Points to the new image.\r
+  @param[in]  ImageSize          Size of the new image in bytes.\r
+  @param[out] ImageUpdatable     Indicates if the new image is valid for update. It also provides,\r
+                                 if available, additional information if the image is invalid.\r
+\r
+  @retval EFI_SUCCESS            The image was successfully checked.\r
+  @retval EFI_ABORTED            The operation is aborted.\r
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.\r
+  @retval EFI_UNSUPPORTED        The operation is not supported.\r
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CheckTheImage (\r
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,\r
+  IN  UINT8                             ImageIndex,\r
+  IN  CONST VOID                        *Image,\r
+  IN  UINTN                             ImageSize,\r
+  OUT UINT32                            *ImageUpdatable\r
+  )\r
+{\r
+  UINT32  LastAttemptStatus;\r
+\r
+  return CheckTheImageInternal (This, ImageIndex, Image, ImageSize, ImageUpdatable, &LastAttemptStatus);\r
+}\r
+\r
 /**\r
   Updates the firmware image of the device.\r
 \r
@@ -945,20 +1176,36 @@ SetTheImage (
   VOID                              *FmpHeader;\r
   UINTN                             FmpPayloadSize;\r
   UINT32                            AllHeaderSize;\r
-  UINT32                            IncommingFwVersion;\r
+  UINT32                            IncomingFwVersion;\r
   UINT32                            LastAttemptStatus;\r
   UINT32                            Version;\r
   UINT32                            LowestSupportedVersion;\r
+  EFI_FIRMWARE_IMAGE_DEP            *Dependencies;\r
+  UINT32                            DependenciesSize;\r
+\r
+  Status            = EFI_SUCCESS;\r
+  Private           = NULL;\r
+  Updateable        = 0;\r
+  BooleanValue      = FALSE;\r
+  FmpHeaderSize     = 0;\r
+  FmpHeader         = NULL;\r
+  FmpPayloadSize    = 0;\r
+  AllHeaderSize     = 0;\r
+  IncomingFwVersion = 0;\r
+  LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+  Dependencies      = NULL;\r
+  DependenciesSize  = 0;\r
+\r
+  if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
 \r
-  Status             = EFI_SUCCESS;\r
-  Updateable         = 0;\r
-  BooleanValue       = FALSE;\r
-  FmpHeaderSize      = 0;\r
-  FmpHeader          = NULL;\r
-  FmpPayloadSize     = 0;\r
-  AllHeaderSize      = 0;\r
-  IncommingFwVersion = 0;\r
-  LastAttemptStatus  = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+  if (This == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - This is NULL.\n", mImageIdName));\r
+    Status            = EFI_INVALID_PARAMETER;\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_PROTOCOL_ARG_MISSING;\r
+    goto cleanup;\r
+  }\r
 \r
   //\r
   // Retrieve the private context structure\r
@@ -974,7 +1221,7 @@ SetTheImage (
   //\r
   // Set to 0 to clear any previous results.\r
   //\r
-  SetLastAttemptVersionInVariable (Private, IncommingFwVersion);\r
+  SetLastAttemptVersionInVariable (Private, IncomingFwVersion);\r
 \r
   //\r
   // if we have locked the device, then skip the set operation.\r
@@ -982,54 +1229,63 @@ SetTheImage (
   //\r
   if (Private->FmpDeviceLocked) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Device is already locked.  Can't update.\n", mImageIdName));\r
-    Status = EFI_UNSUPPORTED;\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_DEVICE_LOCKED;\r
+    Status            = EFI_UNSUPPORTED;\r
     goto cleanup;\r
   }\r
 \r
   //\r
   // Call check image to verify the image\r
   //\r
-  Status = CheckTheImage (This, ImageIndex, Image, ImageSize, &Updateable);\r
+  Status = CheckTheImageInternal (This, ImageIndex, Image, ImageSize, &Updateable, &LastAttemptStatus);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Check The Image failed with %r.\n", mImageIdName, Status));\r
-    if (Status == EFI_SECURITY_VIOLATION) {\r
-      LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
-    }\r
     goto cleanup;\r
   }\r
 \r
+  //\r
+  // Get the dependency from Image.\r
+  //\r
+  Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize, &LastAttemptStatus);\r
+\r
   //\r
   // No functional error in CheckTheImage.  Attempt to get the Version to\r
   // support better error reporting.\r
   //\r
-  FmpHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );\r
+  FmpHeader = GetFmpHeader ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, DependenciesSize, &FmpPayloadSize);\r
   if (FmpHeader == NULL) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetFmpHeader failed.\n", mImageIdName));\r
-    Status = EFI_ABORTED;\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER;\r
+    Status            = EFI_ABORTED;\r
     goto cleanup;\r
   }\r
-  Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncommingFwVersion);\r
+\r
+  Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncomingFwVersion);\r
   if (!EFI_ERROR (Status)) {\r
     //\r
     // Set to actual value\r
     //\r
-    SetLastAttemptVersionInVariable (Private, IncommingFwVersion);\r
+    SetLastAttemptVersionInVariable (Private, IncomingFwVersion);\r
   }\r
 \r
-\r
   if (Updateable != IMAGE_UPDATABLE_VALID) {\r
     DEBUG (\r
       (DEBUG_ERROR,\r
-      "FmpDxe(%s): SetTheImage() - Check The Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n",\r
-      mImageIdName, Updateable)\r
+       "FmpDxe(%s): SetTheImage() - Check The Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n",\r
+       mImageIdName, Updateable)\r
       );\r
+    if (Private->DependenciesSatisfied == FALSE) {\r
+      LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSATISFIED_DEPENDENCIES;\r
+    }\r
+\r
     Status = EFI_ABORTED;\r
     goto cleanup;\r
   }\r
 \r
   if (Progress == NULL) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Invalid progress callback\n", mImageIdName));\r
-    Status = EFI_INVALID_PARAMETER;\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_PROGRESS_CALLBACK_ERROR;\r
+    Status            = EFI_INVALID_PARAMETER;\r
     goto cleanup;\r
   }\r
 \r
@@ -1044,18 +1300,20 @@ SetTheImage (
   }\r
 \r
   //\r
-  //Check System Power\r
+  // Check System Power\r
   //\r
   Status = CheckSystemPower (&BooleanValue);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemPower - API call failed %r.\n", mImageIdName, Status));\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_CHECK_POWER_API;\r
     goto cleanup;\r
   }\r
+\r
   if (!BooleanValue) {\r
     Status = EFI_ABORTED;\r
     DEBUG (\r
       (DEBUG_ERROR,\r
-      "FmpDxe(%s): SetTheImage() - CheckSystemPower - returned False.  Update not allowed due to System Power.\n", mImageIdName)\r
+       "FmpDxe(%s): SetTheImage() - CheckSystemPower - returned False.  Update not allowed due to System Power.\n", mImageIdName)\r
       );\r
     LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_PWR_EVT_BATT;\r
     goto cleanup;\r
@@ -1064,18 +1322,21 @@ SetTheImage (
   Progress (2);\r
 \r
   //\r
-  //Check System Thermal\r
+  // Check System Thermal\r
   //\r
   Status = CheckSystemThermal (&BooleanValue);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemThermal - API call failed %r.\n", mImageIdName, Status));\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_CHECK_SYS_THERMAL_API;\r
     goto cleanup;\r
   }\r
+\r
   if (!BooleanValue) {\r
-    Status = EFI_ABORTED;\r
+    Status            = EFI_ABORTED;\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_THERMAL;\r
     DEBUG (\r
       (DEBUG_ERROR,\r
-      "FmpDxe(%s): SetTheImage() - CheckSystemThermal - returned False.  Update not allowed due to System Thermal.\n", mImageIdName)\r
+       "FmpDxe(%s): SetTheImage() - CheckSystemThermal - returned False.  Update not allowed due to System Thermal.\n", mImageIdName)\r
       );\r
     goto cleanup;\r
   }\r
@@ -1083,18 +1344,21 @@ SetTheImage (
   Progress (3);\r
 \r
   //\r
-  //Check System Environment\r
+  // Check System Environment\r
   //\r
   Status = CheckSystemEnvironment (&BooleanValue);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemEnvironment - API call failed %r.\n", mImageIdName, Status));\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_CHECK_SYS_ENV_API;\r
     goto cleanup;\r
   }\r
+\r
   if (!BooleanValue) {\r
-    Status = EFI_ABORTED;\r
+    Status            = EFI_ABORTED;\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_SYSTEM_ENV;\r
     DEBUG (\r
       (DEBUG_ERROR,\r
-      "FmpDxe(%s): SetTheImage() - CheckSystemEnvironment - returned False.  Update not allowed due to System Environment.\n", mImageIdName)\r
+       "FmpDxe(%s): SetTheImage() - CheckSystemEnvironment - returned False.  Update not allowed due to System Environment.\n", mImageIdName)\r
       );\r
     goto cleanup;\r
   }\r
@@ -1113,13 +1377,15 @@ SetTheImage (
   Status = GetFmpPayloadHeaderSize (FmpHeader, FmpPayloadSize, &FmpHeaderSize);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetFmpPayloadHeaderSize failed %r.\n", mImageIdName, Status));\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER_SIZE;\r
     goto cleanup;\r
   }\r
 \r
-  AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );\r
+  AllHeaderSize = GetAllHeaderSize ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize + DependenciesSize);\r
   if (AllHeaderSize == 0) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\r
-    Status = EFI_ABORTED;\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_ALL_HEADER_SIZE;\r
+    Status            = EFI_ABORTED;\r
     goto cleanup;\r
   }\r
 \r
@@ -1129,21 +1395,50 @@ SetTheImage (
   Progress (5);\r
 \r
   //\r
-  //Copy the requested image to the firmware using the FmpDeviceLib\r
+  // Copy the requested image to the firmware using the FmpDeviceLib\r
   //\r
-  Status = FmpDeviceSetImage (\r
+  Status = FmpDeviceSetImageWithStatus (\r
              (((UINT8 *)Image) + AllHeaderSize),\r
              ImageSize - AllHeaderSize,\r
              VendorCode,\r
              FmpDxeProgress,\r
-             IncommingFwVersion,\r
-             AbortReason\r
+             IncomingFwVersion,\r
+             AbortReason,\r
+             &LastAttemptStatus\r
              );\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() SetImage from FmpDeviceLib failed. Status =  %r.\n", mImageIdName, Status));\r
+\r
+    //\r
+    // LastAttemptStatus returned from the device library should fall within the designated error range\r
+    // [LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE, LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE]\r
+    //\r
+    if ((LastAttemptStatus < LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE) ||\r
+        (LastAttemptStatus > LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE))\r
+    {\r
+      DEBUG (\r
+        (DEBUG_ERROR,\r
+         "FmpDxe(%s): SetTheImage() - LastAttemptStatus %d from FmpDeviceSetImageWithStatus() is invalid.\n",\r
+         mImageIdName,\r
+         LastAttemptStatus)\r
+        );\r
+      LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+    }\r
+\r
     goto cleanup;\r
   }\r
 \r
+  //\r
+  // Store the dependency\r
+  //\r
+  if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
+    Status = SaveFmpDependency (Dependencies, DependenciesSize);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() SaveFmpDependency from FmpDependencyCheckLib failed. (%r)\n", mImageIdName, Status));\r
+    }\r
+\r
+    Status = EFI_SUCCESS;\r
+  }\r
 \r
   //\r
   // Finished the update without error\r
@@ -1171,7 +1466,11 @@ SetTheImage (
 \r
 cleanup:\r
   mProgressFunc = NULL;\r
-  SetLastAttemptStatusInVariable (Private, LastAttemptStatus);\r
+\r
+  if (Private != NULL) {\r
+    DEBUG ((DEBUG_INFO, "FmpDxe(%s): SetTheImage() LastAttemptStatus: %u.\n", mImageIdName, LastAttemptStatus));\r
+    SetLastAttemptStatusInVariable (Private, LastAttemptStatus);\r
+  }\r
 \r
   if (Progress != NULL) {\r
     //\r
@@ -1184,7 +1483,9 @@ cleanup:
   // Need repopulate after SetImage is called to\r
   // update LastAttemptVersion and LastAttemptStatus.\r
   //\r
-  Private->DescriptorPopulated = FALSE;\r
+  if (Private != NULL) {\r
+    Private->DescriptorPopulated = FALSE;\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -1298,6 +1599,11 @@ FmpDxeLockEventNotify (
   EFI_STATUS                        Status;\r
   FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
 \r
+  if (Context == NULL) {\r
+    ASSERT (Context != NULL);\r
+    return;\r
+  }\r
+\r
   Private = (FIRMWARE_MANAGEMENT_PRIVATE_DATA *)Context;\r
 \r
   if (!Private->FmpDeviceLocked) {\r
@@ -1305,7 +1611,7 @@ FmpDxeLockEventNotify (
     // Lock the firmware device\r
     //\r
     FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
-    Status = FmpDeviceLock();\r
+    Status = FmpDeviceLock ();\r
     if (EFI_ERROR (Status)) {\r
       if (Status != EFI_UNSUPPORTED) {\r
         DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLock() returned error.  Status = %r\n", mImageIdName, Status));\r
@@ -1313,6 +1619,7 @@ FmpDxeLockEventNotify (
         DEBUG ((DEBUG_WARN, "FmpDxe(%s): FmpDeviceLock() returned error.  Status = %r\n", mImageIdName, Status));\r
       }\r
     }\r
+\r
     Private->FmpDeviceLocked = TRUE;\r
   }\r
 }\r
@@ -1368,9 +1675,9 @@ InstallFmpInstance (
   //\r
   // Initialize private context data structure\r
   //\r
-  Private->Handle = Handle;\r
+  Private->Handle           = Handle;\r
   Private->FmpDeviceContext = NULL;\r
-  Status = FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
+  Status                    = FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
   if (Status == EFI_UNSUPPORTED) {\r
     Private->FmpDeviceContext = NULL;\r
   } else if (EFI_ERROR (Status)) {\r
@@ -1407,6 +1714,7 @@ InstallFmpInstance (
     if (EFI_ERROR (Status)) {\r
       DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to register notification.  Status = %r\n", mImageIdName, Status));\r
     }\r
+\r
     ASSERT_EFI_ERROR (Status);\r
   } else {\r
     DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): Not registering notification to call FmpDeviceLock() because mfg mode\n", mImageIdName));\r
@@ -1417,8 +1725,10 @@ InstallFmpInstance (
   //\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &Private->Handle,\r
-                  &gEfiFirmwareManagementProtocolGuid, &Private->Fmp,\r
-                  &gEdkiiFirmwareManagementProgressProtocolGuid, &mFmpProgress,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  &Private->Fmp,\r
+                  &gEdkiiFirmwareManagementProgressProtocolGuid,\r
+                  &mFmpProgress,\r
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
@@ -1433,27 +1743,35 @@ cleanup:
       if (Private->FmpDeviceLockEvent != NULL) {\r
         gBS->CloseEvent (Private->FmpDeviceLockEvent);\r
       }\r
+\r
       if (Private->Descriptor.VersionName != NULL) {\r
         FreePool (Private->Descriptor.VersionName);\r
       }\r
+\r
       if (Private->FmpDeviceContext != NULL) {\r
         FmpDeviceSetContext (NULL, &Private->FmpDeviceContext);\r
       }\r
+\r
       if (Private->VersionVariableName != NULL) {\r
         FreePool (Private->VersionVariableName);\r
       }\r
+\r
       if (Private->LsvVariableName != NULL) {\r
         FreePool (Private->LsvVariableName);\r
       }\r
+\r
       if (Private->LastAttemptStatusVariableName != NULL) {\r
         FreePool (Private->LastAttemptStatusVariableName);\r
       }\r
+\r
       if (Private->LastAttemptVersionVariableName != NULL) {\r
         FreePool (Private->LastAttemptVersionVariableName);\r
       }\r
+\r
       if (Private->FmpStateVariableName != NULL) {\r
         FreePool (Private->FmpStateVariableName);\r
       }\r
+\r
       FreePool (Private);\r
     }\r
   }\r
@@ -1503,8 +1821,10 @@ UninstallFmpInstance (
 \r
   Status = gBS->UninstallMultipleProtocolInterfaces (\r
                   Private->Handle,\r
-                  &gEfiFirmwareManagementProtocolGuid, &Private->Fmp,\r
-                  &gEdkiiFirmwareManagementProgressProtocolGuid, &mFmpProgress,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  &Private->Fmp,\r
+                  &gEdkiiFirmwareManagementProgressProtocolGuid,\r
+                  &mFmpProgress,\r
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
@@ -1515,24 +1835,31 @@ UninstallFmpInstance (
   if (Private->Descriptor.VersionName != NULL) {\r
     FreePool (Private->Descriptor.VersionName);\r
   }\r
+\r
   if (Private->FmpDeviceContext != NULL) {\r
     FmpDeviceSetContext (NULL, &Private->FmpDeviceContext);\r
   }\r
+\r
   if (Private->VersionVariableName != NULL) {\r
     FreePool (Private->VersionVariableName);\r
   }\r
+\r
   if (Private->LsvVariableName != NULL) {\r
     FreePool (Private->LsvVariableName);\r
   }\r
+\r
   if (Private->LastAttemptStatusVariableName != NULL) {\r
     FreePool (Private->LastAttemptStatusVariableName);\r
   }\r
+\r
   if (Private->LastAttemptVersionVariableName != NULL) {\r
     FreePool (Private->LastAttemptVersionVariableName);\r
   }\r
+\r
   if (Private->FmpStateVariableName != NULL) {\r
     FreePool (Private->FmpStateVariableName);\r
   }\r
+\r
   FreePool (Private);\r
 \r
   return EFI_SUCCESS;\r
@@ -1557,6 +1884,7 @@ FmpDxeLibDestructor (
   if (mFmpSingleInstance) {\r
     return UninstallFmpInstance (ImageHandle);\r
   }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -1590,12 +1918,12 @@ FmpDxeEntryPoint (
   //\r
   // Get the ImageIdName value for the EFI_FIRMWARE_IMAGE_DESCRIPTOR from a PCD.\r
   //\r
-  mImageIdName = (CHAR16 *) PcdGetPtr (PcdFmpDeviceImageIdName);\r
-  if (PcdGetSize (PcdFmpDeviceImageIdName) <= 2 || mImageIdName[0] == 0) {\r
+  mImageIdName = (CHAR16 *)PcdGetPtr (PcdFmpDeviceImageIdName);\r
+  if ((PcdGetSize (PcdFmpDeviceImageIdName) <= 2) || (mImageIdName[0] == 0)) {\r
     //\r
     // PcdFmpDeviceImageIdName must be set to a non-empty Unicode string\r
     //\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: PcdFmpDeviceImageIdName is an empty string.\n"));\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%g): PcdFmpDeviceImageIdName is an empty string.\n", &gEfiCallerIdGuid));\r
     ASSERT (FALSE);\r
     return EFI_UNSUPPORTED;\r
   }\r
@@ -1620,6 +1948,7 @@ FmpDxeEntryPoint (
   if (PcdGetSize (PcdFmpDeviceLockEventGuid) == sizeof (EFI_GUID)) {\r
     mLockGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceLockEventGuid);\r
   }\r
+\r
   DEBUG ((DEBUG_INFO, "FmpDxe(%s): Lock GUID: %g\n", mImageIdName, mLockGuid));\r
 \r
   //\r