/** @file\r
- Capsule Library instance to update capsule image to flash.\r
+ Capsule Library instance to process capsule images.\r
\r
- Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
\r
**/\r
#include <PiDxe.h>\r
+\r
#include <Guid/Capsule.h>\r
+#include <Guid/FmpCapsule.h>\r
+\r
#include <Library/DebugLib.h>\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/DxeServicesTableLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/CapsuleLib.h>\r
+#include <Library/GenericBdsLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DevicePathLib.h>\r
+\r
+#include <Protocol/FirmwareManagement.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+\r
+/**\r
+ Function indicate the current completion progress of the firmware\r
+ update. Platform may override with own specific progress function.\r
+\r
+ @param Completion A value between 1 and 100 indicating the current completion progress of the firmware update\r
+\r
+ @retval EFI_SUCESS Input capsule is a correct FMP capsule.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Update_Image_Progress (\r
+ IN UINTN Completion\r
+)\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Validate Fmp capsules layout.\r
+\r
+ @param CapsuleHeader Points to a capsule header.\r
+\r
+ @retval EFI_SUCESS Input capsule is a correct FMP capsule.\r
+ @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.\r
+**/\r
+EFI_STATUS\r
+ValidateFmpCapsule (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
+ UINT8 *EndOfCapsule;\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
+ UINT8 *EndOfPayload;\r
+ UINT64 *ItemOffsetList;\r
+ UINT32 ItemNum;\r
+ UINTN Index;\r
+\r
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
+ EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;\r
+\r
+ if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+\r
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
+\r
+ if (ItemNum == FmpCapsuleHeader->EmbeddedDriverCount) {\r
+ //\r
+ // No payload element \r
+ //\r
+ if (((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]) < EndOfCapsule) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ if (FmpCapsuleHeader->PayloadItemCount != 0) {\r
+ //\r
+ // Check if the last payload is within capsule image range\r
+ //\r
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]);\r
+ EndOfPayload = (UINT8 *)(ImageHeader + 1) + ImageHeader->UpdateImageSize + ImageHeader->UpdateVendorCodeSize;\r
+ } else {\r
+ //\r
+ // No driver & payload element in FMP\r
+ //\r
+ EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);\r
+ }\r
+\r
+ if (EndOfPayload != EndOfCapsule) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // All the address in ItemOffsetList must be stored in ascending order\r
+ //\r
+ if (ItemNum >= 2) {\r
+ for (Index = 0; Index < ItemNum - 1; Index++) {\r
+ if (ItemOffsetList[Index] >= ItemOffsetList[Index + 1]) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Process Firmware management protocol data capsule. \r
+\r
+ @param CapsuleHeader Points to a capsule header.\r
+\r
+ @retval EFI_SUCESS Process Capsule Image successfully.\r
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.\r
+ @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory.\r
+**/\r
+EFI_STATUS\r
+ProcessFmpCapsuleImage (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
+ EFI_HANDLE ImageHandle;\r
+ UINT64 *ItemOffsetList;\r
+ UINT32 ItemNum;\r
+ UINTN Index;\r
+ UINTN ExitDataSize;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
+ UINTN NumberOfHandles;\r
+ UINTN DescriptorSize;\r
+ UINT8 FmpImageInfoCount;\r
+ UINT32 FmpImageInfoDescriptorVer;\r
+ UINTN ImageInfoSize;\r
+ UINT32 PackageVersion;\r
+ CHAR16 *PackageVersionName;\r
+ CHAR16 *AbortReason;\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;\r
+ UINTN DriverLen;\r
+ UINTN Index1;\r
+ UINTN Index2;\r
+ MEMMAP_DEVICE_PATH MemMapNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;\r
+\r
+ Status = EFI_SUCCESS;\r
+ HandleBuffer = NULL;\r
+ ExitDataSize = 0;\r
+ DriverDevicePath = NULL;\r
+\r
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
+\r
+ if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+\r
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
+\r
+ //\r
+ // capsule in which driver count and payload count are both zero is not processed.\r
+ //\r
+ if (ItemNum == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // 1. ConnectAll to ensure \r
+ // All the communication protocol required by driver in capsule installed \r
+ // All FMP protocols are installed\r
+ //\r
+ BdsLibConnectAll();\r
+\r
+\r
+ //\r
+ // 2. Try to load & start all the drivers within capsule \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)CapsuleHeader;\r
+ MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);\r
+\r
+ DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);\r
+ if (DriverDevicePath == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
+ if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {\r
+ //\r
+ // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER\r
+ //\r
+ DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];\r
+ } else {\r
+ DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];\r
+ }\r
+\r
+ Status = gBS->LoadImage(\r
+ FALSE,\r
+ gImageHandle,\r
+ DriverDevicePath,\r
+ (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],\r
+ DriverLen,\r
+ &ImageHandle\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto EXIT;\r
+ }\r
+\r
+ Status = gBS->StartImage(\r
+ ImageHandle, \r
+ &ExitDataSize, \r
+ NULL\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
+ goto EXIT;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Connnect all again to connect drivers within capsule \r
+ //\r
+ if (FmpCapsuleHeader->EmbeddedDriverCount > 0) {\r
+ BdsLibConnectAll();\r
+ }\r
+\r
+ //\r
+ // 3. Route payload to right FMP instance\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ NULL,\r
+ &NumberOfHandles,\r
+ &HandleBuffer\r
+ );\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ for(Index1 = 0; Index1 < NumberOfHandles; Index1++) {\r
+ Status = gBS->HandleProtocol(\r
+ HandleBuffer[Index1],\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 = NULL;\r
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+ if (FmpImageInfoBuf == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto EXIT;\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
+\r
+ //\r
+ // If FMP GetInformation interface failed, skip this resource\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 all the payload entry in capsule payload list \r
+ //\r
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
+ if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) &&\r
+ ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {\r
+ AbortReason = NULL;\r
+ if (ImageHeader->UpdateVendorCodeSize == 0) {\r
+ Status = Fmp->SetImage(\r
+ Fmp,\r
+ TempFmpImageInfo->ImageIndex, // ImageIndex\r
+ (UINT8 *)(ImageHeader + 1), // Image\r
+ ImageHeader->UpdateImageSize, // ImageSize\r
+ NULL, // VendorCode\r
+ Update_Image_Progress, // Progress\r
+ &AbortReason // AbortReason\r
+ );\r
+ } else {\r
+ Status = Fmp->SetImage(\r
+ Fmp,\r
+ TempFmpImageInfo->ImageIndex, // ImageIndex\r
+ (UINT8 *)(ImageHeader + 1), // Image\r
+ ImageHeader->UpdateImageSize, // ImageSize\r
+ (UINT8 *)((UINT8 *) (ImageHeader + 1) + ImageHeader->UpdateImageSize), // VendorCode\r
+ Update_Image_Progress, // Progress\r
+ &AbortReason // AbortReason\r
+ );\r
+ }\r
+ if (AbortReason != NULL) {\r
+ DEBUG ((EFI_D_ERROR, "%s\n", AbortReason));\r
+ FreePool(AbortReason);\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version\r
+ //\r
+ TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);\r
+ }\r
+ FreePool(FmpImageInfoBuf);\r
+ }\r
+ }\r
+\r
+EXIT:\r
+\r
+ if (HandleBuffer != NULL) {\r
+ FreePool(HandleBuffer);\r
+ }\r
+\r
+ if (DriverDevicePath != NULL) {\r
+ FreePool(DriverDevicePath);\r
+ }\r
+\r
+ return Status;\r
+}\r
\r
/**\r
Those capsules supported by the firmwares.\r
\r
@retval EFI_SUCESS Input capsule is supported by firmware.\r
@retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.\r
+ @retval EFI_INVALID_PARAMETER Input capsule layout is not correct\r
**/\r
EFI_STATUS\r
EFIAPI\r
return EFI_SUCCESS;\r
}\r
\r
+ if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {\r
+ //\r
+ // Check layout of FMP capsule\r
+ //\r
+ return ValidateFmpCapsule(CapsuleHeader);\r
+ }\r
+\r
return EFI_UNSUPPORTED;\r
}\r
\r
return EFI_UNSUPPORTED;\r
}\r
\r
+ //\r
+ // Check FMP capsule layout\r
+ //\r
+ if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){\r
+ Status = ValidateFmpCapsule(CapsuleHeader);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Press EFI FMP Capsule\r
+ //\r
+ return ProcessFmpCapsuleImage(CapsuleHeader);\r
+ }\r
+\r
//\r
// Skip the capsule header, move to the Firware Volume\r
//\r
return Status;\r
}\r
\r
+/**\r
+\r
+ This routine is called to process capsules.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.\r
+ If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.\r
+\r
+ This routine should be called twice in BDS.\r
+ 1) The first call must be before EndOfDxe. The system capsules is processed.\r
+ If device capsule FMP protocols are exposted at this time and device FMP\r
+ capsule has zero EmbeddedDriverCount, the device capsules are processed.\r
+ Each individual capsule result is recorded in capsule record variable.\r
+ System may reset in this function, if reset is required by capsule and\r
+ all capsules are processed.\r
+ If not all capsules are processed, reset will be defered to second call.\r
+\r
+ 2) The second call must be after EndOfDxe and after ConnectAll, so that all\r
+ device capsule FMP protocols are exposed.\r
+ The system capsules are skipped. If the device capsules are NOT processed\r
+ in first call, they are processed here.\r
+ Each individual capsule result is recorded in capsule record variable.\r
+ System may reset in this function, if reset is required by capsule\r
+ processed in first call and second call.\r
+\r
+ @retval EFI_SUCCESS There is no error when processing capsules.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ProcessCapsules (\r
+ VOID\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
\r