]> 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 57eac5ac147fc925b2c4ac98c4a3ba42d57627d0..1e7ec4a09e1611c9bef2abe6170d1fa699664e86 100644 (file)
@@ -3,65 +3,16 @@
   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, Intel Corporation. All rights reserved.<BR>\r
-\r
-  Redistribution and use in source and binary forms, with or without\r
-  modification, are permitted provided that the following conditions are met:\r
-  1. Redistributions of source code must retain the above copyright notice,\r
-  this list of conditions and the following disclaimer.\r
-  2. Redistributions in binary form must reproduce the above copyright notice,\r
-  this list of conditions and the following disclaimer in the documentation\r
-  and/or other materials provided with the distribution.\r
-\r
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
-  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
-  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
-  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r
-  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
-  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
-  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\r
-  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
-  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\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
 **/\r
 \r
-#include <PiDxe.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/FmpAuthenticationLib.h>\r
-#include <Library/FmpDeviceLib.h>\r
-#include <Library/FmpPayloadHeaderLib.h>\r
-#include <Library/CapsuleUpdatePolicyLib.h>\r
-#include <Protocol/FirmwareManagement.h>\r
-#include <Protocol/FirmwareManagementProgress.h>\r
-#include <Guid/SystemResourceTable.h>\r
-#include <Guid/EventGroup.h>\r
+#include "FmpDxe.h"\r
 #include "VariableSupport.h"\r
 \r
-#define VERSION_STRING_NOT_SUPPORTED  L"VERSION STRING NOT SUPPORTED"\r
-#define VERSION_STRING_NOT_AVAILABLE  L"VERSION STRING NOT AVAILABLE"\r
-\r
-/**\r
-  Check to see if any of the keys in PcdFmpDevicePkcs7CertBufferXdr matches\r
-  the test key.  PcdFmpDeviceTestKeySha256Digest contains the SHA256 hash of\r
-  the test key.  For each key in PcdFmpDevicePkcs7CertBufferXdr, compute the\r
-  SHA256 hash and compare it to PcdFmpDeviceTestKeySha256Digest.  If the\r
-  SHA256 hash matches or there is then error computing the SHA256 hash, then\r
-  set PcdTestKeyUsed to TRUE.  Skip this check if PcdTestKeyUsed is already\r
-  TRUE or PcdFmpDeviceTestKeySha256Digest is not exactly SHA256_DIGEST_SIZE\r
-  bytes.\r
-**/\r
-VOID\r
-DetectTestKey (\r
-  VOID\r
-  );\r
-\r
 ///\r
 /// FILE_GUID from FmpDxe.inf.  When FmpDxe.inf is used in a platform, the\r
 /// FILE_GUID must always be overridden in the <Defines> section to provide\r
@@ -73,30 +24,81 @@ const EFI_GUID  mDefaultModuleFileGuid = {
   0x78ef0a56, 0x1cf0, 0x4535, { 0xb5, 0xda, 0xf6, 0xfd, 0x2f, 0x40, 0x5a, 0x11 }\r
 };\r
 \r
-EFI_FIRMWARE_IMAGE_DESCRIPTOR  mDesc;\r
-BOOLEAN                        mDescriptorPopulated     = FALSE;\r
-BOOLEAN                        mRuntimeVersionSupported = TRUE;\r
-BOOLEAN                        mFmpInstalled            = FALSE;\r
-\r
 ///\r
-/// Function pointer to progress function\r
+/// TRUE if FmpDeviceLib manages a single firmware storage device.\r
 ///\r
-EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  mProgressFunc      = NULL;\r
-BOOLEAN                                        mProgressSupported = FALSE;\r
+BOOLEAN  mFmpSingleInstance = FALSE;\r
 \r
-CHAR16  *mImageIdName = NULL;\r
-UINT64  mImageId      = 0x1;\r
-CHAR16  *mVersionName = NULL;\r
+///\r
+/// Firmware Management Protocol instance that is initialized in the entry\r
+/// point from PCD settings.\r
+///\r
+EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  mFmpProgress;\r
 \r
-EFI_EVENT  mFmpDeviceLockEvent;\r
 //\r
-// Indicates if an attempt has been made to lock a\r
-// FLASH storage device by calling FmpDeviceLock().\r
-// A FLASH storage device may not support being locked,\r
-// so this variable is set to TRUE even if FmpDeviceLock()\r
-// returns an error.\r
+// Template of the private context structure for the Firmware Management\r
+// Protocol instance\r
 //\r
