]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c
SignedCapsulePkg/Universal: Fix various typos
[mirror_edk2.git] / SignedCapsulePkg / Universal / SystemFirmwareUpdate / SystemFirmwareUpdateDxe.c
index ae783ffe4d17c4b806fd0f51d2c70d7c944c75c0..bdb70bdb32cc1ec8df0984a497ad325ad50fe0f1 100644 (file)
@@ -8,14 +8,8 @@
 \r
   FmpSetImage() will receive untrusted input and do basic validation.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -59,17 +53,23 @@ ParseUpdateDataFile (
   @param[in]  ConfigData              Points to the component configuration structure.\r
   @param[out] LastAttemptVersion      The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
   @param[out] LastAttemptStatus       The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[in]  Progress                A function used by the driver to report the progress of the firmware update.\r
+  @param[in]  StartPercentage         The start completion percentage value that may be used to report progress during the flash write operation.\r
+  @param[in]  EndPercentage           The end completion percentage value that may be used to report progress during the flash write operation.\r
 \r
   @retval EFI_SUCCESS             The System Firmware image is updated.\r
   @retval EFI_WRITE_PROTECTED     The flash device is read only.\r
 **/\r
 EFI_STATUS\r
 PerformUpdate (\r
-  IN VOID                         *SystemFirmwareImage,\r
-  IN UINTN                        SystemFirmwareImageSize,\r
-  IN UPDATE_CONFIG_DATA           *ConfigData,\r
-  OUT UINT32                      *LastAttemptVersion,\r
-  OUT UINT32                      *LastAttemptStatus\r
+  IN VOID                                           *SystemFirmwareImage,\r
+  IN UINTN                                          SystemFirmwareImageSize,\r
+  IN UPDATE_CONFIG_DATA                             *ConfigData,\r
+  OUT UINT32                                        *LastAttemptVersion,\r
+  OUT UINT32                                        *LastAttemptStatus,\r
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,\r
+  IN UINTN                                          StartPercentage,\r
+  IN UINTN                                          EndPercentage\r
   )\r
 {\r
   EFI_STATUS                   Status;\r
@@ -78,13 +78,22 @@ PerformUpdate (
   DEBUG((DEBUG_INFO, "  BaseAddress - 0x%lx,", ConfigData->BaseAddress));\r
   DEBUG((DEBUG_INFO, "  ImageOffset - 0x%x,", ConfigData->ImageOffset));\r
   DEBUG((DEBUG_INFO, "  Legnth - 0x%x\n", ConfigData->Length));\r
-  Status = PerformFlashWrite (\r
+  if (Progress != NULL) {\r
+    Progress (StartPercentage);\r
+  }\r
+  Status = PerformFlashWriteWithProgress (\r
              ConfigData->FirmwareType,\r
              ConfigData->BaseAddress,\r
              ConfigData->AddressType,\r
              (VOID *)((UINTN)SystemFirmwareImage + (UINTN)ConfigData->ImageOffset),\r
-             ConfigData->Length\r
+             ConfigData->Length,\r
+             Progress,\r
+             StartPercentage,\r
+             EndPercentage\r
              );\r
+  if (Progress != NULL) {\r
+    Progress (EndPercentage);\r
+  }\r
   if (!EFI_ERROR(Status)) {\r
     *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
     if (ConfigData->FirmwareType == PlatformFirmwareTypeNvRam) {\r
@@ -105,18 +114,20 @@ PerformUpdate (
   @param[in]  ConfigImageSize         The length of the config file image in bytes.\r
   @param[out] LastAttemptVersion      The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
   @param[out] LastAttemptStatus       The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[in]  Progress                A function used by the driver to report the progress of the firmware update.\r
 \r
   @retval EFI_SUCCESS             The System Firmware image is updated.\r
   @retval EFI_WRITE_PROTECTED     The flash device is read only.\r
 **/\r
 EFI_STATUS\r
 UpdateImage (\r
-  IN VOID                         *SystemFirmwareImage,\r
-  IN UINTN                        SystemFirmwareImageSize,\r
-  IN VOID                         *ConfigImage,\r
-  IN UINTN                        ConfigImageSize,\r
-  OUT UINT32                      *LastAttemptVersion,\r
-  OUT UINT32                      *LastAttemptStatus\r
+  IN VOID                                           *SystemFirmwareImage,\r
+  IN UINTN                                          SystemFirmwareImageSize,\r
+  IN VOID                                           *ConfigImage,\r
+  IN UINTN                                          ConfigImageSize,\r
+  OUT UINT32                                        *LastAttemptVersion,\r
+  OUT UINT32                                        *LastAttemptStatus,\r
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress\r
   )\r
 {\r
   EFI_STATUS                            Status;\r
@@ -124,19 +135,34 @@ UpdateImage (
   UPDATE_CONFIG_DATA                    *UpdateConfigData;\r
   CONFIG_HEADER                         ConfigHeader;\r
   UINTN                                 Index;\r
+  UINTN                                 TotalSize;\r
+  UINTN                                 BytesWritten;\r
+  UINTN                                 StartPercentage;\r
+  UINTN                                 EndPercentage;\r
 \r
   if (ConfigImage == NULL) {\r
     DEBUG((DEBUG_INFO, "PlatformUpdate (NoConfig):"));\r
     DEBUG((DEBUG_INFO, "  BaseAddress - 0x%x,", 0));\r
     DEBUG((DEBUG_INFO, "  Length - 0x%x\n", SystemFirmwareImageSize));\r
     // ASSUME the whole System Firmware include NVRAM region.\r
-    Status = PerformFlashWrite (\r
+    StartPercentage = 0;\r
+    EndPercentage = 100;\r
+    if (Progress != NULL) {\r
+      Progress (StartPercentage);\r
+    }\r
+    Status = PerformFlashWriteWithProgress (\r
                PlatformFirmwareTypeNvRam,\r
                0,\r
                FlashAddressTypeRelativeAddress,\r
                SystemFirmwareImage,\r
-               SystemFirmwareImageSize\r
+               SystemFirmwareImageSize,\r
+               Progress,\r
+               StartPercentage,\r
+               EndPercentage\r
                );\r
+    if (Progress != NULL) {\r
+      Progress (EndPercentage);\r
+    }\r
     if (!EFI_ERROR(Status)) {\r
       *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
       mNvRamUpdated = TRUE;\r
@@ -163,17 +189,30 @@ UpdateImage (
   DEBUG((DEBUG_INFO, "ConfigHeader.NumOfUpdates - 0x%x\n", ConfigHeader.NumOfUpdates));\r
   DEBUG((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid)));\r
 \r
+  TotalSize = 0;\r
+  for (Index = 0; Index < ConfigHeader.NumOfUpdates; Index++) {\r
+    if (CompareGuid(&ConfigData[Index].FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {\r
+      TotalSize = TotalSize + ConfigData[Index].Length;\r
+    }\r
+  }\r
+\r
+  BytesWritten = 0;\r
   Index = 0;\r
   UpdateConfigData = ConfigData;\r
   while (Index < ConfigHeader.NumOfUpdates) {\r
     if (CompareGuid(&UpdateConfigData->FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {\r
       DEBUG((DEBUG_INFO, "FileGuid - %g (processing)\n", &UpdateConfigData->FileGuid));\r
+      StartPercentage = (BytesWritten * 100) / TotalSize;\r
+      EndPercentage   = ((BytesWritten + UpdateConfigData->Length) * 100) / TotalSize;\r
       Status = PerformUpdate (\r
                  SystemFirmwareImage,\r
                  SystemFirmwareImageSize,\r
                  UpdateConfigData,\r
                  LastAttemptVersion,\r
-                 LastAttemptStatus\r
+                 LastAttemptStatus,\r
+                 Progress,\r
+                 StartPercentage,\r
+                 EndPercentage\r
                  );\r
       //\r
       // Shall updates be serialized so that if an update is not successfully completed,\r
@@ -186,6 +225,8 @@ UpdateImage (
       DEBUG((DEBUG_INFO, "FileGuid - %g (ignored)\n", &UpdateConfigData->FileGuid));\r
     }\r
 \r
+    BytesWritten += UpdateConfigData->Length;\r
+\r
     Index++;\r
     UpdateConfigData++;\r
   }\r
@@ -202,6 +243,7 @@ UpdateImage (
   @param[in]  ImageSize          The size of the EDKII system FMP capsule image in bytes.\r
   @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
   @param[out] LastAttemptStatus  The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[in]  Progress           A function used by the driver to report the progress of the firmware update.\r
 \r
   @retval EFI_SUCCESS             EDKII system FMP capsule passes authentication and the System Firmware image is updated.\r
   @retval EFI_SECURITY_VIOLATION  EDKII system FMP capsule fails authentication and the System Firmware image is not updated.\r
@@ -209,10 +251,11 @@ UpdateImage (
 **/\r
 EFI_STATUS\r
 SystemFirmwareAuthenticatedUpdate (\r
-  IN VOID                         *Image,\r
-  IN UINTN                        ImageSize,\r
-  OUT UINT32                      *LastAttemptVersion,\r
-  OUT UINT32                      *LastAttemptStatus\r
+  IN VOID                                           *Image,\r
+  IN UINTN                                          ImageSize,\r
+  OUT UINT32                                        *LastAttemptVersion,\r
+  OUT UINT32                                        *LastAttemptStatus,\r
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress\r
   )\r
 {\r
   EFI_STATUS                  Status;\r
@@ -223,6 +266,9 @@ SystemFirmwareAuthenticatedUpdate (
   VOID                        *AuthenticatedImage;\r
   UINTN                       AuthenticatedImageSize;\r
 \r
+  AuthenticatedImage     = NULL;\r
+  AuthenticatedImageSize = 0;\r
+\r
   DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate...\n"));\r
 \r
   Status = CapsuleAuthenticateSystemFirmware(Image, ImageSize, FALSE, LastAttemptVersion, LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);\r
@@ -237,7 +283,7 @@ SystemFirmwareAuthenticatedUpdate (
   ExtractConfigImage(AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);\r
 \r
   DEBUG((DEBUG_INFO, "UpdateImage ...\n"));\r
-  Status = UpdateImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize, LastAttemptVersion, LastAttemptStatus);\r
+  Status = UpdateImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize, LastAttemptVersion, LastAttemptStatus, Progress);\r
   if (EFI_ERROR(Status)) {\r
     DEBUG((DEBUG_INFO, "UpdateImage - %r\n", Status));\r
     return Status;\r
@@ -409,7 +455,7 @@ QueryVariableInfoHook (
   @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_VIOLATIO  The operation could not be performed due to an authentication failure.\r
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -439,15 +485,15 @@ FmpSetImage (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  Status = SystemFirmwareAuthenticatedUpdate((VOID *)Image, ImageSize, &SystemFmpPrivate->LastAttempt.LastAttemptVersion, &SystemFmpPrivate->LastAttempt.LastAttemptStatus);\r
-  DEBUG((DEBUG_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n", SystemFmpPrivate->LastAttempt.LastAttemptVersion, SystemFmpPrivate->LastAttempt.LastAttemptStatus));\r
+  Status = SystemFirmwareAuthenticatedUpdate((VOID *)Image, ImageSize, &SystemFmpPrivate->LastAttempt.LastAttemptVersion, &SystemFmpPrivate->LastAttempt.LastAttemptStatus, Progress);\r
+  DEBUG((DEBUG_INFO, "SetImage - LastAttempt Version - 0x%x, State - 0x%x\n", SystemFmpPrivate->LastAttempt.LastAttemptVersion, SystemFmpPrivate->LastAttempt.LastAttemptStatus));\r
 \r
   //\r
   // If NVRAM is updated, we should no longer touch variable services, because\r
   // the current variable driver may not manage the new NVRAM region.\r
   //\r
   if (mNvRamUpdated) {\r
-    DEBUG ((DEBUG_INFO, "NvRamUpdated, Update Variable Serivces\n"));\r
+    DEBUG ((DEBUG_INFO, "NvRamUpdated, Update Variable Services\n"));\r
     gRT->GetVariable         = GetVariableHook;\r
     gRT->GetNextVariableName = GetNextVariableNameHook;\r
     gRT->SetVariable         = SetVariableHook;\r
@@ -468,59 +514,371 @@ FmpSetImage (
                      sizeof(SystemFmpPrivate->LastAttempt),\r
                      &SystemFmpPrivate->LastAttempt\r
                      );\r
-  DEBUG((DEBUG_INFO, "SetLastAttemp - %r\n", VarStatus));\r
+  DEBUG((DEBUG_INFO, "SetLastAttempt - %r\n", VarStatus));\r
 \r
   return Status;\r
 }\r
 \r
+/**\r
+  Get the set of EFI_FIRMWARE_IMAGE_DESCRIPTOR structures from an FMP Protocol.\r
+\r
+  @param[in]  Handle             Handle with an FMP Protocol or a System FMP\r
+                                 Protocol.\r
+  @param[in]  ProtocolGuid       Pointer to the FMP Protocol GUID or System FMP\r
+                                 Protocol GUID.\r
+  @param[out] FmpImageInfoCount  Pointer to the number of\r
+                                 EFI_FIRMWARE_IMAGE_DESCRIPTOR structures.\r
+  @param[out] DescriptorSize     Pointer to the size, in bytes, of each\r
+                                 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure.\r
+\r
+  @return NULL   No EFI_FIRMWARE_IMAGE_DESCRIPTOR structures found.\r
+  @return !NULL  Pointer to a buffer of EFI_FIRMWARE_IMAGE_DESCRIPTOR structures\r
+                 allocated using AllocatePool().  Caller must free buffer with\r
+                 FreePool().\r
+**/\r
+EFI_FIRMWARE_IMAGE_DESCRIPTOR *\r
+GetFmpImageDescriptors (\r
+  IN  EFI_HANDLE  Handle,\r
+  IN  EFI_GUID    *ProtocolGuid,\r
+  OUT UINT8       *FmpImageInfoCount,\r
+  OUT UINTN       *DescriptorSize\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;\r
+  UINTN                             ImageInfoSize;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR     *FmpImageInfoBuf;\r
+  UINT32                            FmpImageInfoDescriptorVer;\r
+  UINT32                            PackageVersion;\r
+  CHAR16                            *PackageVersionName;\r
+\r
+  *FmpImageInfoCount = 0;\r
+  *DescriptorSize    = 0;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  ProtocolGuid,\r
+                  (VOID **)&Fmp\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Determine the size required for the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.\r
+  //\r
+  ImageInfoSize = 0;\r
+  Status = Fmp->GetImageInfo (\r
+                  Fmp,                         // FMP Pointer\r
+                  &ImageInfoSize,              // Buffer Size (in this case 0)\r
+                  NULL,                        // NULL so we can get size\r
+                  &FmpImageInfoDescriptorVer,  // DescriptorVersion\r
+                  FmpImageInfoCount,           // DescriptorCount\r
+                  DescriptorSize,              // DescriptorSize\r
+                  &PackageVersion,             // PackageVersion\r
+                  &PackageVersionName          // PackageVersionName\r
+                  );\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Unexpected Failure.  Status = %r\n", Status));\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer for the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.\r
+  //\r
+  FmpImageInfoBuf = NULL;\r
+  FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+  if (FmpImageInfoBuf == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failed to allocate memory for descriptors.\n"));\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Retrieve the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.\r
+  //\r
+  PackageVersionName = NULL;\r
+  Status = Fmp->GetImageInfo (\r
+                  Fmp,\r
+                  &ImageInfoSize,              // ImageInfoSize\r
+                  FmpImageInfoBuf,             // ImageInfo\r
+                  &FmpImageInfoDescriptorVer,  // DescriptorVersion\r
+                  FmpImageInfoCount,           // DescriptorCount\r
+                  DescriptorSize,              // DescriptorSize\r
+                  &PackageVersion,             // PackageVersion\r
+                  &PackageVersionName          // PackageVersionName\r
+                  );\r
+\r
+  //\r
+  // Free unused PackageVersionName return buffer\r
+  //\r
+  if (PackageVersionName != NULL) {\r
+    FreePool (PackageVersionName);\r
+    PackageVersionName = NULL;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failure in GetImageInfo.  Status = %r\n", Status));\r
+    if (FmpImageInfoBuf != NULL) {\r
+      FreePool (FmpImageInfoBuf);\r
+    }\r
+    return NULL;\r
+  }\r
+\r
+  return FmpImageInfoBuf;\r
+}\r
+\r
+/**\r
+  Search for handles with an FMP protocol whose EFI_FIRMWARE_IMAGE_DESCRIPTOR\r
+  ImageTypeId matches the ImageTypeId produced by this module.\r
+\r
+  @param[in]  ProtocolGuid  Pointer to the GUID of the protocol to search.\r
+  @param[out] HandleCount   Pointer to the number of returned handles.\r
+\r
+  @return NULL   No matching handles found.\r
+  @return !NULL  Pointer to a buffer of handles allocated using AllocatePool().\r
+                 Caller must free buffer with FreePool().\r
+**/\r
+EFI_HANDLE *\r
+FindMatchingFmpHandles (\r
+  IN  EFI_GUID  *ProtocolGuid,\r
+  OUT UINTN     *HandleCount\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINTN                          TempHandleCount;\r
+  EFI_HANDLE                     *HandleBuffer;\r
+  UINTN                          Index;\r
+  UINTN                          Index2;\r
+  UINTN                          Index3;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR  *OriginalFmpImageInfoBuf;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR  *FmpImageInfoBuf;\r
+  UINT8                          FmpImageInfoCount;\r
+  UINTN                          DescriptorSize;\r
+  BOOLEAN                        MatchFound;\r
+\r
+  *HandleCount  = 0;\r
+  TempHandleCount = 0;\r
+  HandleBuffer = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                   ByProtocol,\r
+                   ProtocolGuid,\r
+                   NULL,\r
+                   &TempHandleCount,\r
+                   &HandleBuffer\r
+                   );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  for (Index = 0; Index < TempHandleCount; Index++) {\r
+    OriginalFmpImageInfoBuf = GetFmpImageDescriptors (\r
+                                HandleBuffer[Index],\r
+                                ProtocolGuid,\r
+                                &FmpImageInfoCount,\r
+                                &DescriptorSize\r
+                                );\r
+\r
+    //\r
+    // Loop through the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.\r
+    //\r
+    FmpImageInfoBuf = OriginalFmpImageInfoBuf;\r
+    MatchFound = FALSE;\r
+    for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {\r
+      for (Index3 = 0; Index3 < mSystemFmpPrivate->DescriptorCount; Index3++) {\r
+        MatchFound = CompareGuid (\r
+                       &FmpImageInfoBuf->ImageTypeId,\r
+                       &mSystemFmpPrivate->ImageDescriptor[Index3].ImageTypeId\r
+                       );\r
+        if (MatchFound) {\r
+          break;\r
+        }\r
+      }\r
+      if (MatchFound) {\r
+        break;\r
+      }\r
+      //\r
+      // Increment the buffer pointer ahead by the size of the descriptor\r
+      //\r
+      FmpImageInfoBuf = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)(((UINT8 *)FmpImageInfoBuf) + DescriptorSize);\r
+    }\r
+    if (MatchFound) {\r
+      HandleBuffer[*HandleCount] = HandleBuffer[Index];\r
+      (*HandleCount)++;\r
+    }\r
+\r
+    FreePool (OriginalFmpImageInfoBuf);\r
+  }\r
+\r
+  if ((*HandleCount) == 0) {\r
+    //\r
+    // No any matching handle.\r
+    //\r
+    FreePool (HandleBuffer);\r
+    return NULL;\r
+  }\r
+  return HandleBuffer;\r
+}\r
+\r
+/**\r
+  Uninstall System FMP Protocol instances that may have been installed by\r
+  SystemFirmwareUpdateDxe drivers dispatches by other capsules.\r
+\r
+  @retval EFI_SUCCESS  All System FMP Protocols found were uninstalled.\r
+  @return Other        One or more System FMP Protocols could not be uninstalled.\r
+\r
+**/\r
+EFI_STATUS\r
+UninstallMatchingSystemFmpProtocols (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             HandleCount;\r
+  UINTN                             Index;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *SystemFmp;\r
+\r
+  //\r
+  // Uninstall SystemFmpProtocol instances that may have been produced by\r
+  // the SystemFirmwareUpdate drivers in FVs dispatched by other capsules.\r
+  //\r
+  HandleBuffer = FindMatchingFmpHandles (\r
+                   &gSystemFmpProtocolGuid,\r
+                   &HandleCount\r
+                   );\r
+  DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Found %d matching System FMP instances\n", HandleCount));\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol(\r
+                    HandleBuffer[Index],\r
+                    &gSystemFmpProtocolGuid,\r
+                    (VOID **)&SystemFmp\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+    DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Uninstall SystemFmp produced by another capsule\n"));\r
+    Status = gBS->UninstallProtocolInterface (\r
+                    HandleBuffer[Index],\r
+                    &gSystemFmpProtocolGuid,\r
+                    SystemFmp\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failed to uninstall SystemFmp %r.  Exiting.\n", Status));\r
+      FreePool (HandleBuffer);\r
+      return Status;\r
+    }\r
+  }\r
+  if (HandleBuffer != NULL) {\r
+    FreePool (HandleBuffer);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   System FMP module entrypoint\r
 \r
-  @param  ImageHandle       The firmware allocated handle for the EFI image.\r
-  @param  SystemTable       A pointer to the EFI System Table.\r
+  @param[in] ImageHandle  The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable  A pointer to the EFI System Table.\r
 \r
-  @return EFI_SUCCESS System FMP module is initialized.\r
+  @retval EFI_SUCCESS           System FMP module is initialized.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources avaulable to\r
+                                initialize this module.\r
+  @retval Other                 System FMP Protocols could not be uninstalled.\r
+  @retval Other                 System FMP Protocol could not be installed.\r
+  @retval Other                 FMP Protocol could not be installed.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 SystemFirmwareUpdateMainDxe (\r
-  IN EFI_HANDLE                         ImageHandle,\r
-  IN EFI_SYSTEM_TABLE                   *SystemTable\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
-  EFI_STATUS                                      Status;\r
+  EFI_STATUS  Status;\r
+  EFI_HANDLE  *HandleBuffer;\r
+  UINTN       HandleCount;\r
 \r
   //\r
   // Initialize SystemFmpPrivateData\r
   //\r
-  mSystemFmpPrivate = AllocateZeroPool (sizeof(SYSTEM_FMP_PRIVATE_DATA));\r
+  mSystemFmpPrivate = AllocateZeroPool (sizeof (SYSTEM_FMP_PRIVATE_DATA));\r
   if (mSystemFmpPrivate == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  Status = InitializePrivateData(mSystemFmpPrivate);\r
-  if (EFI_ERROR(Status)) {\r
-    FreePool(mSystemFmpPrivate);\r
+  Status = InitializePrivateData (mSystemFmpPrivate);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (mSystemFmpPrivate);\r
     mSystemFmpPrivate = NULL;\r
     return Status;\r
   }\r
 \r
   //\r
-  // Install FMP protocol.\r
+  // Uninstall SystemFmpProtocol instances that may have been produced by\r
+  // the SystemFirmwareUpdate drivers in FVs dispatched by other capsules.\r
   //\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &mSystemFmpPrivate->Handle,\r
-                  &gEfiFirmwareManagementProtocolGuid,\r
-                  &mSystemFmpPrivate->Fmp,\r
-                  &gSystemFmpProtocolGuid,\r
-                  &mSystemFmpPrivate->Fmp,\r
-                  NULL\r
-                  );\r
+  Status = UninstallMatchingSystemFmpProtocols ();\r
   if (EFI_ERROR (Status)) {\r
-    FreePool(mSystemFmpPrivate);\r
+    FreePool (mSystemFmpPrivate);\r
     mSystemFmpPrivate = NULL;\r
     return Status;\r
   }\r
 \r
+  //\r
+  // Look for a handle with matching Firmware Management Protocol\r
+  //\r
+  HandleCount = 0;\r
+  HandleBuffer = FindMatchingFmpHandles (\r
+                   &gEfiFirmwareManagementProtocolGuid,\r
+                   &HandleCount\r
+                   );\r
+  DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Found %d matching FMP instances\n", HandleCount));\r
+\r
+  switch (HandleCount) {\r
+  case 0:\r
+    //\r
+    // Install FMP protocol onto a new handle.\r
+    //\r
+    DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Install FMP onto a new handle\n"));\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &mSystemFmpPrivate->Handle,\r
+                    &gEfiFirmwareManagementProtocolGuid,\r
+                    &mSystemFmpPrivate->Fmp,\r
+                    NULL\r
+                    );\r
+    break;\r
+  case 1:\r
+    //\r
+    // Install System FMP protocol onto handle with matching FMP Protocol\r
+    //\r
+    DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Install System FMP onto matching FMP handle\n"));\r
+    mSystemFmpPrivate->Handle = HandleBuffer[0];\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &HandleBuffer[0],\r
+                    &gSystemFmpProtocolGuid,\r
+                    &mSystemFmpPrivate->Fmp,\r
+                    NULL\r
+                    );\r
+    break;\r
+  default:\r
+    //\r
+    // More than one matching handle is not expected.  Unload driver.\r
+    //\r
+    DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: More than one matching FMP handle.  Unload driver.\n"));\r
+    Status = EFI_DEVICE_ERROR;\r
+    break;\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool (HandleBuffer);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (mSystemFmpPrivate);\r
+    mSystemFmpPrivate = NULL;\r
+  }\r
+\r
   return Status;\r
 }\r