+/**\r
+ Dump all FMP information.\r
+**/\r
+VOID\r
+DumpAllFmpInfo (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN NumberOfHandles;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
+ UINTN Index;\r
+ UINTN ImageInfoSize;\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
+ UINT32 FmpImageInfoDescriptorVer;\r
+ UINT8 FmpImageInfoCount;\r
+ UINTN DescriptorSize;\r
+ UINT32 PackageVersion;\r
+ CHAR16 *PackageVersionName;\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ NULL,\r
+ &NumberOfHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return ;\r
+ }\r
+\r
+ for (Index = 0; Index < NumberOfHandles; Index++) {\r
+ Status = gBS->HandleProtocol(\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ (VOID **)&Fmp\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+\r
+ ImageInfoSize = 0;\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ continue;\r
+ }\r
+\r
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+ if (FmpImageInfoBuf == NULL) {\r
+ continue;\r
+ }\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
+ if (EFI_ERROR(Status)) {\r
+ FreePool(FmpImageInfoBuf);\r
+ continue;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));\r
+ DumpFmpImageInfo(\r
+ ImageInfoSize, // ImageInfoSize\r
+ FmpImageInfoBuf, // ImageInfo\r
+ FmpImageInfoDescriptorVer, // DescriptorVersion\r
+ FmpImageInfoCount, // DescriptorCount\r
+ DescriptorSize, // DescriptorSize\r
+ PackageVersion, // PackageVersion\r
+ PackageVersionName // PackageVersionName\r
+ );\r
+\r
+ if (PackageVersionName != NULL) {\r
+ FreePool(PackageVersionName);\r
+ }\r
+\r
+ FreePool(FmpImageInfoBuf);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Get FMP handle by ImageTypeId and HardwareInstance.\r
+\r
+ @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.\r
+ @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.\r
+ @param[in,out] NoHandles The number of handles returned in Buffer.\r
+ @param[out] Buffer[out] A pointer to the buffer to return the requested array of handles.\r
+\r
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of\r
+ handles in Buffer was returned in NoHandles.\r
+ @retval EFI_NOT_FOUND No handles match the search.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.\r
+**/\r
+EFI_STATUS\r
+GetFmpHandleBufferByType (\r
+ IN EFI_GUID *UpdateImageTypeId,\r
+ IN UINT64 UpdateHardwareInstance,\r
+ IN OUT UINTN *NoHandles,\r
+ OUT EFI_HANDLE **Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN NumberOfHandles;\r
+ EFI_HANDLE *MatchedHandleBuffer;\r
+ UINTN MatchedNumberOfHandles;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
+ UINTN Index;\r
+ UINTN ImageInfoSize;\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
+ UINT32 FmpImageInfoDescriptorVer;\r
+ UINT8 FmpImageInfoCount;\r
+ UINTN DescriptorSize;\r
+ UINT32 PackageVersion;\r
+ CHAR16 *PackageVersionName;\r
+ UINTN Index2;\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;\r
+\r
+ *NoHandles = 0;\r
+ *Buffer = NULL;\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ NULL,\r
+ &NumberOfHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ MatchedNumberOfHandles = 0;\r
+ MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);\r
+ if (MatchedHandleBuffer == NULL) {\r
+ FreePool (HandleBuffer);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for (Index = 0; Index < NumberOfHandles; Index++) {\r
+ Status = gBS->HandleProtocol(\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ (VOID **)&Fmp\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+\r
+ ImageInfoSize = 0;\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ continue;\r
+ }\r
+\r
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+ if (FmpImageInfoBuf == NULL) {\r
+ continue;\r
+ }\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
+ if (EFI_ERROR(Status)) {\r
+ FreePool(FmpImageInfoBuf);\r
+ continue;\r
+ }\r
+\r
+ if (PackageVersionName != NULL) {\r
+ FreePool(PackageVersionName);\r
+ }\r
+\r
+ TempFmpImageInfo = FmpImageInfoBuf;\r
+ for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {\r
+ //\r
+ // Check if this FMP instance matches\r
+ //\r
+ if (CompareGuid(UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {\r
+ if ((UpdateHardwareInstance == 0) ||\r
+ ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&\r
+ (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance))) {\r
+ MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];\r
+ MatchedNumberOfHandles++;\r
+ break;\r
+ }\r
+ }\r
+ TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);\r
+ }\r
+ FreePool(FmpImageInfoBuf);\r
+ }\r
+\r
+ if (MatchedNumberOfHandles == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *NoHandles = MatchedNumberOfHandles;\r
+ *Buffer = MatchedHandleBuffer;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Return FmpImageInfoDescriptorVer by an FMP handle.\r
+\r
+ @param[in] Handle A FMP handle.\r
+\r
+ @return FmpImageInfoDescriptorVer associated with the FMP.\r
+**/\r
+UINT32\r
+GetFmpImageInfoDescriptorVer (\r
+ IN EFI_HANDLE Handle\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
+ UINT8 FmpImageInfoCount;\r
+ UINTN DescriptorSize;\r
+ UINT32 PackageVersion;\r
+ CHAR16 *PackageVersionName;\r
+\r
+ Status = gBS->HandleProtocol(\r
+ Handle,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ (VOID **)&Fmp\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return 0;\r
+ }\r
+\r
+ ImageInfoSize = 0;\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return 0;\r
+ }\r
+\r
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+ if (FmpImageInfoBuf == NULL) {\r
+ return 0;\r
+ }\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
+ if (EFI_ERROR(Status)) {\r
+ FreePool(FmpImageInfoBuf);\r
+ return 0;\r
+ }\r
+ return FmpImageInfoDescriptorVer;\r
+}\r
+\r
+/**\r
+ Set FMP image data.\r
+\r
+ @param[in] Handle A FMP handle.\r
+ @param[in] ImageHeader The payload image header.\r
+ @param[in] PayloadIndex The index of the payload.\r
+\r
+ @return The status of FMP->SetImage.\r
+**/\r
+EFI_STATUS\r
+SetFmpImageData (\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
+ IN UINTN PayloadIndex\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
+ UINT8 *Image;\r
+ VOID *VendorCode;\r
+ CHAR16 *AbortReason;\r
+\r
+ Status = gBS->HandleProtocol(\r
+ Handle,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ (VOID **)&Fmp\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+ Image = (UINT8 *)(ImageHeader + 1);\r
+ } else {\r
+ //\r
+ // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,\r
+ // Header should exclude UpdateHardwareInstance field\r
+ //\r
+ Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
+ }\r
+\r
+ if (ImageHeader->UpdateVendorCodeSize == 0) {\r
+ VendorCode = NULL;\r
+ } else {\r
+ VendorCode = Image + ImageHeader->UpdateImageSize;\r
+ }\r
+ AbortReason = NULL;\r
+ DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n"));\r
+ DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));\r
+ DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));\r
+ DEBUG((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));\r
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+ DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));\r
+ }\r
+ DEBUG((DEBUG_INFO, "\n"));\r
+ Status = Fmp->SetImage(\r
+ Fmp,\r
+ ImageHeader->UpdateImageIndex, // ImageIndex\r
+ Image, // Image\r
+ ImageHeader->UpdateImageSize, // ImageSize\r
+ VendorCode, // VendorCode\r
+ Update_Image_Progress, // Progress\r
+ &AbortReason // AbortReason\r
+ );\r
+ DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));\r
+ if (AbortReason != NULL) {\r
+ DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));\r
+ FreePool(AbortReason);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Start a UEFI image in the FMP payload.\r
+\r
+ @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..\r
+ @param[in] ImageSize The size in bytes of ImageBuffer.\r
+\r
+ @return The status of gBS->LoadImage and gBS->StartImage.\r
+**/\r
+EFI_STATUS\r
+StartFmpImage (\r
+ IN VOID *ImageBuffer,\r
+ IN UINTN ImageSize\r
+ )\r
+{\r
+ MEMMAP_DEVICE_PATH MemMapNode;\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE ImageHandle;\r
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;\r
+ UINTN ExitDataSize;\r
+\r
+ SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));\r
+ MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;\r
+ MemMapNode.Header.SubType = HW_MEMMAP_DP;\r
+ MemMapNode.MemoryType = EfiBootServicesCode;\r
+ MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;\r
+ MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);\r
+\r
+ DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);\r
+ if (DriverDevicePath == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));\r
+ Status = gBS->LoadImage(\r
+ FALSE,\r
+ gImageHandle,\r
+ DriverDevicePath,\r
+ ImageBuffer,\r
+ ImageSize,\r
+ &ImageHandle\r
+ );\r
+ DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(DriverDevicePath);\r
+ return Status;\r
+ }\r
+\r
+ DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));\r
+ Status = gBS->StartImage(\r
+ ImageHandle,\r
+ &ExitDataSize,\r
+ NULL\r
+ );\r
+ DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
+ }\r
+\r
+ FreePool(DriverDevicePath);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Record FMP capsule status.\r
+\r
+ @param[in] Handle A FMP handle.\r
+ @param[in] CapsuleHeader The capsule image header\r
+ @param[in] CapsuleStatus The capsule process stauts\r
+ @param[in] PayloadIndex FMP payload index\r
+ @param[in] ImageHeader FMP image header\r
+**/\r
+VOID\r
+RecordFmpCapsuleStatus (\r
+ IN EFI_HANDLE Handle, OPTIONAL\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN EFI_STATUS CapsuleStatus,\r
+ IN UINTN PayloadIndex,\r
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;\r
+ UINT32 FmpImageInfoDescriptorVer;\r
+ EFI_STATUS StatusEsrt;\r
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;\r
+ EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;\r
+\r
+ FmpDevicePath = NULL;\r
+ if (Handle != NULL) {\r
+ gBS->HandleProtocol(\r
+ Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **)&FmpDevicePath\r
+ );\r
+ }\r
+\r
+ RecordFmpCapsuleStatusVariable (\r
+ CapsuleHeader,\r
+ CapsuleStatus,\r
+ PayloadIndex,\r
+ ImageHeader,\r
+ FmpDevicePath\r
+ );\r
+\r
+ //\r
+ // Update corresponding ESRT entry LastAttemp Status\r
+ //\r
+ Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+\r
+ if (Handle == NULL) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Update EsrtEntry For V1, V2 FMP instance.\r
+ // V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface\r
+ //\r
+ FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);\r
+ if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {\r
+ StatusEsrt = EsrtProtocol->GetEsrtEntry(&ImageHeader->UpdateImageTypeId, &EsrtEntry);\r
+ if (!EFI_ERROR(StatusEsrt)){\r
+ if (!EFI_ERROR(CapsuleStatus)) {\r
+ EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+ } else {\r
+ EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+ }\r
+ EsrtEntry.LastAttemptVersion = 0;\r
+ EsrtProtocol->UpdateEsrtEntry(&EsrtEntry);\r
+ }\r
+ }\r
+}\r
+\r