+/** @file\r
+ The logic to process capsule.\r
+\r
+Copyright (c) 2011, 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 <Uefi.h>\r
+#include <PiPei.h>\r
+\r
+#include <Guid/CapsuleVendor.h>\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/BaseLib.h>\r
+\r
+#define MIN_COALESCE_ADDR (1024 * 1024)\r
+#define MAX_SUPPORT_CAPSULE_NUM 50\r
+\r
+#define EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('C', 'a', 'p', 'D')\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ UINT32 CapsuleSize;\r
+} EFI_CAPSULE_PEIM_PRIVATE_DATA;\r
+\r
+/**\r
+ Given a pointer to the capsule block list, info on the available system\r
+ memory, and the size of a buffer, find a free block of memory where a\r
+ buffer of the given size can be copied to safely.\r
+\r
+ @param BlockList Pointer to head of capsule block descriptors\r
+ @param MemBase Pointer to the base of memory in which we want to find free space\r
+ @param MemSize The size of the block of memory pointed to by MemBase\r
+ @param DataSize How big a free block we want to find\r
+\r
+ @return A pointer to a memory block of at least DataSize that lies somewhere \r
+ between MemBase and (MemBase + MemSize). The memory pointed to does not\r
+ contain any of the capsule block descriptors or capsule blocks pointed to\r
+ by the BlockList.\r
+\r
+**/\r
+UINT8 *\r
+FindFreeMem (\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
+ UINT8 *MemBase,\r
+ UINTN MemSize,\r
+ UINTN DataSize\r
+ );\r
+\r
+/**\r
+ Check the integrity of the capsule descriptors.\r
+\r
+ @param BlockList Pointer to the capsule descriptors\r
+\r
+ @retval NULL BlockList is not valid.\r
+ @retval LastBlockDesc Last one Block in BlockList\r
+\r
+**/\r
+EFI_CAPSULE_BLOCK_DESCRIPTOR *\r
+ValidateCapsuleIntegrity (\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList\r
+ );\r
+\r
+/**\r
+ The capsule block descriptors may be fragmented and spread all over memory.\r
+ To simplify the coalescing of capsule blocks, first coalesce all the\r
+ capsule block descriptors low in memory.\r
+\r
+ The descriptors passed in can be fragmented throughout memory. Here\r
+ they are relocated into memory to turn them into a contiguous (null\r
+ terminated) array.\r
+\r
+ @param PeiServices pointer to PEI services table\r
+ @param BlockList pointer to the capsule block descriptors\r
+ @param MemBase base of system memory in which we can work\r
+ @param MemSize size of the system memory pointed to by MemBase\r
+\r
+ @retval NULL could not relocate the descriptors\r
+ @retval Pointer to the base of the successfully-relocated block descriptors. \r
+\r
+**/\r
+EFI_CAPSULE_BLOCK_DESCRIPTOR *\r
+RelocateBlockDescriptors (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
+ IN UINT8 *MemBase,\r
+ IN UINTN MemSize\r
+ );\r
+\r
+/**\r
+ Check every capsule header.\r
+\r
+ @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER\r
+\r
+ @retval FALSE Capsule is OK\r
+ @retval TRUE Capsule is corrupted \r
+\r
+**/\r
+BOOLEAN\r
+IsCapsuleCorrupted (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ );\r
+\r
+/**\r
+ Determine if two buffers overlap in memory.\r
+\r
+ @param Buff1 pointer to first buffer\r
+ @param Size1 size of Buff1\r
+ @param Buff2 pointer to second buffer\r
+ @param Size2 size of Buff2\r
+\r
+ @retval TRUE Buffers overlap in memory.\r
+ @retval FALSE Buffer doesn't overlap.\r
+\r
+**/\r
+BOOLEAN\r
+IsOverlapped (\r
+ UINT8 *Buff1,\r
+ UINTN Size1,\r
+ UINT8 *Buff2,\r
+ UINTN Size2\r
+ );\r
+\r
+/**\r
+ Given a pointer to a capsule block descriptor, traverse the list to figure\r
+ out how many legitimate descriptors there are, and how big the capsule it\r
+ refers to is.\r
+\r
+ @param Desc Pointer to the capsule block descriptors\r
+ NumDescriptors - optional pointer to where to return the number of descriptors\r
+ CapsuleSize - optional pointer to where to return the capsule size\r
+ @param NumDescriptors Optional pointer to where to return the number of descriptors\r
+ @param CapsuleSize Optional pointer to where to return the capsule size\r
+\r
+ @retval EFI_NOT_FOUND No descriptors containing data in the list\r
+ @retval EFI_SUCCESS Return data is valid\r
+\r
+**/\r
+EFI_STATUS\r
+GetCapsuleInfo (\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,\r
+ IN OUT UINTN *NumDescriptors OPTIONAL,\r
+ IN OUT UINTN *CapsuleSize OPTIONAL\r
+ );\r
+\r
+/**\r
+ Given a pointer to the capsule block list, info on the available system\r
+ memory, and the size of a buffer, find a free block of memory where a\r
+ buffer of the given size can be copied to safely.\r
+\r
+ @param BlockList Pointer to head of capsule block descriptors\r
+ @param MemBase Pointer to the base of memory in which we want to find free space\r
+ @param MemSize The size of the block of memory pointed to by MemBase\r
+ @param DataSize How big a free block we want to find\r
+\r
+ @return A pointer to a memory block of at least DataSize that lies somewhere \r
+ between MemBase and (MemBase + MemSize). The memory pointed to does not\r
+ contain any of the capsule block descriptors or capsule blocks pointed to\r
+ by the BlockList.\r
+\r
+**/\r
+UINT8 *\r
+FindFreeMem (\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
+ UINT8 *MemBase,\r
+ UINTN MemSize,\r
+ UINTN DataSize\r
+ )\r
+{\r
+ UINTN Size;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrDesc;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempDesc;\r
+ UINT8 *MemEnd;\r
+ BOOLEAN Failed;\r
+\r
+ //\r
+ // Need at least enough to copy the data to at the end of the buffer, so\r
+ // say the end is less the data size for easy comparisons here.\r
+ //\r
+ MemEnd = MemBase + MemSize - DataSize;\r
+ CurrDesc = BlockList;\r
+ //\r
+ // Go through all the descriptor blocks and see if any obstruct the range\r
+ //\r
+ while (CurrDesc != NULL) {\r
+ //\r
+ // Get the size of this block list and see if it's in the way\r
+ //\r
+ Failed = FALSE;\r
+ TempDesc = CurrDesc;\r
+ Size = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+ while (TempDesc->Length != 0) {\r
+ Size += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+ TempDesc++;\r
+ }\r
+\r
+ if (IsOverlapped (MemBase, DataSize, (UINT8 *) CurrDesc, Size)) {\r
+ //\r
+ // Set our new base to the end of this block list and start all over\r
+ //\r
+ MemBase = (UINT8 *) CurrDesc + Size;\r
+ CurrDesc = BlockList;\r
+ if (MemBase > MemEnd) {\r
+ return NULL;\r
+ }\r
+\r
+ Failed = TRUE;\r
+ }\r
+ //\r
+ // Now go through all the blocks and make sure none are in the way\r
+ //\r
+ while ((CurrDesc->Length != 0) && (!Failed)) {\r
+ if (IsOverlapped (MemBase, DataSize, (UINT8 *) (UINTN) CurrDesc->Union.DataBlock, (UINTN) CurrDesc->Length)) {\r
+ //\r
+ // Set our new base to the end of this block and start all over\r
+ //\r
+ Failed = TRUE;\r
+ MemBase = (UINT8 *) ((UINTN) CurrDesc->Union.DataBlock) + CurrDesc->Length;\r
+ CurrDesc = BlockList;\r
+ if (MemBase > MemEnd) {\r
+ return NULL;\r
+ }\r
+ }\r
+ CurrDesc++;\r
+ }\r
+ //\r
+ // Normal continuation -- jump to next block descriptor list\r
+ //\r
+ if (!Failed) {\r
+ CurrDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) CurrDesc->Union.ContinuationPointer;\r
+ }\r
+ }\r
+ return MemBase;\r
+}\r
+\r
+/**\r
+ Check the integrity of the capsule descriptors.\r
+\r
+ @param BlockList Pointer to the capsule descriptors\r
+\r
+ @retval NULL BlockList is not valid.\r
+ @retval LastBlockDesc Last one Block in BlockList\r
+\r
+**/\r
+EFI_CAPSULE_BLOCK_DESCRIPTOR *\r
+ValidateCapsuleIntegrity (\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList\r
+ )\r
+{\r
+ EFI_CAPSULE_HEADER *CapsuleHeader;\r
+ UINT64 CapsuleSize;\r
+ UINT32 CapsuleCount;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr;\r
+\r
+ //\r
+ // Go through the list to look for inconsistencies. Check for:\r
+ // * misaligned block descriptors.\r
+ // * The first capsule header guid\r
+ // * The first capsule header flag\r
+ // * Data + Length < Data (wrap)\r
+ CapsuleSize = 0;\r
+ CapsuleCount = 0;\r
+ Ptr = BlockList;\r
+ while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
+ //\r
+ // Make sure the descriptor is aligned at UINT64 in memory\r
+ //\r
+ if ((UINTN) Ptr & 0x07) {\r
+ DEBUG ((EFI_D_ERROR, "BlockList address failed alignment check\n"));\r
+ return NULL;\r
+ }\r
+\r
+ if (Ptr->Length == 0) {\r
+ //\r
+ // Descriptor points to another list of block descriptors somewhere\r
+ // else.\r
+ //\r
+ Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer;\r
+ } else {\r
+ //\r
+ //To enhance the reliability of check-up, the first capsule's header is checked here.\r
+ //More reliabilities check-up will do later.\r
+ //\r
+ if (CapsuleSize == 0) {\r
+ //\r
+ //Move to the first capsule to check its header.\r
+ //\r
+ CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock);\r
+ if (IsCapsuleCorrupted (CapsuleHeader)) {\r
+ return NULL;\r
+ }\r
+ CapsuleCount ++;\r
+ CapsuleSize = CapsuleHeader->CapsuleImageSize;\r
+ } else {\r
+ if (CapsuleSize >= Ptr->Length) {\r
+ CapsuleSize = CapsuleSize - Ptr->Length;\r
+ } else {\r
+ CapsuleSize = 0;\r
+ }\r
+ }\r
+ //\r
+ // Move to next BLOCK descriptor\r
+ //\r
+ Ptr++;\r
+ }\r
+ }\r
+\r
+ if (CapsuleCount == 0) {\r
+ //\r
+ // No any capsule is found in BlockList.\r
+ //\r
+ return NULL;\r
+ }\r
+\r
+ return Ptr;\r
+}\r
+\r
+/**\r
+ The capsule block descriptors may be fragmented and spread all over memory.\r
+ To simplify the coalescing of capsule blocks, first coalesce all the\r
+ capsule block descriptors low in memory.\r
+\r
+ The descriptors passed in can be fragmented throughout memory. Here\r
+ they are relocated into memory to turn them into a contiguous (null\r
+ terminated) array.\r
+\r
+ @param PeiServices pointer to PEI services table\r
+ @param BlockList pointer to the capsule block descriptors\r
+ @param MemBase base of system memory in which we can work\r
+ @param MemSize size of the system memory pointed to by MemBase\r
+\r
+ @retval NULL could not relocate the descriptors\r
+ @retval Pointer to the base of the successfully-relocated block descriptors. \r
+\r
+**/\r
+EFI_CAPSULE_BLOCK_DESCRIPTOR *\r
+RelocateBlockDescriptors (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,\r
+ IN UINT8 *MemBase,\r
+ IN UINTN MemSize\r
+ )\r
+{\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *NewBlockList;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrBlockDescHead;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *PrevBlockDescTail;\r
+ UINTN NumDescriptors;\r
+ UINTN BufferSize;\r
+ UINT8 *RelocBuffer;\r
+ UINTN BlockListSize;\r
+ //\r
+ // Get the info on the blocks and descriptors. Since we're going to move\r
+ // the descriptors low in memory, adjust the base/size values accordingly here.\r
+ // GetCapsuleInfo() returns the number of legit descriptors, so add one for\r
+ // a terminator.\r
+ //\r
+ if (GetCapsuleInfo (BlockList, &NumDescriptors, NULL) != EFI_SUCCESS) {\r
+ return NULL;\r
+ }\r
+\r
+ NumDescriptors++;\r
+ BufferSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+ NewBlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) MemBase;\r
+ if (MemSize < BufferSize) {\r
+ return NULL;\r
+ }\r
+\r
+ MemSize -= BufferSize;\r
+ MemBase += BufferSize;\r
+ //\r
+ // Go through all the blocks and make sure none are in the way\r
+ //\r
+ TempBlockDesc = BlockList;\r
+ while (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {\r
+ if (TempBlockDesc->Length == 0) {\r
+ //\r
+ // Next block of descriptors\r
+ //\r
+ TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;\r
+ } else {\r
+ //\r
+ // If the capsule data pointed to by this descriptor is in the way,\r
+ // move it.\r
+ //\r
+ if (IsOverlapped (\r
+ (UINT8 *) NewBlockList,\r
+ BufferSize,\r
+ (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,\r
+ (UINTN) TempBlockDesc->Length\r
+ )) {\r
+ //\r
+ // Relocate the block\r
+ //\r
+ RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, (UINTN) TempBlockDesc->Length);\r
+ if (RelocBuffer == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ CopyMem ((VOID *) RelocBuffer, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);\r
+ TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;\r
+\r
+ DEBUG ((EFI_D_INFO, "Capsule relocate descriptors from/to/size 0x%X 0x%X 0x%X\n", (UINT32)(UINTN)TempBlockDesc->Union.DataBlock, (UINT32)(UINTN)RelocBuffer, (UINT32)(UINTN)TempBlockDesc->Length));\r
+ }\r
+ }\r
+ TempBlockDesc++;\r
+ }\r
+ //\r
+ // Now go through all the block descriptors to make sure that they're not\r
+ // in the memory region we want to copy them to.\r
+ //\r
+ CurrBlockDescHead = BlockList;\r
+ PrevBlockDescTail = NULL;\r
+ while ((CurrBlockDescHead != NULL) && (CurrBlockDescHead->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
+ //\r
+ // Get the size of this list then see if it overlaps our low region\r
+ //\r
+ TempBlockDesc = CurrBlockDescHead;\r
+ BlockListSize = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+ while (TempBlockDesc->Length != 0) {\r
+ BlockListSize += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+ TempBlockDesc++;\r
+ }\r
+\r
+ if (IsOverlapped (\r
+ (UINT8 *) NewBlockList,\r
+ BufferSize,\r
+ (UINT8 *) CurrBlockDescHead,\r
+ BlockListSize\r
+ )) {\r
+ //\r
+ // Overlaps, so move it out of the way\r
+ //\r
+ RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, BlockListSize);\r
+ if (RelocBuffer == NULL) {\r
+ return NULL;\r
+ }\r
+ CopyMem ((VOID *) RelocBuffer, (VOID *) CurrBlockDescHead, BlockListSize);\r
+ DEBUG ((EFI_D_INFO, "Capsule reloc descriptor block #2\n"));\r
+ //\r
+ // Point the previous block's next point to this copied version. If\r
+ // the tail pointer is null, then this is the first descriptor block.\r
+ //\r
+ if (PrevBlockDescTail == NULL) {\r
+ BlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) RelocBuffer;\r
+ } else {\r
+ PrevBlockDescTail->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;\r
+ }\r
+ }\r
+ //\r
+ // Save our new tail and jump to the next block list\r
+ //\r
+ PrevBlockDescTail = TempBlockDesc;\r
+ CurrBlockDescHead = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;\r
+ }\r
+ //\r
+ // Cleared out low memory. Now copy the descriptors down there.\r
+ //\r
+ TempBlockDesc = BlockList;\r
+ CurrBlockDescHead = NewBlockList;\r
+ while ((TempBlockDesc != NULL) && (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
+ if (TempBlockDesc->Length != 0) {\r
+ CurrBlockDescHead->Union.DataBlock = TempBlockDesc->Union.DataBlock;\r
+ CurrBlockDescHead->Length = TempBlockDesc->Length;\r
+ CurrBlockDescHead++;\r
+ TempBlockDesc++;\r
+ } else {\r
+ TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;\r
+ }\r
+ }\r
+ //\r
+ // Null terminate\r
+ //\r
+ CurrBlockDescHead->Union.ContinuationPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;\r
+ CurrBlockDescHead->Length = 0;\r
+ return NewBlockList;\r
+}\r
+\r
+/**\r
+ Determine if two buffers overlap in memory.\r
+\r
+ @param Buff1 pointer to first buffer\r
+ @param Size1 size of Buff1\r
+ @param Buff2 pointer to second buffer\r
+ @param Size2 size of Buff2\r
+\r
+ @retval TRUE Buffers overlap in memory.\r
+ @retval FALSE Buffer doesn't overlap.\r
+\r
+**/\r
+BOOLEAN\r
+IsOverlapped (\r
+ UINT8 *Buff1,\r
+ UINTN Size1,\r
+ UINT8 *Buff2,\r
+ UINTN Size2\r
+ )\r
+{\r
+ //\r
+ // If buff1's end is less than the start of buff2, then it's ok.\r
+ // Also, if buff1's start is beyond buff2's end, then it's ok.\r
+ //\r
+ if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Given a pointer to a capsule block descriptor, traverse the list to figure\r
+ out how many legitimate descriptors there are, and how big the capsule it\r
+ refers to is.\r
+\r
+ @param Desc Pointer to the capsule block descriptors\r
+ NumDescriptors - optional pointer to where to return the number of descriptors\r
+ CapsuleSize - optional pointer to where to return the capsule size\r
+ @param NumDescriptors Optional pointer to where to return the number of descriptors\r
+ @param CapsuleSize Optional pointer to where to return the capsule size\r
+\r
+ @retval EFI_NOT_FOUND No descriptors containing data in the list\r
+ @retval EFI_SUCCESS Return data is valid\r
+\r
+**/\r
+EFI_STATUS\r
+GetCapsuleInfo (\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,\r
+ IN OUT UINTN *NumDescriptors OPTIONAL,\r
+ IN OUT UINTN *CapsuleSize OPTIONAL\r
+ )\r
+{\r
+ UINTN Count;\r
+ UINTN Size;\r
+\r
+ Count = 0;\r
+ Size = 0;\r
+\r
+ while (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {\r
+ if (Desc->Length == 0) {\r
+ //\r
+ // Descriptor points to another list of block descriptors somewhere\r
+ //\r
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;\r
+ } else {\r
+ Size += (UINTN) Desc->Length;\r
+ Count++;\r
+ Desc++;\r
+ }\r
+ }\r
+ //\r
+ // If no descriptors, then fail\r
+ //\r
+ if (Count == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (NumDescriptors != NULL) {\r
+ *NumDescriptors = Count;\r
+ }\r
+\r
+ if (CapsuleSize != NULL) {\r
+ *CapsuleSize = Size;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check every capsule header.\r
+\r
+ @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER\r
+\r
+ @retval FALSE Capsule is OK\r
+ @retval TRUE Capsule is corrupted \r
+\r
+**/\r
+BOOLEAN\r
+IsCapsuleCorrupted (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ //\r
+ //A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET.\r
+ //\r
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {\r
+ return TRUE;\r
+ }\r
+ //\r
+ //Make sure the flags combination is supported by the platform.\r
+ //\r
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {\r
+ return TRUE;\r
+ }\r
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Try to verify the integrity of a capsule test pattern before the\r
+ capsule gets coalesced. This can be useful in narrowing down\r
+ where capsule data corruption occurs.\r
+\r
+ The test pattern mode fills in memory with a counting UINT32 value. \r
+ If the capsule is not divided up in a multiple of 4-byte blocks, then\r
+ things get messy doing the check. Therefore there are some cases\r
+ here where we just give up and skip the pre-coalesce check.\r
+\r
+ @param PeiServices PEI services table\r
+ @param Desc Pointer to capsule descriptors\r
+**/\r
+VOID\r
+CapsuleTestPatternPreCoalesce (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc\r
+ )\r
+{\r
+ UINT32 *TestPtr;\r
+ UINT32 TestCounter;\r
+ UINT32 TestSize;\r
+ //\r
+ // Find first data descriptor\r
+ //\r
+ while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;\r
+ }\r
+\r
+ if (Desc->Union.ContinuationPointer == 0) {\r
+ return ;\r
+ }\r
+ //\r
+ // First one better be long enough to at least hold the test signature\r
+ //\r
+ if (Desc->Length < sizeof (UINT32)) {\r
+ DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce punted #1\n"));\r
+ return ;\r
+ }\r
+\r
+ TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;\r
+ //\r
+ // 0x54534554 "TEST"\r
+ //\r
+ if (*TestPtr != 0x54534554) {\r
+ return ;\r
+ }\r
+\r
+ TestCounter = 0;\r
+ TestSize = (UINT32) Desc->Length - 2 * sizeof (UINT32);\r
+ //\r
+ // Skip over the signature and the size fields in the pattern data header\r
+ //\r
+ TestPtr += 2;\r
+ while (1) {\r
+ if ((TestSize & 0x03) != 0) {\r
+ DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce punted #2\n"));\r
+ return ;\r
+ }\r
+\r
+ while (TestSize > 0) {\r
+ if (*TestPtr != TestCounter) {\r
+ DEBUG ((EFI_D_INFO, "Capsule test pattern pre-coalesce failed data corruption check\n"));\r
+ return ;\r
+ }\r
+\r
+ TestSize -= sizeof (UINT32);\r
+ TestCounter++;\r
+ TestPtr++;\r
+ }\r
+ Desc++;\r
+ while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;\r
+ }\r
+\r
+ if (Desc->Union.ContinuationPointer == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {\r
+ return ;\r
+ }\r
+ TestSize = (UINT32) Desc->Length;\r
+ TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;\r
+ }\r
+}\r
+\r
+/**\r
+ Checks for the presence of capsule descriptors.\r
+ Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
+\r
+ @param BlockListBuffer Pointer to the buffer of capsule descriptors variables\r
+ @param BlockDescriptorList Pointer to the capsule descriptors list\r
+\r
+ @retval EFI_SUCCESS a valid capsule is present\r
+ @retval EFI_NOT_FOUND if a valid capsule is not present\r
+**/\r
+EFI_STATUS\r
+BuildCapsuleDescriptors (\r
+ IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,\r
+ OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptorList \r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *LastBlock;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlock;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *HeadBlock;\r
+\r
+ LastBlock = NULL;\r
+ HeadBlock = NULL;\r
+ TempBlock = NULL;\r
+ Index = 0;\r
+\r
+ while (BlockListBuffer[Index] != 0) {\r
+ if (Index == 0) {\r
+ //\r
+ // For the first Capsule Image, test integrity of descriptors.\r
+ //\r
+ LastBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index]);\r
+ if (LastBlock == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Return the base of the block descriptors\r
+ //\r
+ HeadBlock = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index];\r
+ } else { \r
+ //\r
+ // Test integrity of descriptors.\r
+ //\r
+ TempBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index]);\r
+ if (TempBlock == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Combine the different BlockList into single BlockList.\r
+ //\r
+ LastBlock->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)BlockListBuffer[Index];\r
+ LastBlock->Length = 0;\r
+ LastBlock = TempBlock;\r
+ }\r
+ Index ++;\r
+ }\r
+ \r
+ if (HeadBlock != NULL) {\r
+ *BlockDescriptorList = HeadBlock;\r
+ return EFI_SUCCESS;\r
+ }\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ The function to coalesce a fragmented capsule in memory.\r
+\r
+ Memory Map for coalesced capsule:\r
+ MemBase + ---->+---------------------------+<-----------+\r
+ MemSize | CapsuleOffset[49] | |\r
+ +---------------------------+ |\r
+ | ................ | |\r
+ +---------------------------+ |\r
+ | CapsuleOffset[2] | |\r
+ +---------------------------+ |\r
+ | CapsuleOffset[1] | |\r
+ +---------------------------+ |\r
+ | CapsuleOffset[0] | CapsuleSize \r
+ +---------------------------+ |\r
+ | CapsuleNumber | |\r
+ +---------------------------+ |\r
+ | | | \r
+ | | | \r
+ | Capsule Image | | \r
+ | | | \r
+ | | | \r
+ +---------------------------+ |\r
+ | PrivateData | |\r
+ DestPtr ----> +---------------------------+<-----------+\r
+ | | |\r
+ | FreeMem | FreeMemSize\r
+ | | |\r
+ FreeMemBase --->+---------------------------+<-----------+\r
+ | Terminator |\r
+ +---------------------------+\r
+ | BlockDescriptor n |\r
+ +---------------------------+\r
+ | ................. |\r
+ +---------------------------+\r
+ | BlockDescriptor 1 |\r
+ +---------------------------+\r
+ | BlockDescriptor 0 |\r
+ +---------------------------+\r
+ | PrivateDataDesc 0 |\r
+ MemBase ---->+---------------------------+<----- BlockList\r
+\r
+ @param PeiServices General purpose services available to every PEIM.\r
+ @param BlockListBuffer Point to the buffer of Capsule Descriptor Variables.\r
+ @param MemoryBase Pointer to the base of a block of memory that we can walk\r
+ all over while trying to coalesce our buffers.\r
+ On output, this variable will hold the base address of\r
+ a coalesced capsule.\r
+ @param MemorySize Size of the memory region pointed to by MemoryBase.\r
+ On output, this variable will contain the size of the\r
+ coalesced capsule.\r
+\r
+ @retval EFI_NOT_FOUND If we could not find the capsule descriptors.\r
+\r
+ @retval EFI_BUFFER_TOO_SMALL\r
+ If we could not coalesce the capsule in the memory\r
+ region provided to us.\r
+\r
+ @retval EFI_SUCCESS Processed the capsule successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CapsuleDataCoalesce (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,\r
+ IN OUT VOID **MemoryBase,\r
+ IN OUT UINTN *MemorySize\r
+ )\r
+{\r
+ VOID *NewCapsuleBase;\r
+ VOID *DataPtr;\r
+ UINT8 CapsuleIndex;\r
+ UINT8 *FreeMemBase;\r
+ UINT8 *DestPtr;\r
+ UINT8 *RelocPtr;\r
+ UINT32 CapsuleOffset[MAX_SUPPORT_CAPSULE_NUM]; \r
+ UINT32 *AddDataPtr;\r
+ UINT32 CapsuleTimes; \r
+ UINT64 SizeLeft; \r
+ UINT64 CapsuleImageSize; \r
+ UINTN CapsuleSize;\r
+ UINTN DescriptorsSize;\r
+ UINTN FreeMemSize;\r
+ UINTN NumDescriptors;\r
+ BOOLEAN IsCorrupted;\r
+ BOOLEAN CapsuleBeginFlag;\r
+ EFI_STATUS Status;\r
+ EFI_CAPSULE_HEADER *CapsuleHeader;\r
+ EFI_CAPSULE_PEIM_PRIVATE_DATA PrivateData;\r
+ EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateDataPtr;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrentBlockDesc;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc[2];\r
+\r
+ CapsuleIndex = 0;\r
+ SizeLeft = 0;\r
+ CapsuleTimes = 0;\r
+ CapsuleImageSize = 0;\r
+ PrivateDataPtr = NULL;\r
+ AddDataPtr = NULL;\r
+ CapsuleHeader = NULL;\r
+ CapsuleBeginFlag = TRUE;\r
+ IsCorrupted = TRUE;\r
+ CapsuleSize = 0;\r
+ NumDescriptors = 0;\r
+ \r
+ //\r
+ // Build capsule descriptors list\r
+ //\r
+ Status = BuildCapsuleDescriptors (BlockListBuffer, &BlockList);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG_CODE (\r
+ CapsuleTestPatternPreCoalesce (PeiServices, BlockList);\r
+ );\r
+\r
+ //\r
+ // Get the size of our descriptors and the capsule size. GetCapsuleInfo()\r
+ // returns the number of descriptors that actually point to data, so add\r
+ // one for a terminator. Do that below.\r
+ //\r
+ GetCapsuleInfo (BlockList, &NumDescriptors, &CapsuleSize);\r
+ if ((CapsuleSize == 0) || (NumDescriptors == 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Initialize our local copy of private data. When we're done, we'll create a\r
+ // descriptor for it as well so that it can be put into free memory without\r
+ // trashing anything.\r
+ //\r
+ PrivateData.Signature = EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE;\r
+ PrivateData.CapsuleSize = (UINT32) CapsuleSize;\r
+ PrivateDataDesc[0].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) &PrivateData;\r
+ PrivateDataDesc[0].Length = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA);\r
+ PrivateDataDesc[1].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) BlockList;\r
+ PrivateDataDesc[1].Length = 0;\r
+ //\r
+ // In addition to PrivateDataDesc[1:0], one terminator is added\r
+ // See below RelocateBlockDescriptors()\r
+ //\r
+ NumDescriptors += 3;\r
+ CapsuleSize += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + sizeof(CapsuleOffset) + sizeof(UINT32);\r
+ BlockList = PrivateDataDesc;\r
+ DescriptorsSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+\r
+ //\r
+ // Don't go below some min address. If the base is below it,\r
+ // then move it up and adjust the size accordingly.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "Capsule Memory range from 0x%8X to 0x%8X\n", (UINTN) *MemoryBase, (UINTN)*MemoryBase + *MemorySize));\r
+ if ((UINTN)*MemoryBase < (UINTN) MIN_COALESCE_ADDR) {\r
+ if (((UINTN)*MemoryBase + *MemorySize) < (UINTN) MIN_COALESCE_ADDR) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ *MemorySize = *MemorySize - ((UINTN) MIN_COALESCE_ADDR - (UINTN) *MemoryBase);\r
+ *MemoryBase = (VOID *) (UINTN) MIN_COALESCE_ADDR;\r
+ }\r
+ }\r
+\r
+ if (*MemorySize <= (CapsuleSize + DescriptorsSize)) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ FreeMemBase = *MemoryBase;\r
+ FreeMemSize = *MemorySize;\r
+ DEBUG ((EFI_D_INFO, "Capsule Free Memory from 0x%8X to 0x%8X\n", (UINTN) FreeMemBase, (UINTN) FreeMemBase + FreeMemSize));\r
+\r
+ //\r
+ // Relocate all the block descriptors to low memory to make further\r
+ // processing easier.\r
+ //\r
+ BlockList = RelocateBlockDescriptors (PeiServices, BlockList, FreeMemBase, FreeMemSize);\r
+ if (BlockList == NULL) {\r
+ //\r
+ // Not enough room to relocate the descriptors\r
+ //\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ //\r
+ // Take the top of memory for the capsule. Naturally align.\r
+ //\r
+ DestPtr = FreeMemBase + FreeMemSize - CapsuleSize;\r
+ DestPtr = (UINT8 *) ((UINTN) DestPtr &~ (UINTN) (sizeof (UINTN) - 1));\r
+ FreeMemBase = (UINT8 *) BlockList + DescriptorsSize;\r
+ FreeMemSize = FreeMemSize - DescriptorsSize - CapsuleSize;\r
+ NewCapsuleBase = (VOID *) DestPtr;\r
+\r
+ //\r
+ // Move all the blocks to the top (high) of memory.\r
+ // Relocate all the obstructing blocks. Note that the block descriptors\r
+ // were coalesced when they were relocated, so we can just ++ the pointer.\r
+ //\r
+ CurrentBlockDesc = BlockList;\r
+ while ((CurrentBlockDesc->Length != 0) || (CurrentBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {\r
+ //\r
+ // See if any of the remaining capsule blocks are in the way\r
+ //\r
+ TempBlockDesc = CurrentBlockDesc;\r
+ while (TempBlockDesc->Length != 0) {\r
+ //\r
+ // Is this block in the way of where we want to copy the current descriptor to?\r
+ //\r
+ if (IsOverlapped (\r
+ (UINT8 *) DestPtr,\r
+ (UINTN) CurrentBlockDesc->Length,\r
+ (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,\r
+ (UINTN) TempBlockDesc->Length\r
+ )) {\r
+ //\r
+ // Relocate the block\r
+ //\r
+ RelocPtr = FindFreeMem (BlockList, FreeMemBase, FreeMemSize, (UINTN) TempBlockDesc->Length);\r
+ if (RelocPtr == NULL) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ CopyMem ((VOID *) RelocPtr, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);\r
+ DEBUG ((EFI_D_INFO, "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n",\r
+ (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) RelocPtr, (UINTN) TempBlockDesc->Length));\r
+\r
+ TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocPtr;\r
+ }\r
+ //\r
+ // Next descriptor\r
+ //\r
+ TempBlockDesc++;\r
+ }\r
+ //\r
+ // Ok, we made it through. Copy the block.\r
+ // we just support greping one capsule from the lists of block descs list.\r
+ //\r
+ CapsuleTimes ++;\r
+ //\r
+ //Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA\r
+ //\r
+ if (CapsuleTimes > 1) {\r
+ //\r
+ //For every capsule entry point, check its header to determine whether to relocate it.\r
+ //If it is invalid, skip it and move on to the next capsule. If it is valid, relocate it.\r
+ //\r
+ if (CapsuleBeginFlag) {\r
+ CapsuleBeginFlag = FALSE;\r
+ CapsuleHeader = (EFI_CAPSULE_HEADER*)(UINTN)CurrentBlockDesc->Union.DataBlock;\r
+ SizeLeft = CapsuleHeader->CapsuleImageSize;\r
+ if (!IsCapsuleCorrupted (CapsuleHeader)) {\r
+\r
+ if (CapsuleIndex > (MAX_SUPPORT_CAPSULE_NUM - 1)) {\r
+ DEBUG ((EFI_D_ERROR, "Capsule number exceeds the max number of %d!\n", MAX_SUPPORT_CAPSULE_NUM));\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ //\r
+ // Relocate this valid capsule\r
+ //\r
+ IsCorrupted = FALSE;\r
+ CapsuleImageSize += SizeLeft;\r
+ CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length);\r
+ DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8lX to 0x%8lX with size 0x%8X\n",CapsuleTimes,\r
+ (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));\r
+ //\r
+ // Cache the begin offset of this capsule\r
+ //\r
+ CapsuleOffset[CapsuleIndex++] = (UINT32) (UINTN) DestPtr - (UINT32)(UINTN)NewCapsuleBase - (UINT32)sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA);\r
+ DestPtr += CurrentBlockDesc->Length;\r
+ }\r
+ //\r
+ // If the current block length is greater than or equal to SizeLeft, this is the \r
+ // start of the next capsule\r
+ //\r
+ if (CurrentBlockDesc->Length < SizeLeft) {\r
+ SizeLeft -= CurrentBlockDesc->Length;\r
+ } else {\r
+ //\r
+ // Start the next cycle\r
+ //\r
+ SizeLeft = 0;\r
+ IsCorrupted = TRUE;\r
+ CapsuleBeginFlag = TRUE; \r
+ }\r
+ } else {\r
+ //\r
+ //Go on relocating the current capule image.\r
+ //\r
+ if (CurrentBlockDesc->Length < SizeLeft) {\r
+ if (!IsCorrupted) {\r
+ CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) (CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);\r
+ DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8lX to 0x%8lX with size 0x%8X\n",CapsuleTimes,\r
+ (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));\r
+ DestPtr += CurrentBlockDesc->Length;\r
+ }\r
+ SizeLeft -= CurrentBlockDesc->Length;\r
+ } else {\r
+ //\r
+ //Here is the end of the current capsule image.\r
+ //\r
+ if (!IsCorrupted) {\r
+ CopyMem ((VOID *) DestPtr, (VOID *)(UINTN)(CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);\r
+ DEBUG ((EFI_D_INFO, "Capsule coalesce block no.0x%8X from 0x%8lX to 0x%8lX with size 0x%8X\n",CapsuleTimes,\r
+ (UINTN)CurrentBlockDesc->Union.DataBlock, (UINTN)DestPtr, (UINTN)CurrentBlockDesc->Length));\r
+ DestPtr += CurrentBlockDesc->Length;\r
+ }\r
+ //\r
+ // Start the next cycle\r
+ //\r
+ SizeLeft = 0;\r
+ IsCorrupted = TRUE;\r
+ CapsuleBeginFlag = TRUE; \r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ //The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.\r
+ //\r
+ CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length);\r
+ DestPtr += CurrentBlockDesc->Length;\r
+ }\r
+ //\r
+ //Walk through the block descriptor list.\r
+ //\r
+ CurrentBlockDesc++;\r
+ }\r
+ //\r
+ // We return the base of memory we want reserved, and the size.\r
+ // The memory peim should handle it appropriately from there.\r
+ //\r
+ *MemorySize = (UINTN) CapsuleImageSize;\r
+ *MemoryBase = (VOID *) NewCapsuleBase;\r
+\r
+ //\r
+ //Append the offsets of mutiply capsules to the continous buffer\r
+ //\r
+ DataPtr = (VOID*)((UINTN)NewCapsuleBase + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (UINTN)CapsuleImageSize);\r
+ AddDataPtr = (UINT32*)(((UINTN) DataPtr + sizeof(UINT32) - 1) &~ (UINT32) (sizeof (UINT32) - 1));\r
+\r
+ *AddDataPtr++ = CapsuleIndex;\r
+\r
+ CopyMem (AddDataPtr, &CapsuleOffset[0], sizeof (UINT32) * CapsuleIndex);\r
+\r
+ PrivateDataPtr = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) NewCapsuleBase;\r
+ PrivateDataPtr->CapsuleSize = (UINT32) CapsuleImageSize;\r
+\r
+ return EFI_SUCCESS;\r
+}\r