/** @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 - 2013, 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
+ UINT8 *EndOfCapsule;\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
+ 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
+ //\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)CapsuleHeader;\r
+ MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)((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 == 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 - ItemOffsetList[Index];\r
+ } else {\r
+ DriverLen = ItemOffsetList[Index + 1] - 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
+ &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
--- /dev/null
+/** @file\r
+ Guid & data structure used for Delivering Capsules Containing Updates to Firmware\r
+ Managment Protocol\r
+\r
+ Copyright (c) 2013, 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
+\r
+ @par Revision Reference:\r
+ GUIDs defined in UEFI 2.4 spec.\r
+\r
+**/\r
+\r
+\r
+#ifndef _FMP_CAPSULE_GUID_H__\r
+#define _FMP_CAPSULE_GUID_H__\r
+\r
+//\r
+// This is the GUID of the capsule for Firmware Management Protocol.\r
+//\r
+#define EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID \\r
+ { \\r
+ 0x6dcbd5ed, 0xe82d, 0x4c44, {0xbd, 0xa1, 0x71, 0x94, 0x19, 0x9a, 0xd9, 0x2a } \\r
+ }\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT32 Version;\r
+\r
+ ///\r
+ /// The number of drivers included in the capsule and the number of corresponding\r
+ /// offsets stored in ItemOffsetList array. \r
+ ///\r
+ UINT16 EmbeddedDriverCount;\r
+\r
+ ///\r
+ /// The number of payload items included in the capsule and the number of\r
+ /// corresponding offsets stored in the ItemOffsetList array.\r
+ ///\r
+ UINT16 PayloadItemCount;\r
+\r
+ ///\r
+ /// Variable length array of dimension [EmbeddedDriverCount + PayloadItemCount]\r
+ /// containing offsets of each of the drivers and payload items contained within the capsule\r
+ ///\r
+ // UINT64 ItemOffsetList[];\r
+} EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER;\r
+\r
+typedef struct {\r
+ UINT32 Version;\r
+\r
+ ///\r
+ /// Used to identifiy device firmware targeted by this update. This guid is matched by\r
+ /// system firmware against ImageTypeId field within a EFI_FIRMWARE_IMAGE_DESCRIPTOR\r
+ ///\r
+ EFI_GUID UpdateImageTypeId;\r
+\r
+ ///\r
+ /// Passed as ImageIndex in call to EFI_FIRMWARE_MANAGEMENT_PROTOCOL.SetImage()\r
+ ///\r
+ UINT8 UpdateImageIndex;\r
+ UINT8 reserved_bytes[3];\r
+\r
+ ///\r
+ /// Size of the binary update image which immediately follows this structure\r
+ ///\r
+ UINT32 UpdateImageSize;\r
+\r
+ ///\r
+ ///Size of the VendorCode bytes which optionally immediately follow binary update image in the capsule\r
+ ///\r
+ UINT32 UpdateVendorCodeSize;\r
+} EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER;\r
+\r
+#pragma pack()\r
+\r
+\r
+#define EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION 0x00000001 \r
+#define EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION 0x00000001\r
+\r
+extern EFI_GUID gEfiFmpCapsuleGuid;\r
+\r
+#endif\r