+/**\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
+ 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
+ HandleBuffer = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ ProtocolGuid,\r
+ NULL,\r
+ HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ *HandleCount = 0;\r
+ return NULL;\r
+ }\r
+\r
+ for (Index = 0; Index < *HandleCount; 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[Index] = NULL;\r
+ }\r
+\r
+ FreePool (OriginalFmpImageInfoBuf);\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