-BOOLEAN    mFmpDeviceLocked = FALSE;\r
+const FIRMWARE_MANAGEMENT_PRIVATE_DATA  mFirmwareManagementPrivateDataTemplate = {\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA_SIGNATURE, // Signature\r
+  NULL,                                       // Handle\r
+  {                                            // Fmp\r
+    GetTheImageInfo,\r
+    GetTheImage,\r
+    SetTheImage,\r
+    CheckTheImage,\r
+    GetPackageInfo,\r
+    SetPackageInfo\r
+  },\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
+    },\r
+    1,     // ImageId\r
+    NULL,  // ImageIdName\r
+    0,     // Version\r
+    NULL,  // VersionName\r
+    0,     // Size\r
+    0,     // AttributesSupported\r
+    0,     // AttributesSetting\r
+    0,     // Compatibilities\r
+    0,     // LowestSupportedImageVersion\r
+    0,     // LastAttemptVersion\r
+    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
+  TRUE              // DependenciesSatisfied\r
+};\r
+\r
+///\r
+/// GUID that is used to create event used to lock the firmware storage device.\r
+///\r
+EFI_GUID  *mLockGuid = NULL;\r
+\r
+///\r
+/// Progress() function pointer passed into SetTheImage()\r
+///\r
+EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  mProgressFunc = NULL;\r
+\r
+///\r
+/// Null-terminated Unicode string retrieved from PcdFmpDeviceImageIdName.\r
+///\r
+CHAR16  *mImageIdName = NULL;\r
 \r
 /**\r
   Callback function to report the process of the firmware updating.\r
@@ -124,14 +126,10 @@ FmpDxeProgress (
   IN UINTN  Completion\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  EFI_STATUS  Status;\r
 \r
   Status = EFI_UNSUPPORTED;\r
 \r
-  if (!mProgressSupported) {\r
-    return Status;\r
-  }\r
-\r
   if (mProgressFunc == NULL) {\r
     return Status;\r
   }\r
@@ -142,7 +140,6 @@ FmpDxeProgress (
   Status = mProgressFunc (((Completion * 92) / 100) + 6);\r
 \r
   if (Status == EFI_UNSUPPORTED) {\r
-    mProgressSupported = FALSE;\r
     mProgressFunc = NULL;\r
   }\r
 \r
@@ -152,9 +149,11 @@ 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
-  @return  The ImageTypeId GUID\r
+  @retval  The ImageTypeId GUID\r
 \r
 **/\r
 EFI_GUID *\r
@@ -164,26 +163,36 @@ 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: FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid error %r\n", Status));\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid error %r\n", mImageIdName, Status));\r
     }\r
-    return &gEfiCallerIdGuid;\r
+  } else if (FmpDeviceLibGuid == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid GUID\n", mImageIdName));\r
+    Status = EFI_NOT_FOUND;\r
   }\r
-  if (FmpDeviceLibGuid == NULL) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid GUID\n"));\r
-    return &gEfiCallerIdGuid;\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
 /**\r
   Returns a pointer to the Null-terminated Unicode ImageIdName string.\r
 \r
-  @return  Null-terminated Unicode ImageIdName string.\r
+  @retval  Null-terminated Unicode ImageIdName string.\r
 \r
 **/\r
 CHAR16 *\r
