+++ /dev/null
-/** @file\r
- Capsule Library instance to process capsule images.\r
-\r
- Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\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
- @param CapsuleHeader Points to a capsule header.\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
-SupportCapsuleImage (\r
- IN EFI_CAPSULE_HEADER *CapsuleHeader\r
- )\r
-{\r
- if (CompareGuid (&gEfiCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {\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
-/**\r
- The firmware implements to process the capsule image.\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
-EFIAPI\r
-ProcessCapsuleImage (\r
- IN EFI_CAPSULE_HEADER *CapsuleHeader\r
- )\r
-{\r
- UINT32 Length;\r
- EFI_FIRMWARE_VOLUME_HEADER *FvImage;\r
- EFI_FIRMWARE_VOLUME_HEADER *ProcessedFvImage;\r
- EFI_STATUS Status;\r
- EFI_HANDLE FvProtocolHandle;\r
- UINT32 FvAlignment;\r
-\r
- FvImage = NULL;\r
- ProcessedFvImage = NULL;\r
- Status = EFI_SUCCESS;\r
-\r
- if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {\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
- FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
- Length = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;\r
-\r
- while (Length != 0) {\r
- //\r
- // Point to the next firmware volume header, and then\r
- // call the DXE service to process it.\r
- //\r
- if (FvImage->FvLength > (UINTN) Length) {\r
- //\r
- // Notes: need to stuff this status somewhere so that the\r
- // error can be detected at OS runtime\r
- //\r
- Status = EFI_VOLUME_CORRUPTED;\r
- break;\r
- }\r
-\r
- FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16);\r
- //\r
- // FvAlignment must be more than 8 bytes required by FvHeader structure.\r
- //\r
- if (FvAlignment < 8) {\r
- FvAlignment = 8;\r
- }\r
- //\r
- // Check FvImage Align is required.\r
- //\r
- if (((UINTN) FvImage % FvAlignment) == 0) {\r
- ProcessedFvImage = FvImage;\r
- } else {\r
- //\r
- // Allocate new aligned buffer to store FvImage.\r
- //\r
- ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment);\r
- if (ProcessedFvImage == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- break;\r
- }\r
- CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength);\r
- }\r
-\r
- Status = gDS->ProcessFirmwareVolume (\r
- (VOID *) ProcessedFvImage,\r
- (UINTN) ProcessedFvImage->FvLength,\r
- &FvProtocolHandle\r
- );\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- //\r
- // Call the dispatcher to dispatch any drivers from the produced firmware volume\r
- //\r
- gDS->Dispatch ();\r
- //\r
- // On to the next FV in the capsule\r
- //\r
- Length -= (UINT32) FvImage->FvLength;\r
- FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength);\r
- }\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