This instance handles Microsoft UX capsule, UEFI defined FMP capsule.
This instance should not assume any capsule image format.
Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Chao Zhang <chao.b.zhang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
--- /dev/null
+/** @file\r
+ DXE capsule library.\r
+\r
+ Caution: This module requires additional review when modified.\r
+ This module will have external input - capsule image.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),\r
+ ValidateFmpCapsule(), DisplayCapsuleImage(), ConvertBmpToGopBlt() will\r
+ receive untrusted input and do basic validation.\r
+\r
+ Copyright (c) 2016, 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
+**/\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <IndustryStandard/Bmp.h>\r
+#include <IndustryStandard/WindowsUxCapsule.h>\r
+\r
+#include <Guid/FmpCapsule.h>\r
+#include <Guid/SystemResourceTable.h>\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/CapsuleLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <Protocol/GraphicsOutput.h>\r
+#include <Protocol/EsrtManagement.h>\r
+#include <Protocol/FirmwareManagement.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+BOOLEAN mAreAllImagesProcessed;\r
+\r
+EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;\r
+BOOLEAN mIsVirtualAddrConverted = FALSE;\r
+BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;\r
+\r
+/**\r
+ Initialize capsule related variables.\r
+**/\r
+VOID\r
+InitCapsuleVariable (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Check if this FMP capsule is processed.\r
+\r
+ @param[in] CapsuleHeader The capsule image header\r
+ @param[in] PayloadIndex FMP payload index\r
+ @param[in] ImageHeader FMP image header\r
+\r
+ @retval TRUE This FMP capsule is processed.\r
+ @retval FALSE This FMP capsule is not processed.\r
+**/\r
+BOOLEAN\r
+IsFmpCapsuleProcessed (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN UINTN PayloadIndex,\r
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader\r
+ );\r
+\r
+/**\r
+ Record capsule status variable.\r
+\r
+ @param[in] CapsuleHeader The capsule image header\r
+ @param[in] CapsuleStatus The capsule process stauts\r
+\r
+ @retval EFI_SUCCESS The capsule status variable is recorded.\r
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
+**/\r
+EFI_STATUS\r
+RecordCapsuleStatusVariable (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN EFI_STATUS CapsuleStatus\r
+ );\r
+\r
+/**\r
+ Record FMP capsule status variable.\r
+\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
+ @retval EFI_SUCCESS The capsule status variable is recorded.\r
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
+**/\r
+EFI_STATUS\r
+RecordFmpCapsuleStatusVariable (\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
+/**\r
+ Function indicate the current completion progress of the firmware\r
+ update. Platform may override with own specific progress function.\r
+\r
+ @param[in] 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
+ Return if this CapsuleGuid is a FMP capsule GUID or not.\r
+\r
+ @param[in] CapsuleGuid A pointer to EFI_GUID\r
+\r
+ @retval TRUE It is a FMP capsule GUID.\r
+ @retval FALSE It is not a FMP capsule GUID.\r
+**/\r
+BOOLEAN\r
+IsFmpCapsuleGuid (\r
+ IN EFI_GUID *CapsuleGuid\r
+ )\r
+{\r
+ if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Validate if it is valid capsule header\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ This function assumes the caller provided correct CapsuleHeader pointer\r
+ and CapsuleSize.\r
+\r
+ This function validates the fields in EFI_CAPSULE_HEADER.\r
+\r
+ @param[in] CapsuleHeader Points to a capsule header.\r
+ @param[in] CapsuleSize Size of the whole capsule image.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidCapsuleHeader (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN UINT64 CapsuleSize\r
+ )\r
+{\r
+ if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {\r
+ return FALSE;\r
+ }\r
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {\r
+ return FALSE;\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Validate Fmp capsules layout.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ This function assumes the caller validated the capsule by using\r
+ IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.\r
+ The capsule buffer size is CapsuleHeader->CapsuleImageSize.\r
+\r
+ This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\r
+ and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.\r
+\r
+ This function need support nested FMP capsule.\r
+\r
+ @param[in] CapsuleHeader Points to a capsule header.\r
+ @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.\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
+ OUT UINT16 *EmbeddedDriverCount OPTIONAL\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
+ UINTN FmpCapsuleSize;\r
+ UINTN FmpCapsuleHeaderSize;\r
+ UINT64 FmpImageSize;\r
+ UINTN FmpImageHeaderSize;\r
+\r
+ if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
+ return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);\r
+ }\r
+\r
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {\r
+ DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
+ EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;\r
+ FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;\r
+\r
+ if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {\r
+ DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\r
+ if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r
+ DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+\r
+ // No overflow\r
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
+\r
+ if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {\r
+ DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;\r
+\r
+ // Check ItemOffsetList\r
+ for (Index = 0; Index < ItemNum; Index++) {\r
+ if (ItemOffsetList[Index] >= FmpCapsuleSize) {\r
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {\r
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // All the address in ItemOffsetList must be stored in ascending order\r
+ //\r
+ if (Index > 0) {\r
+ if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {\r
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\r
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
+ if (Index == ItemNum - 1) {\r
+ EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);\r
+ } else {\r
+ EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];\r
+ }\r
+ FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];\r
+\r
+ if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {\r
+ DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);\r
+ if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||\r
+ (ImageHeader->Version < 1)) {\r
+ DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+ FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
+ }\r
+\r
+ // No overflow\r
+ if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {\r
+ DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ if (ItemNum == 0) {\r
+ //\r
+ // No driver & payload element in FMP\r
+ //\r
+ EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);\r
+ if (EndOfPayload != EndOfCapsule) {\r
+ DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (EmbeddedDriverCount != NULL) {\r
+ *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer\r
+ is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt\r
+ buffer is passed in it will be used if it is big enough.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ @param[in] BmpImage Pointer to BMP file\r
+ @param[in] BmpImageSize Number of bytes in BmpImage\r
+ @param[in, out] GopBlt Buffer containing GOP version of BmpImage.\r
+ @param[in, out] GopBltSize Size of GopBlt in bytes.\r
+ @param[out] PixelHeight Height of GopBlt/BmpImage in pixels\r
+ @param[out] PixelWidth Width of GopBlt/BmpImage in pixels\r
+\r
+ @retval EFI_SUCCESS GopBlt and GopBltSize are returned.\r
+ @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image\r
+ @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough.\r
+ GopBltSize will contain the required size.\r
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ConvertBmpToGopBlt (\r
+ IN VOID *BmpImage,\r
+ IN UINTN BmpImageSize,\r
+ IN OUT VOID **GopBlt,\r
+ IN OUT UINTN *GopBltSize,\r
+ OUT UINTN *PixelHeight,\r
+ OUT UINTN *PixelWidth\r
+ )\r
+{\r
+ UINT8 *Image;\r
+ UINT8 *ImageHeader;\r
+ BMP_IMAGE_HEADER *BmpHeader;\r
+ BMP_COLOR_MAP *BmpColorMap;\r
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;\r
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
+ UINT64 BltBufferSize;\r
+ UINTN Index;\r
+ UINTN Height;\r
+ UINTN Width;\r
+ UINTN ImageIndex;\r
+ UINT32 DataSizePerLine;\r
+ BOOLEAN IsAllocated;\r
+ UINT32 ColorMapNum;\r
+\r
+ if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;\r
+\r
+ if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Doesn't support compress.\r
+ //\r
+ if (BmpHeader->CompressionType != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Only support BITMAPINFOHEADER format.\r
+ // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER\r
+ //\r
+ if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // The data size in each line must be 4 byte alignment.\r
+ //\r
+ DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);\r
+ BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);\r
+ if (BltBufferSize > (UINT32) ~0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((BmpHeader->Size != BmpImageSize) ||\r
+ (BmpHeader->Size < BmpHeader->ImageOffset) ||\r
+ (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Calculate Color Map offset in the image.\r
+ //\r
+ Image = BmpImage;\r
+ BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));\r
+ if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {\r
+ switch (BmpHeader->BitPerPixel) {\r
+ case 1:\r
+ ColorMapNum = 2;\r
+ break;\r
+ case 4:\r
+ ColorMapNum = 16;\r
+ break;\r
+ case 8:\r
+ ColorMapNum = 256;\r
+ break;\r
+ default:\r
+ ColorMapNum = 0;\r
+ break;\r
+ }\r
+ //\r
+ // BMP file may has padding data between the bmp header section and the bmp data section.\r
+ //\r
+ if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Calculate graphics image data address in the image\r
+ //\r
+ Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;\r
+ ImageHeader = Image;\r
+\r
+ //\r
+ // Calculate the BltBuffer needed size.\r
+ //\r
+ BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);\r
+ //\r
+ // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow\r
+ //\r
+ if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+\r
+ IsAllocated = FALSE;\r
+ if (*GopBlt == NULL) {\r
+ //\r
+ // GopBlt is not allocated by caller.\r
+ //\r
+ *GopBltSize = (UINTN) BltBufferSize;\r
+ *GopBlt = AllocatePool (*GopBltSize);\r
+ IsAllocated = TRUE;\r
+ if (*GopBlt == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ //\r
+ // GopBlt has been allocated by caller.\r
+ //\r
+ if (*GopBltSize < (UINTN) BltBufferSize) {\r
+ *GopBltSize = (UINTN) BltBufferSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ }\r
+\r
+ *PixelWidth = BmpHeader->PixelWidth;\r
+ *PixelHeight = BmpHeader->PixelHeight;\r
+\r
+ //\r
+ // Convert image from BMP to Blt buffer format\r
+ //\r
+ BltBuffer = *GopBlt;\r
+ for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {\r
+ Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];\r
+ for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {\r
+ switch (BmpHeader->BitPerPixel) {\r
+ case 1:\r
+ //\r
+ // Convert 1-bit (2 colors) BMP to 24-bit color\r
+ //\r
+ for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {\r
+ Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;\r
+ Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;\r
+ Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;\r
+ Blt++;\r
+ Width++;\r
+ }\r
+\r
+ Blt--;\r
+ Width--;\r
+ break;\r
+\r
+ case 4:\r
+ //\r
+ // Convert 4-bit (16 colors) BMP Palette to 24-bit color\r
+ //\r
+ Index = (*Image) >> 4;\r
+ Blt->Red = BmpColorMap[Index].Red;\r
+ Blt->Green = BmpColorMap[Index].Green;\r
+ Blt->Blue = BmpColorMap[Index].Blue;\r
+ if (Width < (BmpHeader->PixelWidth - 1)) {\r
+ Blt++;\r
+ Width++;\r
+ Index = (*Image) & 0x0f;\r
+ Blt->Red = BmpColorMap[Index].Red;\r
+ Blt->Green = BmpColorMap[Index].Green;\r
+ Blt->Blue = BmpColorMap[Index].Blue;\r
+ }\r
+ break;\r
+\r
+ case 8:\r
+ //\r
+ // Convert 8-bit (256 colors) BMP Palette to 24-bit color\r
+ //\r
+ Blt->Red = BmpColorMap[*Image].Red;\r
+ Blt->Green = BmpColorMap[*Image].Green;\r
+ Blt->Blue = BmpColorMap[*Image].Blue;\r
+ break;\r
+\r
+ case 24:\r
+ //\r
+ // It is 24-bit BMP.\r
+ //\r
+ Blt->Blue = *Image++;\r
+ Blt->Green = *Image++;\r
+ Blt->Red = *Image;\r
+ break;\r
+\r
+ case 32:\r
+ //\r
+ // it is 32-bit BMP. Skip pixel's highest byte\r
+ //\r
+ Blt->Blue = *Image++;\r
+ Blt->Green = *Image++;\r
+ Blt->Red = *Image++;\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Other bit format BMP is not supported.\r
+ //\r
+ if (IsAllocated) {\r
+ FreePool (*GopBlt);\r
+ *GopBlt = NULL;\r
+ }\r
+ return EFI_UNSUPPORTED;\r
+ };\r
+\r
+ }\r
+\r
+ ImageIndex = (UINTN) (Image - ImageHeader);\r
+ if ((ImageIndex % 4) != 0) {\r
+ //\r
+ // Bmp Image starts each row on a 32-bit boundary!\r
+ //\r
+ Image = Image + (4 - (ImageIndex % 4));\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Those capsules supported by the firmwares.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ @param[in] 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
+**/\r
+EFI_STATUS\r
+DisplayCapsuleImage (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ DISPLAY_DISPLAY_PAYLOAD *ImagePayload;\r
+ UINTN PayloadSize;\r
+ EFI_STATUS Status;\r
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
+ UINTN BltSize;\r
+ UINTN Height;\r
+ UINTN Width;\r
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
+\r
+ ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1);\r
+ PayloadSize = (UINTN)(CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER));\r
+\r
+ if (ImagePayload->Version != 1) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ if (CalculateCheckSum8((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Only Support Bitmap by now\r
+ //\r
+ if (ImagePayload->ImageType != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Try to open GOP\r
+ //\r
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);\r
+ if (EFI_ERROR(Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Blt = NULL;\r
+ Width = 0;\r
+ Height = 0;\r
+ Status = ConvertBmpToGopBlt (\r
+ ImagePayload + 1,\r
+ PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),\r
+ (VOID **)&Blt,\r
+ &BltSize,\r
+ &Height,\r
+ &Width\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = GraphicsOutput->Blt (\r
+ GraphicsOutput,\r
+ Blt,\r
+ EfiBltBufferToVideo,\r
+ 0,\r
+ 0,\r
+ (UINTN) ImagePayload->OffsetX,\r
+ (UINTN) ImagePayload->OffsetY,\r
+ Width,\r
+ Height,\r
+ Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
+ );\r
+\r
+ FreePool(Blt);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Dump FMP information.\r
+\r
+ @param[in] ImageInfoSize The size of ImageInfo, in bytes.\r
+ @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.\r
+ @param[in] PackageVersion The version of package.\r
+ @param[in] PackageVersionName The version name of package.\r
+**/\r
+VOID\r
+DumpFmpImageInfo (\r
+ IN UINTN ImageInfoSize,\r
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,\r
+ IN UINT32 DescriptorVersion,\r
+ IN UINT8 DescriptorCount,\r
+ IN UINTN DescriptorSize,\r
+ IN UINT32 PackageVersion,\r
+ IN CHAR16 *PackageVersionName\r
+ )\r
+{\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;\r
+ UINTN Index;\r
+\r
+ DEBUG((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));\r
+ DEBUG((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));\r
+ DEBUG((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));\r
+ DEBUG((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));\r
+ DEBUG((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));\r
+ CurrentImageInfo = ImageInfo;\r
+ for (Index = 0; Index < DescriptorCount; Index++) {\r
+ DEBUG((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));\r
+ DEBUG((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));\r
+ DEBUG((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));\r
+ DEBUG((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));\r
+ DEBUG((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));\r
+ DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));\r
+ DEBUG((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));\r
+ DEBUG((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));\r
+ DEBUG((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));\r
+ DEBUG((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));\r
+ DEBUG((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));\r
+ if (DescriptorVersion > 1) {\r
+ DEBUG((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));\r
+ if (DescriptorVersion > 2) {\r
+ DEBUG((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));\r
+ DEBUG((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));\r
+ DEBUG((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance));\r
+ }\r
+ }\r
+ //\r
+ // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version\r
+ //\r
+ CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);\r
+ }\r
+}\r
+\r
+/**\r
+ Dump a non-nested FMP capsule.\r
+\r
+ @param[in] CapsuleHeader A pointer to CapsuleHeader\r
+**/\r
+VOID\r
+DumpFmpCapsule (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
+ UINTN Index;\r
+ UINT64 *ItemOffsetList;\r
+\r
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
+\r
+ DEBUG((DEBUG_VERBOSE, "FmpCapsule:\n"));\r
+ DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));\r
+ DEBUG((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));\r
+ DEBUG((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));\r
+\r
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+ for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
+ DEBUG((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));\r
+ }\r
+ for (; Index < (UINTN)(FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount); Index++) {\r
+ DEBUG((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));\r
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
+\r
+ DEBUG((DEBUG_VERBOSE, " ImageHeader:\n"));\r
+ DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));\r
+ DEBUG((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));\r
+ DEBUG((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));\r
+ DEBUG((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));\r
+ DEBUG((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));\r
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+ DEBUG((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Process Firmware management protocol data capsule.\r
+\r
+ This function assumes the caller validated the capsule by using\r
+ ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.\r
+\r
+ This function need support nested FMP capsule.\r
+\r
+ @param[in] CapsuleHeader Points to a capsule header.\r
+ @param[in] AreAllImagesProcessed If all the FMP images in the capsule are processed.\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
+ OUT BOOLEAN *AreAllImagesProcessed\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS StatusEsrt;\r
+ EFI_STATUS StatusRet;\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
+ UINT8 *Image;\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
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;\r
+ EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;\r
+ VOID *VendorCode;\r
+\r
+ if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
+ return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), AreAllImagesProcessed);\r
+ }\r
+\r
+ ASSERT(AreAllImagesProcessed != NULL);\r
+\r
+ Status = EFI_SUCCESS;\r
+ StatusRet = EFI_NOT_FOUND;\r
+ HandleBuffer = NULL;\r
+ ExitDataSize = 0;\r
+ DriverDevicePath = NULL;\r
+ EsrtProtocol = NULL;\r
+ *AreAllImagesProcessed = FALSE;\r
+\r
+ DumpFmpCapsule(CapsuleHeader);\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
+ *AreAllImagesProcessed = TRUE;\r
+ return EFI_SUCCESS;\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
+ EsrtProtocol = NULL;\r
+ }\r
+\r
+ //\r
+ // 1. 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
+ DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));\r
+ Status = gBS->LoadImage(\r
+ FALSE,\r
+ gImageHandle,\r
+ DriverDevicePath,\r
+ (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],\r
+ DriverLen,\r
+ &ImageHandle\r
+ );\r
+ DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));\r
+ if (EFI_ERROR(Status)) {\r
+ StatusRet = Status;\r
+ goto EXIT;\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
+ StatusRet = Status;\r
+ goto EXIT;\r
+ }\r
+ }\r
+\r
+ //\r
+ // 2. Route payload to right FMP instance\r
+ //\r
+ DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));\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
+ StatusRet = 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
+ 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
+ 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
+\r
+ if (IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) {\r
+ DEBUG((DEBUG_INFO, "FMP Capsule already processed (%g):", CapsuleHeader));\r
+ DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", ImageHeader->UpdateImageTypeId));\r
+ DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ImageIndex - 0x%x\n", Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader->UpdateImageIndex));\r
+ continue;\r
+ }\r
+\r
+ if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) &&\r
+ ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {\r
+ AbortReason = NULL;\r
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+ if(ImageHeader->UpdateHardwareInstance != 0){\r
+ //\r
+ // FMP Version is >=2 & UpdateHardwareInstance Skip 2 case\r
+ // 1. FMP Image info Version < 3\r
+ // 2. HardwareInstance doesn't match\r
+ //\r
+ if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION ||\r
+ ImageHeader->UpdateHardwareInstance != TempFmpImageInfo->HardwareInstance) {\r
+ continue;\r
+ }\r
+ }\r
+ Image = (UINT8 *)(ImageHeader + 1);\r
+ } else {\r
+ //\r
+ // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.\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
+ DEBUG((DEBUG_INFO, "Fmp->SetImage ...\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
+ RecordFmpCapsuleStatusVariable(\r
+ CapsuleHeader, // CapsuleGuid\r
+ Status, // CapsuleStatus\r
+ Index - FmpCapsuleHeader->EmbeddedDriverCount, // PayloadIndex\r
+ ImageHeader // ImageHeader\r
+ );\r
+ if (StatusRet != EFI_SUCCESS) {\r
+ StatusRet = Status;\r
+ }\r
+ //\r
+ // Update EsrtEntry For V1, V2 FMP instance. V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface\r
+ //\r
+ if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION && EsrtProtocol != NULL) {\r
+ StatusEsrt = EsrtProtocol->GetEsrtEntry(&TempFmpImageInfo->ImageTypeId, &EsrtEntry);\r
+ if (!EFI_ERROR(StatusEsrt)){\r
+ if (!EFI_ERROR(Status)) {\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
+ //\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
+ //\r
+ // final check for AreAllImagesProcessed\r
+ //\r
+ *AreAllImagesProcessed = TRUE;\r
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
+\r
+ if (!IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) {\r
+ *AreAllImagesProcessed = FALSE;\r
+ break;\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 StatusRet;\r
+}\r
+\r
+/**\r
+ Return if there is a FMP header below capsule header.\r
+\r
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
+\r
+ @retval TRUE There is a FMP header below capsule header.\r
+ @retval FALSE There is not a FMP header below capsule header\r
+**/\r
+BOOLEAN\r
+IsNestedFmpCapsule (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
+ UINTN Index;\r
+ BOOLEAN EsrtGuidFound;\r
+ EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
+ UINTN NestedCapsuleSize;\r
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;\r
+ EFI_SYSTEM_RESOURCE_ENTRY Entry;\r
+\r
+ EsrtGuidFound = FALSE;\r
+\r
+ //\r
+ // Check ESRT protocol\r
+ //\r
+ Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);\r
+ if (!EFI_ERROR(Status)) {\r
+ EsrtGuidFound = TRUE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check ESRT configuration table\r
+ //\r
+ if (!EsrtGuidFound) {\r
+ Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
+ if (!EFI_ERROR(Status)) {\r
+ ASSERT (Esrt != NULL);\r
+ EsrtEntry = (VOID *)(Esrt + 1);\r
+ for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
+ if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {\r
+ EsrtGuidFound = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (!EsrtGuidFound) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check nested capsule header\r
+ // FMP GUID after ESRT one\r
+ //\r
+ NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
+ NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;\r
+ if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {\r
+ return FALSE;\r
+ }\r
+ if (!IsValidCapsuleHeader(NestedCapsuleHeader, NestedCapsuleSize)) {\r
+ return FALSE;\r
+ }\r
+ if (!IsFmpCapsuleGuid(&NestedCapsuleHeader->CapsuleGuid)) {\r
+ return FALSE;\r
+ }\r
+ DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.\r
+\r
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
+\r
+ @retval TRUE It is a system FMP.\r
+ @retval FALSE It is a device FMP.\r
+**/\r
+BOOLEAN\r
+IsFmpCapsule (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
+ return TRUE;\r
+ }\r
+ if (IsNestedFmpCapsule(CapsuleHeader)) {\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Those capsules supported by the firmwares.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ @param[in] 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
+ //\r
+ // check Display Capsule Guid\r
+ //\r
+ if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (IsFmpCapsule(CapsuleHeader)) {\r
+ //\r
+ // Check layout of FMP capsule\r
+ //\r
+ return ValidateFmpCapsule(CapsuleHeader, NULL);\r
+ }\r
+ DEBUG((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ The firmware implements to process the capsule image.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ @param[in] 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
+ EFI_STATUS Status;\r
+ BOOLEAN AreAllImagesProcessed;\r
+\r
+ if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Display image in firmware update display capsule\r
+ //\r
+ if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {\r
+ DEBUG((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));\r
+ Status = DisplayCapsuleImage(CapsuleHeader);\r
+ RecordCapsuleStatusVariable(CapsuleHeader, Status);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check FMP capsule layout\r
+ //\r
+ if (IsFmpCapsule (CapsuleHeader)) {\r
+ DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));\r
+ DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));\r
+ Status = ValidateFmpCapsule(CapsuleHeader, NULL);\r
+ DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Press EFI FMP Capsule\r
+ //\r
+ DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));\r
+ Status = ProcessFmpCapsuleImage(CapsuleHeader, &AreAllImagesProcessed);\r
+ DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));\r
+\r
+ if (!AreAllImagesProcessed) {\r
+ mAreAllImagesProcessed = FALSE;\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Callback function executed when the EndOfDxe event group is signaled.\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context The pointer to the notification function's context, which\r
+ is implementation-dependent.\r
+**/\r
+VOID\r
+EFIAPI\r
+DxeCapsuleLibEndOfDxe (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ mDxeCapsuleLibEndOfDxe = TRUE;\r
+}\r
+\r
+/**\r
+ The constructor function.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The constructor successfully .\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeCapsuleLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_EVENT EndOfDxeEvent;\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ DxeCapsuleLibEndOfDxe,\r
+ NULL,\r
+ &gEfiEndOfDxeEventGroupGuid,\r
+ &EndOfDxeEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ InitCapsuleVariable();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+## @file\r
+# Capsule library instance for DXE_DRIVER.\r
+#\r
+# Capsule library instance for DXE_DRIVER module types.\r
+#\r
+# Copyright (c) 2016, 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
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = DxeCapsuleLib\r
+ MODULE_UNI_FILE = DxeCapsuleLib.uni\r
+ FILE_GUID = 534E35DE-8EB3-47b3-A4E0-72A571E50733\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = CapsuleLib|DXE_DRIVER UEFI_APPLICATION\r
+ CONSTRUCTOR = DxeCapsuleLibConstructor\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ DxeCapsuleLib.c\r
+ DxeCapsuleProcessLib.c\r
+ DxeCapsuleReportLib.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ MemoryAllocationLib\r
+ DxeServicesTableLib\r
+ UefiBootServicesTableLib\r
+ DevicePathLib\r
+ ReportStatusCodeLib\r
+ PrintLib\r
+ HobLib\r
+\r
+[Pcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES\r
+\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem ## CONSUMES\r
+\r
+[Protocols]\r
+ gEsrtManagementProtocolGuid ## CONSUMES\r
+ gEfiFirmwareManagementProtocolGuid ## SOMETIMES_CONSUMES\r
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES\r
+\r
+[Guids]\r
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID\r
+ gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID\r
+ gEfiSystemResourceTableGuid ## SOMETIMES_CONSUMES ## GUID\r
+ gEfiCapsuleReportGuid ## CONSUMES ## Variable\r
+ gEfiCapsuleVendorGuid ## CONSUMES ## Variable\r
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event\r
+\r
+[Depex]\r
+ gEfiVariableWriteArchProtocolGuid\r
--- /dev/null
+// /** @file\r
+// Capsule library instance for DXE_DRIVER.\r
+//\r
+// Capsule library instance for DXE_DRIVER module types.\r
+//\r
+// Copyright (c) 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
+// 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
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_DRIVER module types."\r
+\r
--- /dev/null
+/** @file\r
+ DXE capsule process.\r
+\r
+ Caution: This module requires additional review when modified.\r
+ This module will have external input - capsule image.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ ProcessCapsules(), ProcessTheseCapsules() will receive untrusted\r
+ input and do basic validation.\r
+\r
+ Copyright (c) 2016, 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
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/EsrtManagement.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/CapsuleLib.h>\r
+\r
+#include <IndustryStandard/WindowsUxCapsule.h>\r
+\r
+/**\r
+ Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.\r
+\r
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
+\r
+ @retval TRUE It is a system FMP.\r
+ @retval FALSE It is a device FMP.\r
+**/\r
+BOOLEAN\r
+IsFmpCapsule (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ );\r
+\r
+/**\r
+ Validate Fmp capsules layout.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ This function assumes the caller validated the capsule by using\r
+ IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.\r
+ The capsule buffer size is CapsuleHeader->CapsuleImageSize.\r
+\r
+ This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\r
+ and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.\r
+\r
+ This function need support nested FMP capsule.\r
+\r
+ @param[in] CapsuleHeader Points to a capsule header.\r
+ @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.\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
+ OUT UINT16 *EmbeddedDriverCount OPTIONAL\r
+ );\r
+\r
+/**\r
+ Validate if it is valid capsule header\r
+\r
+ This function assumes the caller provided correct CapsuleHeader pointer\r
+ and CapsuleSize.\r
+\r
+ This function validates the fields in EFI_CAPSULE_HEADER.\r
+\r
+ @param[in] CapsuleHeader Points to a capsule header.\r
+ @param[in] CapsuleSize Size of the whole capsule image.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidCapsuleHeader (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN UINT64 CapsuleSize\r
+ );\r
+\r
+extern BOOLEAN mDxeCapsuleLibEndOfDxe;\r
+extern BOOLEAN mAreAllImagesProcessed;\r
+BOOLEAN mNeedReset;\r
+\r
+/**\r
+\r
+ This routine is called to process capsules.\r
+\r
+ Caution: This function may receive untrusted input.\r
+\r
+ Each individual capsule result is recorded in capsule record variable.\r
+\r
+ @param[in] NeedBlockDriver TRUE: Need skip the FMP capsules with non zero EmbeddedDriverCount.\r
+ FALSE: No need to skip any FMP capsules.\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
+ProcessTheseCapsules (\r
+ IN BOOLEAN NeedBlockDriver\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PEI_HOB_POINTERS HobPointer;\r
+ EFI_CAPSULE_HEADER *CapsuleHeader;\r
+ UINT32 Size;\r
+ UINT32 CapsuleNumber;\r
+ UINT32 CapsuleTotalNumber;\r
+ EFI_CAPSULE_TABLE *CapsuleTable;\r
+ UINT32 Index;\r
+ UINT32 CacheIndex;\r
+ UINT32 CacheNumber;\r
+ VOID **CapsulePtr;\r
+ VOID **CapsulePtrCache;\r
+ EFI_GUID *CapsuleGuidCache;\r
+ EFI_STATUS *CapsuleStatusArray;\r
+ BOOLEAN DisplayCapsuleExist;\r
+ ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
+ UINT16 EmbeddedDriverCount;\r
+\r
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));\r
+\r
+ CapsuleNumber = 0;\r
+ CapsuleTotalNumber = 0;\r
+ CacheIndex = 0;\r
+ CacheNumber = 0;\r
+ CapsulePtr = NULL;\r
+ CapsulePtrCache = NULL;\r
+ CapsuleGuidCache = NULL;\r
+ DisplayCapsuleExist = FALSE;\r
+ EsrtManagement = NULL;\r
+\r
+ Status = EFI_SUCCESS;\r
+ //\r
+ // Find all capsule images from hob\r
+ //\r
+ HobPointer.Raw = GetHobList ();\r
+ while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {\r
+ if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {\r
+ HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid\r
+ } else {\r
+ CapsuleTotalNumber++;\r
+ }\r
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
+ }\r
+\r
+ if (CapsuleTotalNumber == 0) {\r
+ //\r
+ // We didn't find a hob, so had no errors.\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Init temp Capsule Data table.\r
+ //\r
+ CapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);\r
+ ASSERT (CapsulePtr != NULL);\r
+ if (CapsulePtr == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);\r
+ ASSERT (CapsulePtrCache != NULL);\r
+ if (CapsulePtrCache == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber);\r
+ ASSERT (CapsuleGuidCache != NULL);\r
+ if (CapsuleGuidCache == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ CapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * CapsuleTotalNumber);\r
+ ASSERT (CapsuleStatusArray != NULL);\r
+ if (CapsuleStatusArray == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Find all capsule images from hob\r
+ //\r
+ HobPointer.Raw = GetHobList ();\r
+ while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {\r
+ CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;\r
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
+ }\r
+\r
+ //\r
+ // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install\r
+ // capsuleTable to configure table with EFI_CAPSULE_GUID\r
+ //\r
+\r
+ //\r
+ // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating\r
+ // System to have information persist across a system reset. EFI System Table must\r
+ // point to an array of capsules that contains the same CapsuleGuid value. And agents\r
+ // searching for this type capsule will look in EFI System Table and search for the\r
+ // capsule's Guid and associated pointer to retrieve the data. Two steps below describes\r
+ // how to sorting the capsules by the unique guid and install the array to EFI System Table.\r
+ // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an\r
+ // array for later sorting capsules by CapsuleGuid.\r
+ //\r
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
+ CapsuleStatusArray [Index] = EFI_UNSUPPORTED;\r
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
+ //\r
+ // For each capsule, we compare it with known CapsuleGuid in the CacheArray.\r
+ // If already has the Guid, skip it. Whereas, record it in the CacheArray as\r
+ // an additional one.\r
+ //\r
+ CacheIndex = 0;\r
+ while (CacheIndex < CacheNumber) {\r
+ if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) {\r
+ break;\r
+ }\r
+ CacheIndex++;\r
+ }\r
+ if (CacheIndex == CacheNumber) {\r
+ CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID));\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules\r
+ // whose guid is the same as it, and malloc memory for an array which preceding\r
+ // with UINT32. The array fills with entry point of capsules that have the same\r
+ // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install\r
+ // this array into EFI System Table, so that agents searching for this type capsule\r
+ // will look in EFI System Table and search for the capsule's Guid and associated\r
+ // pointer to retrieve the data.\r
+ //\r
+ CacheIndex = 0;\r
+ while (CacheIndex < CacheNumber) {\r
+ CapsuleNumber = 0;\r
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
+ if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {\r
+ //\r
+ // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.\r
+ //\r
+ CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;\r
+ //\r
+ // When a Capsule is listed in CapsulePtrCache, it will be reported in ConfigurationTable\r
+ // So, report the CapsuleStatus as "processed successfully".\r
+ //\r
+ CapsuleStatusArray [Index] = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ if (CapsuleNumber != 0) {\r
+ Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);\r
+ CapsuleTable = AllocateRuntimePool (Size);\r
+ ASSERT (CapsuleTable != NULL);\r
+ if (CapsuleTable == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CapsuleTable->CapsuleArrayNumber = CapsuleNumber;\r
+ CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));\r
+ Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ CacheIndex++;\r
+ }\r
+\r
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdatingFirmware)));\r
+\r
+ //\r
+ // If Windows UX capsule exist, process it first\r
+ //\r
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+ if (CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) {\r
+ DEBUG ((DEBUG_INFO, "ProcessCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));\r
+ DisplayCapsuleExist = TRUE;\r
+ DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));\r
+ Status = ProcessCapsuleImage (CapsuleHeader);\r
+ DEBUG((DEBUG_INFO, "ProcessCapsuleImage (Ux) - %r\n", Status));\r
+ CapsuleStatusArray [Index] = Status;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!DisplayCapsuleExist) {\r
+ //\r
+ // Display Capsule not found. Display the default string.\r
+ //\r
+ Print (L"Updating the firmware ......\r\n");\r
+ }\r
+\r
+ //\r
+ // All capsules left are recognized by platform.\r
+ //\r
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+ if (!CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) {\r
+ //\r
+ // Call capsule library to process capsule image.\r
+ //\r
+ EmbeddedDriverCount = 0;\r
+ if (IsFmpCapsule(CapsuleHeader)) {\r
+ Status = ValidateFmpCapsule(CapsuleHeader, &EmbeddedDriverCount);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if ((!NeedBlockDriver) || (EmbeddedDriverCount == 0)) {\r
+ DEBUG((DEBUG_INFO, "ProcessCapsuleImage - 0x%x\n", CapsuleHeader));\r
+ Status = ProcessCapsuleImage (CapsuleHeader);\r
+ CapsuleStatusArray [Index] = Status;\r
+ DEBUG((DEBUG_INFO, "ProcessCapsuleImage - %r\n", Status));\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));\r
+ DEBUG ((DEBUG_ERROR, "Capsule process failed. reset the system!\n"));\r
+ Print (L"Firmware update failed...\r\n");\r
+ } else {\r
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));\r
+ }\r
+\r
+ if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||\r
+ IsFmpCapsule(CapsuleHeader)) {\r
+ mNeedReset = TRUE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);\r
+ //\r
+ // Always sync ESRT Cache from FMP Instance\r
+ //\r
+ if (!EFI_ERROR(Status)) {\r
+ EsrtManagement->SyncEsrtFmp();\r
+ }\r
+ Status = EFI_SUCCESS;\r
+\r
+Done:\r
+ //\r
+ // Free the allocated temp memory space.\r
+ //\r
+ if (CapsuleGuidCache != NULL) {\r
+ FreePool(CapsuleGuidCache);\r
+ }\r
+ if (CapsulePtrCache != NULL) {\r
+ FreePool(CapsulePtrCache);\r
+ }\r
+ if (CapsulePtr != NULL) {\r
+ FreePool(CapsulePtr);\r
+ }\r
+\r
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Do reset system.\r
+**/\r
+VOID\r
+DoResetSystem (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeResettingSystem)));\r
+\r
+ Print(L"Capsule Request Cold Reboot.\n");\r
+ DEBUG((DEBUG_INFO, "Capsule Request Cold Reboot."));\r
+\r
+ for (Index = 5; Index > 0; Index--) {\r
+ Print(L"\rResetting system in %d seconds ...", Index);\r
+ DEBUG((DEBUG_INFO, "\rResetting system in %d seconds ...", Index));\r
+ gBS->Stall(1000000);\r
+ }\r
+\r
+ gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);\r
+\r
+ CpuDeadLoop();\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
+ EFI_STATUS Status;\r
+\r
+ if (!mDxeCapsuleLibEndOfDxe) {\r
+ //\r
+ // Initialize mAreAllImagesProcessed to be TRUE.\r
+ //\r
+ // It will be updated to FALSE in ProcessTheseCapsules()->ProcessCapsuleImage(),\r
+ // if there is any FMP image in any FMP capsule not processed.\r
+ //\r
+ mAreAllImagesProcessed = TRUE;\r
+\r
+ Status = ProcessTheseCapsules(TRUE);\r
+ //\r
+ // Reboot System if and only if all capsule processed.\r
+ // If not, defer reset to 2nd process.\r
+ //\r
+ if (mNeedReset && mAreAllImagesProcessed) {\r
+ DoResetSystem();\r
+ }\r
+ } else {\r
+ Status = ProcessTheseCapsules(FALSE);\r
+ //\r
+ // Reboot System if required after all capsule processed\r
+ //\r
+ if (mNeedReset) {\r
+ DoResetSystem();\r
+ }\r
+ }\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ DXE capsule process.\r
+ Dummy function for runtime module, because CapsuleDxeRuntime\r
+ does not need call ProcessCapsules().\r
+\r
+ Copyright (c) 2016, 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
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/CapsuleLib.h>\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
--- /dev/null
+/** @file\r
+ DXE capsule report related function.\r
+\r
+ Copyright (c) 2016, 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
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/FirmwareManagement.h>\r
+#include <Protocol/VariableLock.h>\r
+#include <Guid/CapsuleReport.h>\r
+#include <Guid/FmpCapsule.h>\r
+#include <Guid/CapsuleVendor.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/CapsuleLib.h>\r
+\r
+#include <IndustryStandard/WindowsUxCapsule.h>\r
+\r
+typedef struct {\r
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultHeader;\r
+ EFI_CAPSULE_RESULT_VARIABLE_FMP CapsuleResultFmp;\r
+} CAPSULE_RESULT_VARIABLE_CACHE;\r
+\r
+#define CAPSULE_RESULT_VARIABLE_CACHE_COUNT 0x10\r
+\r
+CAPSULE_RESULT_VARIABLE_CACHE *mCapsuleResultVariableCache;\r
+UINTN mCapsuleResultVariableCacheMaxCount;\r
+UINTN mCapsuleResultVariableCacheCount;\r
+\r
+/**\r
+ Get current capsule last variable index.\r
+\r
+ @return Current capsule last variable index.\r
+ @retval -1 No current capsule last variable.\r
+**/\r
+INTN\r
+GetCurrentCapsuleLastIndex (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Size;\r
+ CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
+ EFI_STATUS Status;\r
+ UINT16 CurrentIndex;\r
+\r
+ Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
+ Status = gRT->GetVariable(\r
+ L"CapsuleLast",\r
+ &gEfiCapsuleReportGuid,\r
+ NULL,\r
+ &Size,\r
+ CapsuleLastStr\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return -1;\r
+ }\r
+ CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]);\r
+ return CurrentIndex;\r
+}\r
+\r
+/**\r
+ Check if this FMP capsule is processed.\r
+\r
+ @param[in] CapsuleHeader The capsule image header\r
+ @param[in] PayloadIndex FMP payload index\r
+ @param[in] ImageHeader FMP image header\r
+\r
+ @retval TRUE This FMP capsule is processed.\r
+ @retval FALSE This FMP capsule is not processed.\r
+**/\r
+BOOLEAN\r
+IsFmpCapsuleProcessed (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN UINTN PayloadIndex,\r
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult;\r
+ EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp;\r
+\r
+ for (Index = 0; Index < mCapsuleResultVariableCacheCount; Index++) {\r
+ //\r
+ // Check\r
+ //\r
+ CapsuleResult = &mCapsuleResultVariableCache[Index].CapsuleResultHeader;\r
+ if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {\r
+ if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
+ if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {\r
+ CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1);\r
+ if (CompareGuid(&CapsuleResultFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId) &&\r
+ (CapsuleResultFmp->UpdateImageIndex == ImageHeader->UpdateImageIndex) &&\r
+ (CapsuleResultFmp->PayloadIndex == PayloadIndex) ) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Write a new capsule status variable cache.\r
+\r
+ @param[in] CapsuleResult The capsule status variable\r
+ @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes\r
+\r
+ @retval EFI_SUCCESS The capsule status variable is cached.\r
+ @retval EFI_OUT_OF_RESOURCES No resource to cache the capsule status variable.\r
+**/\r
+EFI_STATUS\r
+WriteNewCapsuleResultVariableCache (\r
+ IN VOID *CapsuleResult,\r
+ IN UINTN CapsuleResultSize\r
+ )\r
+{\r
+ if (CapsuleResultSize > sizeof(CAPSULE_RESULT_VARIABLE_CACHE)) {\r
+ CapsuleResultSize = sizeof(CAPSULE_RESULT_VARIABLE_CACHE);\r
+ }\r
+\r
+ if (mCapsuleResultVariableCacheCount == mCapsuleResultVariableCacheMaxCount) {\r
+ mCapsuleResultVariableCache = ReallocatePool(\r
+ mCapsuleResultVariableCacheMaxCount * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),\r
+ (mCapsuleResultVariableCacheMaxCount + CAPSULE_RESULT_VARIABLE_CACHE_COUNT) * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),\r
+ mCapsuleResultVariableCache\r
+ );\r
+ if (mCapsuleResultVariableCache == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ mCapsuleResultVariableCacheMaxCount += CAPSULE_RESULT_VARIABLE_CACHE_COUNT;\r
+ }\r
+\r
+ ASSERT(mCapsuleResultVariableCacheCount < mCapsuleResultVariableCacheMaxCount);\r
+ ASSERT(mCapsuleResultVariableCache != NULL);\r
+ CopyMem(\r
+ &mCapsuleResultVariableCache[mCapsuleResultVariableCacheCount],\r
+ CapsuleResult,\r
+ CapsuleResultSize\r
+ );\r
+ mCapsuleResultVariableCacheCount++;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get a new capsule status variable index.\r
+\r
+ @return A new capsule status variable index.\r
+ @retval -1 No new capsule status variable index.\r
+**/\r
+INTN\r
+GetNewCapsuleResultIndex (\r
+ VOID\r
+ )\r
+{\r
+ INTN CurrentIndex;\r
+\r
+ CurrentIndex = GetCurrentCapsuleLastIndex();\r
+ if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) {\r
+ return -1;\r
+ }\r
+\r
+ return CurrentIndex + 1;\r
+}\r
+\r
+/**\r
+ Write a new capsule status variable.\r
+\r
+ @param[in] CapsuleResult The capsule status variable\r
+ @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes\r
+\r
+ @retval EFI_SUCCESS The capsule status variable is recorded.\r
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
+**/\r
+EFI_STATUS\r
+WriteNewCapsuleResultVariable (\r
+ IN VOID *CapsuleResult,\r
+ IN UINTN CapsuleResultSize\r
+ )\r
+{\r
+ INTN CapsuleResultIndex;\r
+ CHAR16 CapsuleResultStr[sizeof("Capsule####")];\r
+ UINTN Size;\r
+ EFI_STATUS Status;\r
+\r
+ CapsuleResultIndex = GetNewCapsuleResultIndex();\r
+ DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));\r
+ if (CapsuleResultIndex == -1) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ UnicodeSPrint(\r
+ CapsuleResultStr,\r
+ sizeof(CapsuleResultStr),\r
+ L"Capsule%04x",\r
+ CapsuleResultIndex\r
+ );\r
+\r
+ Status = gRT->SetVariable(\r
+ CapsuleResultStr,\r
+ &gEfiCapsuleReportGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ CapsuleResultSize,\r
+ CapsuleResult\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
+ DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));\r
+ Status = gRT->SetVariable(\r
+ L"CapsuleLast",\r
+ &gEfiCapsuleReportGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ Size,\r
+ CapsuleResultStr\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Record capsule status variable and to local cache.\r
+\r
+ @param[in] CapsuleHeader The capsule image header\r
+ @param[in] CapsuleStatus The capsule process stauts\r
+\r
+ @retval EFI_SUCCESS The capsule status variable is recorded.\r
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
+**/\r
+EFI_STATUS\r
+RecordCapsuleStatusVariable (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN EFI_STATUS CapsuleStatus\r
+ )\r
+{\r
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;\r
+ EFI_STATUS Status;\r
+\r
+ CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);\r
+ CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
+ ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));\r
+ gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);\r
+ CapsuleResultVariable.CapsuleStatus = CapsuleStatus;\r
+\r
+ //\r
+ // Save Local Cache\r
+ //\r
+ Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
+\r
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
+ Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Record FMP capsule status variable and to local cache.\r
+\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
+ @retval EFI_SUCCESS The capsule status variable is recorded.\r
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
+**/\r
+EFI_STATUS\r
+RecordFmpCapsuleStatusVariable (\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
+ UINT8 CapsuleResultVariable[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)];\r
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;\r
+ EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;\r
+ EFI_STATUS Status;\r
+\r
+ CapsuleResultVariableHeader = (VOID *)&CapsuleResultVariable[0];\r
+ CapsuleResultVariableHeader->VariableTotalSize = sizeof(CapsuleResultVariable);\r
+ CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
+ ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));\r
+ gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);\r
+ CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;\r
+\r
+ CapsuleResultVariableFmp = (VOID *)&CapsuleResultVariable[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)];\r
+ CapsuleResultVariableFmp->Version = 0x1;\r
+ CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;\r
+ CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;\r
+ CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);\r
+\r
+ //\r
+ // Save Local Cache\r
+ //\r
+ Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
+\r
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
+ Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize CapsuleMax variables.\r
+**/\r
+VOID\r
+InitCapsuleMaxVariable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ CHAR16 CapsuleMaxStr[sizeof("Capsule####")];\r
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
+\r
+ UnicodeSPrint(\r
+ CapsuleMaxStr,\r
+ sizeof(CapsuleMaxStr),\r
+ L"Capsule%04x",\r
+ PcdGet16(PcdCapsuleMax)\r
+ );\r
+\r
+ Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
+ Status = gRT->SetVariable(\r
+ L"CapsuleMax",\r
+ &gEfiCapsuleReportGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ Size,\r
+ CapsuleMaxStr\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ // Lock it per UEFI spec.\r
+ Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);\r
+ ASSERT_EFI_ERROR(Status);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize CapsuleLast variables.\r
+**/\r
+VOID\r
+InitCapsuleLastVariable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MODE BootMode;\r
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
+ VOID *CapsuleResult;\r
+ UINTN Size;\r
+ CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
+\r
+ BootMode = GetBootModeHob();\r
+ if (BootMode == BOOT_ON_FLASH_UPDATE) {\r
+ Status = gRT->SetVariable(\r
+ L"CapsuleLast",\r
+ &gEfiCapsuleReportGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ 0,\r
+ NULL\r
+ );\r
+ // Do not lock it because it will be updated later.\r
+ } else {\r
+ //\r
+ // Check if OS/APP cleared L"Capsule####"\r
+ //\r
+ ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));\r
+ Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
+ Status = gRT->GetVariable(\r
+ L"CapsuleLast",\r
+ &gEfiCapsuleReportGuid,\r
+ NULL,\r
+ &Size,\r
+ CapsuleLastStr\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // L"CapsuleLast" is got, check if data is there.\r
+ //\r
+ Status = GetVariable2 (\r
+ CapsuleLastStr,\r
+ &gEfiCapsuleReportGuid,\r
+ (VOID **) &CapsuleResult,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // If no data, delete L"CapsuleLast"\r
+ //\r
+ Status = gRT->SetVariable(\r
+ L"CapsuleLast",\r
+ &gEfiCapsuleReportGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ 0,\r
+ NULL\r
+ );\r
+ }\r
+ }\r
+\r
+ // Lock it in normal boot path per UEFI spec.\r
+ Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);\r
+ ASSERT_EFI_ERROR(Status);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize capsule update variables.\r
+**/\r
+VOID\r
+InitCapsuleUpdateVariable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ CHAR16 CapsuleVarName[30];\r
+ CHAR16 *TempVarName;\r
+\r
+ //\r
+ // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
+ // as early as possible which will avoid the next time boot after the capsule update\r
+ // will still into the capsule loop\r
+ //\r
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);\r
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
+ Index = 0;\r
+ while (TRUE) {\r
+ if (Index > 0) {\r
+ UnicodeValueToString (TempVarName, 0, Index, 0);\r
+ }\r
+ Status = gRT->SetVariable (\r
+ CapsuleVarName,\r
+ &gEfiCapsuleVendorGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ (VOID *)NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // There is no capsule variables, quit\r
+ //\r
+ break;\r
+ }\r
+ Index++;\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize capsule related variables.\r
+**/\r
+VOID\r
+InitCapsuleVariable (\r
+ VOID\r
+ )\r
+{\r
+ InitCapsuleUpdateVariable();\r
+ InitCapsuleMaxVariable();\r
+ InitCapsuleLastVariable();\r
+ //\r
+ // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"\r
+ // to check status and delete them.\r
+ //\r
+}\r
--- /dev/null
+/** @file\r
+ DXE capsule report related function.\r
+ Dummy function for runtime module, because CapsuleDxeRuntime\r
+ does not need record capsule status variable.\r
+\r
+ Copyright (c) 2016, 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
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/FirmwareManagement.h>\r
+#include <Guid/FmpCapsule.h>\r
+#include <Library/CapsuleLib.h>\r
+\r
+/**\r
+ Check if this FMP capsule is processed.\r
+\r
+ @param[in] CapsuleHeader The capsule image header\r
+ @param[in] PayloadIndex FMP payload index\r
+ @param[in] ImageHeader FMP image header\r
+\r
+ @retval TRUE This FMP capsule is processed.\r
+ @retval FALSE This FMP capsule is not processed.\r
+**/\r
+BOOLEAN\r
+IsFmpCapsuleProcessed (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN UINTN PayloadIndex,\r
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader\r
+ )\r
+{\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Record capsule status variable and to local cache.\r
+\r
+ @param[in] CapsuleHeader The capsule image header\r
+ @param[in] CapsuleStatus The capsule process stauts\r
+\r
+ @retval EFI_SUCCESS The capsule status variable is recorded.\r
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
+**/\r
+EFI_STATUS\r
+RecordCapsuleStatusVariable (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN EFI_STATUS CapsuleStatus\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Record FMP capsule status variable and to local cache.\r
+\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
+ @retval EFI_SUCCESS The capsule status variable is recorded.\r
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
+**/\r
+EFI_STATUS\r
+RecordFmpCapsuleStatusVariable (\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
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Initialize capsule related variables.\r
+**/\r
+VOID\r
+InitCapsuleVariable (\r
+ VOID\r
+ )\r
+{\r
+ return;\r
+}\r
--- /dev/null
+/** @file\r
+ Capsule library runtime support.\r
+\r
+ Copyright (c) 2016, 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
+**/\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Guid/FmpCapsule.h>\r
+#include <Guid/SystemResourceTable.h>\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+extern EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable;\r
+extern BOOLEAN mIsVirtualAddrConverted;\r
+\r
+/**\r
+ Convert EsrtTable physical address to virtual address.\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context The pointer to the notification function's context, which\r
+ is implementation-dependent.\r
+**/\r
+VOID\r
+EFIAPI\r
+DxeCapsuleLibVirtualAddressChangeEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_CONFIGURATION_TABLE *ConfigEntry;\r
+\r
+ //\r
+ // Get Esrt table first\r
+ //\r
+ ConfigEntry = gST->ConfigurationTable;\r
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
+ if (CompareGuid(&gEfiSystemResourceTableGuid, &ConfigEntry->VendorGuid)) {\r
+ break;\r
+ }\r
+ ConfigEntry++;\r
+ }\r
+\r
+ //\r
+ // If no Esrt table installed in Configure Table\r
+ //\r
+ if (Index < gST->NumberOfTableEntries) {\r
+ //\r
+ // Search Esrt to check given capsule is qualified\r
+ //\r
+ mEsrtTable = (EFI_SYSTEM_RESOURCE_TABLE *) ConfigEntry->VendorTable;\r
+\r
+ //\r
+ // Update protocol pointer to Esrt Table.\r
+ //\r
+ gRT->ConvertPointer (0x00, (VOID**) &(mEsrtTable));\r
+ }\r
+\r
+ mIsVirtualAddrConverted = TRUE;\r
+\r
+}\r
+\r
+/**\r
+ The constructor function hook VirtualAddressChange event to use ESRT table as capsule routing table.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The constructor successfully .\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeRuntimeCapsuleLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ //\r
+ // Make sure we can handle virtual address changes.\r
+ //\r
+ Event = NULL;\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ DxeCapsuleLibVirtualAddressChangeEvent,\r
+ NULL,\r
+ &gEfiEventVirtualAddressChangeGuid,\r
+ &Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+## @file\r
+# Capsule library instance for DXE_RUNTIME_DRIVER.\r
+#\r
+# Capsule library instance for DXE_RUNTIME_DRIVER module types.\r
+#\r
+# Copyright (c) 2016, 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
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = DxeRuntimeCapsuleLib\r
+ MODULE_UNI_FILE = DxeRuntimeCapsuleLib.uni\r
+ FILE_GUID = 19BE1E4B-1A9A-44c1-8F12-32DD0470516A\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = CapsuleLib|DXE_RUNTIME_DRIVER\r
+ CONSTRUCTOR = DxeCapsuleLibConstructor\r
+ CONSTRUCTOR = DxeRuntimeCapsuleLibConstructor\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ DxeCapsuleLib.c\r
+ DxeCapsuleProcessLibNull.c\r
+ DxeCapsuleReportLibNull.c\r
+ DxeCapsuleRuntime.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ MemoryAllocationLib\r
+ DxeServicesTableLib\r
+ UefiBootServicesTableLib\r
+ DevicePathLib\r
+ ReportStatusCodeLib\r
+ PrintLib\r
+ HobLib\r
+\r
+[Pcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES\r
+\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem ## CONSUMES\r
+\r
+[Protocols]\r
+ gEsrtManagementProtocolGuid ## CONSUMES\r
+ gEfiFirmwareManagementProtocolGuid ## SOMETIMES_CONSUMES\r
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES\r
+\r
+[Guids]\r
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID\r
+ gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID\r
+ gEfiSystemResourceTableGuid ## SOMETIMES_CONSUMES ## GUID\r
+ gEfiCapsuleReportGuid ## CONSUMES ## Variable\r
+ gEfiCapsuleVendorGuid ## CONSUMES ## Variable\r
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event\r
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event\r
+\r
+[Depex]\r
+ gEfiVariableWriteArchProtocolGuid\r
--- /dev/null
+// /** @file\r
+// Capsule library instance for DXE_RUNTIME_DRIVER.\r
+//\r
+// Capsule library instance for DXE_RUNTIME_DRIVER module types.\r
+//\r
+// Copyright (c) 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
+// 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
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_RUNTIME_DRIVER module types."\r
+\r