@@ -200,12 +209,15 @@ GetImageTypeNameString (
   2. Check if we have a variable for lowest supported version (this will be updated with each capsule applied)\r
   3. Check Fixed at build PCD\r
 \r
-  Take the largest value\r
+  @param[in] Private  Pointer to the private context structure for the\r
+                      Firmware Management Protocol instance.\r
+\r
+  @retval  The largest value\r
 \r
 **/\r
 UINT32\r
 GetLowestSupportedVersion (\r
-  VOID\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private\r
   )\r
 {\r
   EFI_STATUS  Status;\r
@@ -230,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
@@ -242,7 +254,7 @@ GetLowestSupportedVersion (
   //\r
   // Check the lowest supported version UEFI variable for this device\r
   //\r
-  VariableLowestSupportedVersion = GetLowestSupportedVersionFromVariable();\r
+  VariableLowestSupportedVersion = GetLowestSupportedVersionFromVariable (Private);\r
   if (VariableLowestSupportedVersion > ReturnLsv) {\r
     ReturnLsv = VariableLowestSupportedVersion;\r
   }\r
@@ -254,101 +266,141 @@ GetLowestSupportedVersion (
 }\r
 \r
 /**\r
-  Populates the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure in the module global\r
-  variable mDesc.\r
+  Populates the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure in the private\r
+  context structure.\r
+\r
+  @param[in] Private  Pointer to the private context structure for the\r
+                      Firmware Management Protocol instance.\r
 \r
 **/\r
 VOID\r
 PopulateDescriptor (\r
-  VOID\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private\r
   )\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
+  Private->Descriptor.ImageId     = Private->Descriptor.ImageIndex;\r
+  Private->Descriptor.ImageIdName = GetImageTypeNameString ();\r
 \r
-  mDesc.ImageIndex = 1;\r
-  CopyGuid (&mDesc.ImageTypeId, GetImageTypeIdGuid());\r
-  mDesc.ImageId = mImageId;\r
-  mDesc.ImageIdName = GetImageTypeNameString();\r
+  //\r
+  // Get the hardware instance from FmpDeviceLib\r
+  //\r
+  Status = FmpDeviceGetHardwareInstance (&Private->Descriptor.HardwareInstance);\r
+  if (Status == EFI_UNSUPPORTED) {\r
+    Private->Descriptor.HardwareInstance = 0;\r
+  }\r
+\r
+  //\r
+  // Generate UEFI Variable names used to store status information for this\r
+  // FMP instance.\r
+  //\r
+  GenerateFmpVariableNames (Private);\r
 \r
   //\r
   // Get the version.  Some devices don't support getting the firmware version\r
   // at runtime.  If FmpDeviceLib does not support returning a version, then\r
   // it is stored in a UEFI variable.\r
   //\r
-  Status = FmpDeviceGetVersion (&mDesc.Version);\r
+  Status = FmpDeviceGetVersion (&Private->Descriptor.Version);\r
   if (Status == EFI_UNSUPPORTED) {\r
-    mRuntimeVersionSupported = FALSE;\r
-    mDesc.Version = GetVersionFromVariable();\r
+    Private->RuntimeVersionSupported = FALSE;\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: GetVersion() from FmpDeviceLib (%s) returned %r\n", GetImageTypeNameString(), Status));\r
-    mDesc.Version = DEFAULT_VERSION;\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
   //\r
   // Free the current version name.  Shouldn't really happen but this populate\r
   // function could be called multiple times (to refresh).\r
   //\r
-  if (mVersionName != NULL) {\r
-    FreePool (mVersionName);\r
-    mVersionName = NULL;\r
+  if (Private->Descriptor.VersionName != NULL) {\r
+    FreePool (Private->Descriptor.VersionName);\r
+    Private->Descriptor.VersionName = NULL;\r
   }\r
 \r
   //\r
   // Attempt to get the version string from the FmpDeviceLib\r
   //\r
-  Status = FmpDeviceGetVersionString (&mVersionName);\r
+  Status = FmpDeviceGetVersionString (&Private->Descriptor.VersionName);\r
   if (Status == EFI_UNSUPPORTED) {\r
-    DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() unsupported in FmpDeviceLib.\n"));\r
-    mVersionName = AllocateCopyPool (\r
-                     sizeof (VERSION_STRING_NOT_SUPPORTED),\r
-                     VERSION_STRING_NOT_SUPPORTED\r
-                     );\r
+    DEBUG ((DEBUG_INFO, "FmpDxe(%s): GetVersionString() unsupported in FmpDeviceLib.\n", mImageIdName));\r
+    Private->Descriptor.VersionName = AllocateCopyPool (\r
+                                        sizeof (VERSION_STRING_NOT_SUPPORTED),\r
+                                        VERSION_STRING_NOT_SUPPORTED\r
+                                        );\r
   } else if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() not available in FmpDeviceLib.\n"));\r
-    mVersionName = AllocateCopyPool (\r
-                     sizeof (VERSION_STRING_NOT_AVAILABLE),\r
-                     VERSION_STRING_NOT_AVAILABLE\r
-                     );\r
+    DEBUG ((DEBUG_INFO, "FmpDxe(%s): GetVersionString() not available in FmpDeviceLib.\n", mImageIdName));\r
+    Private->Descriptor.VersionName = AllocateCopyPool (\r
+                                        sizeof (VERSION_STRING_NOT_AVAILABLE),\r
+                                        VERSION_STRING_NOT_AVAILABLE\r
+                                        );\r
   }\r
 \r
-  mDesc.VersionName = mVersionName;\r
-\r
-  mDesc.LowestSupportedImageVersion = GetLowestSupportedVersion();\r
+  Private->Descriptor.LowestSupportedImageVersion = GetLowestSupportedVersion (Private);\r
 \r
   //\r
   // Get attributes from the FmpDeviceLib\r
   //\r
-  FmpDeviceGetAttributes (&mDesc.AttributesSupported, &mDesc.AttributesSetting);\r
+  FmpDeviceGetAttributes (\r
+    &Private->Descriptor.AttributesSupported,\r
+    &Private->Descriptor.AttributesSetting\r
+    );\r
 \r
   //\r
   // Force set the updatable bits in the attributes;\r
   //\r
-  mDesc.AttributesSupported |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;\r
-  mDesc.AttributesSetting   |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;\r
+  Private->Descriptor.AttributesSupported |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;\r
+  Private->Descriptor.AttributesSetting   |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;\r
 \r
   //\r
   // Force set the authentication bits in the attributes;\r
   //\r
-  mDesc.AttributesSupported |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
-  mDesc.AttributesSetting   |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+  Private->Descriptor.AttributesSupported |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+  Private->Descriptor.AttributesSetting   |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
 \r
-  mDesc.Compatibilities = 0;\r
+  Private->Descriptor.Compatibilities = 0;\r
 \r
   //\r
   // Get the size of the firmware image from the FmpDeviceLib\r
   //\r
-  Status = FmpDeviceGetSize (&mDesc.Size);\r
+  Status = FmpDeviceGetSize (&Private->Descriptor.Size);\r
   if (EFI_ERROR (Status)) {\r
-    mDesc.Size = 0;\r
+    Private->Descriptor.Size = 0;\r
   }\r
 \r
-  mDesc.LastAttemptVersion = GetLastAttemptVersionFromVariable ();\r
-  mDesc.LastAttemptStatus  = GetLastAttemptStatusFromVariable ();\r
+  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
-  mDescriptorPopulated = TRUE;\r
+  Private->DescriptorPopulated = TRUE;\r
 }\r
 \r
 /**\r
@@ -402,15 +454,28 @@ GetTheImageInfo (
   OUT    CHAR16                            **PackageVersionName\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  EFI_STATUS                        Status;\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
 \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
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);\r
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
+\r
   //\r
   // Check for valid pointer\r
   //\r
   if (ImageInfoSize == NULL) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: GetImageInfo() - ImageInfoSize is NULL.\n"));\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImageInfo() - ImageInfoSize is NULL.\n", mImageIdName));\r
     Status = EFI_INVALID_PARAMETER;\r
     goto cleanup;\r
   }\r
@@ -421,7 +486,7 @@ GetTheImageInfo (
   //\r
   if (*ImageInfoSize < (sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR))) {\r
     *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);\r
-    DEBUG ((DEBUG_VERBOSE, "FmpDxe: GetImageInfo() - ImageInfoSize is to small.\n"));\r
+    DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): GetImageInfo() - ImageInfoSize is to small.\n", mImageIdName));\r
     Status = EFI_BUFFER_TOO_SMALL;\r
     goto cleanup;\r
   }\r
@@ -429,9 +494,10 @@ GetTheImageInfo (
   //\r
   // Confirm that buffer isn't null\r
   //\r
-  if ( (ImageInfo == NULL) || (DescriptorVersion == NULL) || (DescriptorCount == NULL) || (DescriptorSize == NULL)\r
-       || (PackageVersion == NULL)) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: GetImageInfo() - Pointer Parameter is NULL.\n"));\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
   }\r
@@ -441,19 +507,19 @@ GetTheImageInfo (
   //\r
   *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);\r
 \r
-\r
-  if (!mDescriptorPopulated) {\r
-    PopulateDescriptor();\r
-  }\r
+  //\r
+  // Make sure the descriptor has already been loaded or refreshed\r
+  //\r
+  PopulateDescriptor (Private);\r
 \r
   //\r
   // Copy the image descriptor\r
   //\r
-  CopyMem (ImageInfo, &mDesc, sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR));\r
+  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
@@ -500,22 +566,39 @@ GetTheImage (
   IN OUT UINTN                             *ImageSize\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  UINTN       Size;\r
+  EFI_STATUS                        Status;\r
+  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
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);\r
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
+\r
   //\r
   // Check to make sure index is 1 (only 1 image for this device)\r
   //\r
   if (ImageIndex != 1) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - Image Index Invalid.\n"));\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - Image Index Invalid.\n", mImageIdName));\r
     Status = EFI_INVALID_PARAMETER;\r
     goto cleanup;\r
   }\r
 \r
   if (ImageSize == NULL) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - ImageSize Pointer Parameter is NULL.\n"));\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - ImageSize Pointer Parameter is NULL.\n", mImageIdName));\r
     Status = EFI_INVALID_PARAMETER;\r
     goto cleanup;\r
   }\r
@@ -527,15 +610,16 @@ GetTheImage (
   if (EFI_ERROR (Status)) {\r
     Size = 0;\r
   }\r
+\r
   if (*ImageSize < Size) {\r
     *ImageSize = Size;\r
-    DEBUG ((DEBUG_VERBOSE, "FmpDxe: GetImage() - ImageSize is to small.\n"));\r
+    DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): GetImage() - ImageSize is to small.\n", mImageIdName));\r
     Status = EFI_BUFFER_TOO_SMALL;\r
     goto cleanup;\r
   }\r
 \r
   if (Image == NULL) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - Image Pointer Parameter is NULL.\n"));\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - Image Pointer Parameter is NULL.\n", mImageIdName));\r
     Status = EFI_INVALID_PARAMETER;\r
     goto cleanup;\r
   }\r
@@ -550,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
@@ -562,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
@@ -599,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
@@ -606,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
@@ -631,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
@@ -641,68 +755,111 @@ 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
-  UINTN       RawSize;\r
-  VOID        *FmpPayloadHeader;\r
-  UINTN       FmpPayloadSize;\r
-  UINT32      Version;\r
-  UINT32      FmpHeaderSize;\r
-  UINTN       AllHeaderSize;\r
-  UINT32      Index;\r
-  VOID        *PublicKeyData;\r
-  UINTN       PublicKeyDataLength;\r
-  UINT8       *PublicKeyDataXdr;\r
-  UINT8       *PublicKeyDataXdrEnd;\r
+  EFI_STATUS                        Status;\r
+  UINT32                            LocalLastAttemptStatus;\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
+  UINTN                             RawSize;\r
+  VOID                              *FmpPayloadHeader;\r
+  UINTN                             FmpPayloadSize;\r
+  UINT32                            Version;\r
+  UINT32                            FmpHeaderSize;\r
+  UINTN                             AllHeaderSize;\r
+  UINT32                            Index;\r
+  VOID                              *PublicKeyData;\r
+  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
-  Status           = EFI_SUCCESS;\r
-  RawSize          = 0;\r
-  FmpPayloadHeader = NULL;\r
-  FmpPayloadSize   = 0;\r
-  Version          = 0;\r
-  FmpHeaderSize    = 0;\r
-  AllHeaderSize    = 0;\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
-  // make sure the descriptor has already been loaded\r
+  // A last attempt status error code will always override the success\r
+  // value before returning from the function\r
   //\r
-  if (!mDescriptorPopulated) {\r
-    PopulateDescriptor();\r
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+\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
+  //\r
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);\r
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
+\r
+  //\r
+  // Make sure the descriptor has already been loaded or refreshed\r
+  //\r
+  PopulateDescriptor (Private);\r
+\r
   if (ImageUpdatable == NULL) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - ImageUpdatable Pointer Parameter is NULL.\n"));\r
-    Status = EFI_INVALID_PARAMETER;\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - ImageUpdatable Pointer Parameter is NULL.\n", mImageIdName));\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: CheckImage() - Image Pointer Parameter is NULL.\n"));\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
-    DEBUG ((DEBUG_ERROR, "FmpDxe: Invalid certificate, skipping it.\n"));\r
-    Status = EFI_ABORTED;\r
+  if ((PublicKeyDataXdr == NULL) || (PublicKeyDataXdr == PublicKeyDataXdrEnd)) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Invalid certificate, skipping it.\n", mImageIdName));\r
+    Status                 = EFI_ABORTED;\r
+    LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_CERTIFICATE;\r
   } else {\r
     //\r
     // Try each key from PcdFmpDevicePkcs7CertBufferXdr\r
@@ -711,10 +868,11 @@ CheckTheImage (
       Index++;\r
       DEBUG (\r
         (DEBUG_INFO,\r
-        "FmpDxe: Certificate #%d [%p..%p].\n",\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
@@ -722,10 +880,12 @@ CheckTheImage (
         //\r
         // Key data extends beyond end of PCD\r
         //\r
-        DEBUG ((DEBUG_ERROR, "FmpDxe: Certificate size extends beyond end of PCD, skipping it.\n"));\r
-        Status = EFI_ABORTED;\r
+        DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Certificate size extends beyond end of PCD, skipping it.\n", mImageIdName));\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
@@ -738,27 +898,36 @@ CheckTheImage (
         //\r
         // Key data extends beyond end of PCD\r
         //\r
-        DEBUG ((DEBUG_ERROR, "FmpDxe: Certificate extends beyond end of PCD, skipping it.\n"));\r
-        Status = EFI_ABORTED;\r
+        DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Certificate extends beyond end of PCD, skipping it.\n", mImageIdName));\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: CheckTheImage() - Authentication Failed %r.\n", 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
@@ -766,41 +935,77 @@ CheckTheImage (
   // Check to make sure index is 1\r
   //\r
   if (ImageIndex != 1) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - Image Index Invalid.\n"));\r
-    *ImageUpdatable = IMAGE_UPDATABLE_INVALID_TYPE;\r
-    Status = EFI_SUCCESS;\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Index Invalid.\n", mImageIdName));\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: CheckTheImage() - GetFmpHeader failed.\n"));\r
-    Status = EFI_ABORTED;\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpHeader failed.\n", mImageIdName));\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: CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", Status));\r
-    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
-    Status = EFI_SUCCESS;\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status));\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
   //\r
   // Check the lowest supported version\r
   //\r
-  if (Version < mDesc.LowestSupportedImageVersion) {\r
+  if (Version < Private->Descriptor.LowestSupportedImageVersion) {\r
     DEBUG (\r
       (DEBUG_ERROR,\r
-      "FmpDxe: CheckTheImage() - Version Lower than lowest supported version. 0x%08X < 0x%08X\n",\r
-      Version, mDesc.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
@@ -810,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
@@ -819,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: CheckTheImage() - GetAllHeaderSize failed.\n"));\r
-    Status = EFI_ABORTED;\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\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
-    DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - FmpDeviceLib CheckImage failed. Status = %r\n", 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
@@ -897,112 +1168,152 @@ SetTheImage (
   OUT CHAR16                                         **AbortReason\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  UINT32      Updateable;\r
-  BOOLEAN     BooleanValue;\r
-  UINT32      FmpHeaderSize;\r
-  VOID        *FmpHeader;\r
-  UINTN       FmpPayloadSize;\r
-  UINT32      AllHeaderSize;\r
-  UINT32      IncommingFwVersion;\r
-  UINT32      LastAttemptStatus;\r
-  UINT32      Version;\r
-  UINT32      LowestSupportedVersion;\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
-\r
-\r
-  SetLastAttemptVersionInVariable (IncommingFwVersion); //set to 0 to clear any previous results.\r
+  EFI_STATUS                        Status;\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
+  UINT32                            Updateable;\r
+  BOOLEAN                           BooleanValue;\r
+  UINT32                            FmpHeaderSize;\r
+  VOID                              *FmpHeader;\r
+  UINTN                             FmpPayloadSize;\r
+  UINT32                            AllHeaderSize;\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
+  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
+  //\r
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);\r
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
+\r
+  //\r
+  // Make sure the descriptor has already been loaded or refreshed\r
+  //\r
+  PopulateDescriptor (Private);\r
+\r
+  //\r
+  // Set to 0 to clear any previous results.\r
+  //\r
+  SetLastAttemptVersionInVariable (Private, IncomingFwVersion);\r
 \r
   //\r
   // if we have locked the device, then skip the set operation.\r
   // it should be blocked by hardware too but we can catch here even faster\r
   //\r
-  if (mFmpDeviceLocked) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Device is already locked.  Can't update.\n"));\r
-    Status = EFI_UNSUPPORTED;\r
+  if (Private->FmpDeviceLocked) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Device is already locked.  Can't update.\n", mImageIdName));\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: SetTheImage() - Check The Image failed with %r.\n", Status));\r
-    if (Status == EFI_SECURITY_VIOLATION) {\r
-      LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
-    }\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Check The Image failed with %r.\n", mImageIdName, Status));\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: SetTheImage() - GetFmpHeader failed.\n"));\r
-    Status = EFI_ABORTED;\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetFmpHeader failed.\n", mImageIdName));\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 (IncommingFwVersion);\r
+    SetLastAttemptVersionInVariable (Private, IncomingFwVersion);\r
   }\r
 \r
-\r
   if (Updateable != IMAGE_UPDATABLE_VALID) {\r
     DEBUG (\r
       (DEBUG_ERROR,\r
-      "FmpDxed: SetTheImage() - Check The Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n",\r
-      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: SetTheImage() - Invalid progress callback\n"));\r
-    Status = EFI_INVALID_PARAMETER;\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Invalid progress callback\n", mImageIdName));\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_PROGRESS_CALLBACK_ERROR;\r
+    Status            = EFI_INVALID_PARAMETER;\r
     goto cleanup;\r
   }\r
 \r
   mProgressFunc = Progress;\r
-  mProgressSupported = TRUE;\r
 \r
   //\r
   // Checking the image is at least 1%\r
   //\r
   Status = Progress (1);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Progress Callback failed with Status %r.\n", Status));\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Progress Callback failed with Status %r.\n", mImageIdName, Status));\r
   }\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: SetTheImage() - CheckSystemPower - API call failed %r.\n", 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: SetTheImage() - CheckSystemPower - returned False.  Update not allowed due to System Power.\n")\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
@@ -1011,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: SetTheImage() - CheckSystemThermal - API call failed %r.\n", 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: SetTheImage() - CheckSystemThermal - returned False.  Update not allowed due to System Thermal.\n")\r
+       "FmpDxe(%s): SetTheImage() - CheckSystemThermal - returned False.  Update not allowed due to System Thermal.\n", mImageIdName)\r
       );\r
     goto cleanup;\r
   }\r
@@ -1030,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: SetTheImage() - CheckSystemEnvironment - API call failed %r.\n", 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: SetTheImage() - CheckSystemEnvironment - returned False.  Update not allowed due to System Environment.\n")\r
+       "FmpDxe(%s): SetTheImage() - CheckSystemEnvironment - returned False.  Update not allowed due to System Environment.\n", mImageIdName)\r
       );\r
     goto cleanup;\r
   }\r
@@ -1052,21 +1369,23 @@ SetTheImage (
   // Save LastAttemptStatus as error so that if SetImage never returns the error\r
   // state is recorded.\r
   //\r
-  SetLastAttemptStatusInVariable (LastAttemptStatus);\r
+  SetLastAttemptStatusInVariable (Private, LastAttemptStatus);\r
 \r
   //\r
   // Strip off all the headers so the device can process its firmware\r
   //\r
   Status = GetFmpPayloadHeaderSize (FmpHeader, FmpPayloadSize, &FmpHeaderSize);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetFmpPayloadHeaderSize failed %r.\n", 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: SetTheImage() - GetAllHeaderSize failed.\n"));\r
-    Status = EFI_ABORTED;\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\r
+    LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_ALL_HEADER_SIZE;\r
+    Status            = EFI_ABORTED;\r
     goto cleanup;\r
   }\r
 \r
@@ -1076,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: SetTheImage() SetImage from FmpDeviceLib failed. Status =  %r.\n", 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
@@ -1101,27 +1449,28 @@ SetTheImage (
   //\r
   // Update the version stored in variable\r
   //\r
-  if (!mRuntimeVersionSupported) {\r
+  if (!Private->RuntimeVersionSupported) {\r
     Version = DEFAULT_VERSION;\r
     GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &Version);\r
-    SetVersionInVariable (Version);\r
+    SetVersionInVariable (Private, Version);\r
   }\r
 \r
   //\r
   // Update lowest supported variable\r
   //\r
-  {\r
-    LowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;\r
-    GetFmpPayloadHeaderLowestSupportedVersion (FmpHeader, FmpPayloadSize, &LowestSupportedVersion);\r
-    SetLowestSupportedVersionInVariable (LowestSupportedVersion);\r
-  }\r
+  LowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;\r
+  GetFmpPayloadHeaderLowestSupportedVersion (FmpHeader, FmpPayloadSize, &LowestSupportedVersion);\r
+  SetLowestSupportedVersionInVariable (Private, LowestSupportedVersion);\r
 \r
   LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
 \r
 cleanup:\r
   mProgressFunc = NULL;\r
-  mProgressSupported = FALSE;\r
-  SetLastAttemptStatusInVariable (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
@@ -1134,7 +1483,9 @@ cleanup:
   // Need repopulate after SetImage is called to\r
   // update LastAttemptVersion and LastAttemptStatus.\r
   //\r
-  mDescriptorPopulated = FALSE;\r
+  if (Private != NULL) {\r
+    Private->DescriptorPopulated = FALSE;\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -1245,21 +1596,31 @@ FmpDxeLockEventNotify (
   IN VOID       *Context\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
+  EFI_STATUS                        Status;\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
 \r
-  if (!mFmpDeviceLocked) {\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
     //\r
     // Lock the firmware device\r
     //\r
-    Status = FmpDeviceLock();\r
+    FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
+    Status = FmpDeviceLock ();\r
     if (EFI_ERROR (Status)) {\r
       if (Status != EFI_UNSUPPORTED) {\r
-        DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLock() returned error.  Status = %r\n", Status));\r
+        DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLock() returned error.  Status = %r\n", mImageIdName, Status));\r
       } else {\r
-        DEBUG ((DEBUG_WARN, "FmpDxe: FmpDeviceLock() returned error.  Status = %r\n", Status));\r
+        DEBUG ((DEBUG_WARN, "FmpDxe(%s): FmpDeviceLock() returned error.  Status = %r\n", mImageIdName, Status));\r
       }\r
     }\r
-    mFmpDeviceLocked = TRUE;\r
+\r
+    Private->FmpDeviceLocked = TRUE;\r
   }\r
 }\r
 \r
@@ -1279,85 +1640,254 @@ InstallFmpInstance (
   IN EFI_HANDLE  Handle\r
   )\r
 {\r
-  EFI_STATUS                                   Status;\r
-  EFI_FIRMWARE_MANAGEMENT_PROTOCOL             *Fmp;\r
-  EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  *FmpProgress;\r
-\r
-  Status      = EFI_SUCCESS;\r
-  Fmp         = NULL;\r
-  FmpProgress = NULL;\r
+  EFI_STATUS                        Status;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
 \r
   //\r
   // Only allow a single FMP Protocol instance to be installed\r
   //\r
-  if (mFmpInstalled) {\r
+  Status = gBS->OpenProtocol (\r
+                  Handle,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  (VOID **)&Fmp,\r
+                  NULL,\r
+                  NULL,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
     return EFI_ALREADY_STARTED;\r
   }\r
 \r
   //\r
   // Allocate FMP Protocol instance\r
   //\r
-  Fmp = AllocateZeroPool (sizeof (EFI_FIRMWARE_MANAGEMENT_PROTOCOL));\r
-  if (Fmp == NULL) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for FMP Protocol instance.\n"));\r
+  Private = AllocateCopyPool (\r
+              sizeof (mFirmwareManagementPrivateDataTemplate),\r
+              &mFirmwareManagementPrivateDataTemplate\r
+              );\r
+  if (Private == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to allocate memory for private structure.\n", mImageIdName));\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto cleanup;\r
   }\r
 \r
   //\r
-  // Allocate FMP Progress Protocol instance\r
+  // Initialize private context data structure\r
   //\r
-  FmpProgress = AllocateZeroPool (sizeof (EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL));\r
-  if (FmpProgress == NULL) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for FMP Progress Protocol instance.\n"));\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    FreePool (Fmp);\r
+  Private->Handle           = Handle;\r
+  Private->FmpDeviceContext = NULL;\r
+  Status                    = FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
+  if (Status == EFI_UNSUPPORTED) {\r
+    Private->FmpDeviceContext = NULL;\r
+  } else if (EFI_ERROR (Status)) {\r
     goto cleanup;\r
   }\r
 \r
   //\r
-  // Set up FMP Protocol function pointers\r
+  // Make sure the descriptor has already been loaded or refreshed\r
   //\r
-  Fmp->GetImageInfo   = GetTheImageInfo;\r
-  Fmp->GetImage       = GetTheImage;\r
-  Fmp->SetImage       = SetTheImage;\r
-  Fmp->CheckImage     = CheckTheImage;\r
-  Fmp->GetPackageInfo = GetPackageInfo;\r
-  Fmp->SetPackageInfo = SetPackageInfo;\r
+  PopulateDescriptor (Private);\r
 \r
-  //\r
-  // Fill in FMP Progress Protocol fields for Version 1\r
-  //\r
-  FmpProgress->Version                        = 1;\r
-  FmpProgress->ProgressBarForegroundColor.Raw = PcdGet32 (PcdFmpDeviceProgressColor);\r
-  FmpProgress->WatchdogSeconds                = PcdGet8 (PcdFmpDeviceProgressWatchdogTimeInSeconds);\r
+  if (IsLockFmpDeviceAtLockEventGuidRequired ()) {\r
+    //\r
+    // Register all UEFI Variables used by this module to be locked.\r
+    //\r
+    Status = LockAllFmpVariables (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to register variables to lock.  Status = %r.\n", mImageIdName, Status));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "FmpDxe(%s): All variables registered to lock\n", mImageIdName));\r
+    }\r
+\r
+    //\r
+    // Create and register notify function to lock the FMP device.\r
+    //\r
+    Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    FmpDxeLockEventNotify,\r
+                    Private,\r
+                    mLockGuid,\r
+                    &Private->FmpDeviceLockEvent\r
+                    );\r
+    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
+  }\r
 \r
   //\r
   // Install FMP Protocol and FMP Progress Protocol\r
   //\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &Handle,\r
+                  &Private->Handle,\r
                   &gEfiFirmwareManagementProtocolGuid,\r
-                  Fmp,\r
+                  &Private->Fmp,\r
                   &gEdkiiFirmwareManagementProgressProtocolGuid,\r
-                  FmpProgress,\r
+                  &mFmpProgress,\r
                   NULL\r
                   );\r
-\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: FMP Protocol install error. Status = %r.\n", Status));\r
-    FreePool (Fmp);\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Protocol install error. Status = %r.\n", mImageIdName, Status));\r
     goto cleanup;\r
   }\r
 \r
-  DEBUG ((DEBUG_INFO, "FmpDxe: FMP Protocol Installed!\n"));\r
-  mFmpInstalled = TRUE;\r
-\r
 cleanup:\r
 \r
+  if (EFI_ERROR (Status)) {\r
+    if (Private != NULL) {\r
+      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
+\r
   return Status;\r
 }\r
 \r
+/**\r
+  Function to uninstall FMP instance.\r
+\r
+  @param[in]  Handle  The device handle to install a FMP instance on.\r
+\r
+  @retval  EFI_SUCCESS            FMP Installed\r
+  @retval  EFI_INVALID_PARAMETER  Handle was invalid\r
+  @retval  other                  Error installing FMP\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UninstallFmpInstance (\r
+  IN EFI_HANDLE  Handle\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;\r
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Handle,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  (VOID **)&Fmp,\r
+                  NULL,\r
+                  NULL,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Protocol open error. Status = %r.\n", mImageIdName, Status));\r
+    return Status;\r
+  }\r
+\r
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (Fmp);\r
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);\r
+\r
+  if (Private->FmpDeviceLockEvent != NULL) {\r
+    gBS->CloseEvent (Private->FmpDeviceLockEvent);\r
+  }\r
+\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  Private->Handle,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  &Private->Fmp,\r
+                  &gEdkiiFirmwareManagementProgressProtocolGuid,\r
+                  &mFmpProgress,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Protocol uninstall error. Status = %r.\n", mImageIdName, Status));\r
+    return Status;\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
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Unloads the application and its installed protocol.\r
+\r
+  @param ImageHandle       Handle that identifies the image to be unloaded.\r
+  @param  SystemTable      The system table.\r
+\r
+  @retval EFI_SUCCESS      The image has been unloaded.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FmpDxeLibDestructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  if (mFmpSingleInstance) {\r
+    return UninstallFmpInstance (ImageHandle);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Main entry for this driver/library.\r
 \r
@@ -1373,7 +1903,6 @@ FmpDxeEntryPoint (
   )\r
 {\r
   EFI_STATUS  Status;\r
-  EFI_GUID    *LockGuid;\r
 \r
   //\r
   // Verify that a new FILE_GUID value has been provided in the <Defines>\r
@@ -1389,13 +1918,14 @@ 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: FmpDeviceLib 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
 \r
   //\r
@@ -1403,45 +1933,24 @@ FmpDxeEntryPoint (
   //\r
   DetectTestKey ();\r
 \r
-  if (IsLockFmpDeviceAtLockEventGuidRequired ()) {\r
-    //\r
-    // Lock all UEFI Variables used by this module.\r
-    //\r
-    Status = LockAllFmpVariables ();\r
-    if (EFI_ERROR (Status)) {\r
-      DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variables.  Status = %r.\n", Status));\r
-    } else {\r
-      DEBUG ((DEBUG_INFO, "FmpDxe: All variables locked\n"));\r
-    }\r
-\r
-    //\r
-    // Register notify function to lock the FMP device.\r
-    // The lock event GUID is retrieved from PcdFmpDeviceLockEventGuid.\r
-    // If PcdFmpDeviceLockEventGuid is not the size of an EFI_GUID, then\r
-    // gEfiEndOfDxeEventGroupGuid is used.\r
-    //\r
-    LockGuid = &gEfiEndOfDxeEventGroupGuid;\r
-    if (PcdGetSize (PcdFmpDeviceLockEventGuid) == sizeof (EFI_GUID)) {\r
-      LockGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceLockEventGuid);\r
-    }\r
-    DEBUG ((DEBUG_INFO, "FmpDxe: Lock GUID: %g\n", LockGuid));\r
+  //\r
+  // Fill in FMP Progress Protocol fields for Version 1\r
+  //\r
+  mFmpProgress.Version                        = 1;\r
+  mFmpProgress.ProgressBarForegroundColor.Raw = PcdGet32 (PcdFmpDeviceProgressColor);\r
+  mFmpProgress.WatchdogSeconds                = PcdGet8 (PcdFmpDeviceProgressWatchdogTimeInSeconds);\r
 \r
-    Status = gBS->CreateEventEx (\r
-                    EVT_NOTIFY_SIGNAL,\r
-                    TPL_CALLBACK,\r
-                    FmpDxeLockEventNotify,\r
-                    NULL,\r
-                    LockGuid,\r
-                    &mFmpDeviceLockEvent\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to register notification.  Status = %r\n", Status));\r
-    }\r
-    ASSERT_EFI_ERROR (Status);\r
-  } else {\r
-    DEBUG ((DEBUG_VERBOSE, "FmpDxe: Not registering notification to call FmpDeviceLock() because mfg mode\n"));\r
+  // The lock event GUID is retrieved from PcdFmpDeviceLockEventGuid.\r
+  // If PcdFmpDeviceLockEventGuid is not the size of an EFI_GUID, then\r
+  // gEfiEndOfDxeEventGroupGuid is used.\r
+  //\r
+  mLockGuid = &gEfiEndOfDxeEventGroupGuid;\r
+  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
   // Register with library the install function so if the library uses\r
   // UEFI driver model/driver binding protocol it can install FMP on its device handle\r
@@ -1450,15 +1959,27 @@ FmpDxeEntryPoint (
   //\r
   Status = RegisterFmpInstaller (InstallFmpInstance);\r
   if (Status == EFI_UNSUPPORTED) {\r
-    DEBUG ((DEBUG_INFO, "FmpDxe: FmpDeviceLib registration returned EFI_UNSUPPORTED.  Installing single FMP instance.\n"));\r
-    Status = InstallFmpInstance (ImageHandle);\r
+    mFmpSingleInstance = TRUE;\r
+    DEBUG ((DEBUG_INFO, "FmpDxe(%s): FmpDeviceLib registration returned EFI_UNSUPPORTED.  Installing single FMP instance.\n", mImageIdName));\r
+    Status = RegisterFmpUninstaller (UninstallFmpInstance);\r
+    if (Status == EFI_UNSUPPORTED) {\r
+      Status = InstallFmpInstance (ImageHandle);\r
+    } else {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib RegisterFmpInstaller and RegisterFmpUninstaller do not match.\n", mImageIdName));\r
+      Status = EFI_UNSUPPORTED;\r
+    }\r
   } else if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib registration returned %r.  No FMP installed.\n", Status));\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib registration returned %r.  No FMP installed.\n", mImageIdName, Status));\r
   } else {\r
     DEBUG ((\r
       DEBUG_INFO,\r
-      "FmpDxe: FmpDeviceLib registration returned EFI_SUCCESS.  Expect FMP to be installed during the BDS/Device connection phase.\n"\r
+      "FmpDxe(%s): FmpDeviceLib registration returned EFI_SUCCESS.  Expect FMP to be installed during the BDS/Device connection phase.\n",\r
+      mImageIdName\r
       ));\r
+    Status = RegisterFmpUninstaller (UninstallFmpInstance);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib RegisterFmpInstaller and RegisterFmpUninstaller do not match.\n", mImageIdName));\r
+    }\r
   }\r
 \r
   return Status;\r