From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Universal/CapsulePei/Common/CapsuleCoalesce.c | 1291 ++++++++++++++++++++ 1 file changed, 1291 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c (limited to 'roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c') diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c b/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c new file mode 100644 index 000000000..468eea5d3 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c @@ -0,0 +1,1291 @@ +/** @file + The logic to process capsule. + + Caution: This module requires additional review when modified. + This driver will have external input - capsule image. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + CapsuleDataCoalesce() will do basic validation before coalesce capsule data + into memory. + +(C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +#include + +#include +#include +#include +#include + +#include "CommonHeader.h" + +#define MIN_COALESCE_ADDR (1024 * 1024) + +/** + Given a pointer to the capsule block list, info on the available system + memory, and the size of a buffer, find a free block of memory where a + buffer of the given size can be copied to safely. + + @param BlockList Pointer to head of capsule block descriptors + @param MemBase Pointer to the base of memory in which we want to find free space + @param MemSize The size of the block of memory pointed to by MemBase + @param DataSize How big a free block we want to find + + @return A pointer to a memory block of at least DataSize that lies somewhere + between MemBase and (MemBase + MemSize). The memory pointed to does not + contain any of the capsule block descriptors or capsule blocks pointed to + by the BlockList. + +**/ +UINT8 * +FindFreeMem ( + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, + UINT8 *MemBase, + UINTN MemSize, + UINTN DataSize + ); + +/** + The capsule block descriptors may be fragmented and spread all over memory. + To simplify the coalescing of capsule blocks, first coalesce all the + capsule block descriptors low in memory. + + The descriptors passed in can be fragmented throughout memory. Here + they are relocated into memory to turn them into a contiguous (null + terminated) array. + + @param PeiServices pointer to PEI services table + @param BlockList pointer to the capsule block descriptors + @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero. + @param MemBase base of system memory in which we can work + @param MemSize size of the system memory pointed to by MemBase + + @retval NULL could not relocate the descriptors + @retval Pointer to the base of the successfully-relocated block descriptors. + +**/ +EFI_CAPSULE_BLOCK_DESCRIPTOR * +RelocateBlockDescriptors ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, + IN UINTN NumDescriptors, + IN UINT8 *MemBase, + IN UINTN MemSize + ); + +/** + Check every capsule header. + + @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER + + @retval FALSE Capsule is OK + @retval TRUE Capsule is corrupted + +**/ +BOOLEAN +IsCapsuleCorrupted ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ); + +/** + Determine if two buffers overlap in memory. + + @param Buff1 pointer to first buffer + @param Size1 size of Buff1 + @param Buff2 pointer to second buffer + @param Size2 size of Buff2 + + @retval TRUE Buffers overlap in memory. + @retval FALSE Buffer doesn't overlap. + +**/ +BOOLEAN +IsOverlapped ( + UINT8 *Buff1, + UINTN Size1, + UINT8 *Buff2, + UINTN Size2 + ); + +/** + Given a pointer to a capsule block descriptor, traverse the list to figure + out how many legitimate descriptors there are, and how big the capsule it + refers to is. + + @param Desc Pointer to the capsule block descriptors + @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero. + @param CapsuleSize Optional pointer to where to return the capsule image size + @param CapsuleNumber Optional pointer to where to return the number of capsule + + @retval EFI_NOT_FOUND No descriptors containing data in the list + @retval EFI_SUCCESS Return data is valid + +**/ +EFI_STATUS +GetCapsuleInfo ( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc, + IN OUT UINTN *NumDescriptors OPTIONAL, + IN OUT UINTN *CapsuleSize OPTIONAL, + IN OUT UINTN *CapsuleNumber OPTIONAL + ); + +/** + Given a pointer to the capsule block list, info on the available system + memory, and the size of a buffer, find a free block of memory where a + buffer of the given size can be copied to safely. + + @param BlockList Pointer to head of capsule block descriptors + @param MemBase Pointer to the base of memory in which we want to find free space + @param MemSize The size of the block of memory pointed to by MemBase + @param DataSize How big a free block we want to find + + @return A pointer to a memory block of at least DataSize that lies somewhere + between MemBase and (MemBase + MemSize). The memory pointed to does not + contain any of the capsule block descriptors or capsule blocks pointed to + by the BlockList. + +**/ +UINT8 * +FindFreeMem ( + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, + UINT8 *MemBase, + UINTN MemSize, + UINTN DataSize + ) +{ + UINTN Size; + EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrDesc; + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempDesc; + UINT8 *MemEnd; + BOOLEAN Failed; + + // + // Need at least enough to copy the data to at the end of the buffer, so + // say the end is less the data size for easy comparisons here. + // + MemEnd = MemBase + MemSize - DataSize; + CurrDesc = BlockList; + // + // Go through all the descriptor blocks and see if any obstruct the range + // + while (CurrDesc != NULL) { + // + // Get the size of this block list and see if it's in the way + // + Failed = FALSE; + TempDesc = CurrDesc; + Size = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); + while (TempDesc->Length != 0) { + Size += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); + TempDesc++; + } + + if (IsOverlapped (MemBase, DataSize, (UINT8 *) CurrDesc, Size)) { + // + // Set our new base to the end of this block list and start all over + // + MemBase = (UINT8 *) CurrDesc + Size; + CurrDesc = BlockList; + if (MemBase > MemEnd) { + return NULL; + } + + Failed = TRUE; + } + // + // Now go through all the blocks and make sure none are in the way + // + while ((CurrDesc->Length != 0) && (!Failed)) { + if (IsOverlapped (MemBase, DataSize, (UINT8 *) (UINTN) CurrDesc->Union.DataBlock, (UINTN) CurrDesc->Length)) { + // + // Set our new base to the end of this block and start all over + // + Failed = TRUE; + MemBase = (UINT8 *) ((UINTN) CurrDesc->Union.DataBlock) + CurrDesc->Length; + CurrDesc = BlockList; + if (MemBase > MemEnd) { + return NULL; + } + } + CurrDesc++; + } + // + // Normal continuation -- jump to next block descriptor list + // + if (!Failed) { + CurrDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) CurrDesc->Union.ContinuationPointer; + } + } + return MemBase; +} + +/** + Validate capsule by MemoryResource. + + @param MemoryResource Pointer to the buffer of memory resource descriptor. + @param Address Address to be validated. + @param Size Size to be validated. + + @retval TRUE No memory resource descriptor reported in HOB list before capsule Coalesce, + or it is valid in one MemoryResource. + FALSE It is not in any MemoryResource. + +**/ +BOOLEAN +ValidateCapsuleByMemoryResource ( + IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource, + IN EFI_PHYSICAL_ADDRESS Address, + IN UINT64 Size + ) +{ + UINTN Index; + + // + // Sanity Check + // + if (Size > MAX_ADDRESS) { + DEBUG ((DEBUG_ERROR, "ERROR: Size(0x%lx) > MAX_ADDRESS\n", Size)); + return FALSE; + } + + // + // Sanity Check + // + if (Address > (MAX_ADDRESS - Size)) { + DEBUG ((DEBUG_ERROR, "ERROR: Address(0x%lx) > (MAX_ADDRESS - Size(0x%lx))\n", Address, Size)); + return FALSE; + } + + if (MemoryResource == NULL) { + // + // No memory resource descriptor reported in HOB list before capsule Coalesce. + // + return TRUE; + } + + for (Index = 0; MemoryResource[Index].ResourceLength != 0; Index++) { + if ((Address >= MemoryResource[Index].PhysicalStart) && + ((Address + Size) <= (MemoryResource[Index].PhysicalStart + MemoryResource[Index].ResourceLength))) { + DEBUG ((DEBUG_INFO, "Address(0x%lx) Size(0x%lx) in MemoryResource[0x%x] - Start(0x%lx) Length(0x%lx)\n", + Address, Size, + Index, MemoryResource[Index].PhysicalStart, MemoryResource[Index].ResourceLength)); + return TRUE; + } + } + + DEBUG ((DEBUG_ERROR, "ERROR: Address(0x%lx) Size(0x%lx) not in any MemoryResource\n", Address, Size)); + return FALSE; +} + +/** + Check the integrity of the capsule descriptors. + + @param BlockList Pointer to the capsule descriptors + @param MemoryResource Pointer to the buffer of memory resource descriptor. + + @retval NULL BlockList is not valid. + @retval LastBlockDesc Last one Block in BlockList + +**/ +EFI_CAPSULE_BLOCK_DESCRIPTOR * +ValidateCapsuleIntegrity ( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, + IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource + ) +{ + EFI_CAPSULE_HEADER *CapsuleHeader; + UINT64 CapsuleSize; + UINTN CapsuleCount; + EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr; + + DEBUG ((DEBUG_INFO, "ValidateCapsuleIntegrity\n")); + + // + // Go through the list to look for inconsistencies. Check for: + // * misaligned block descriptors. + // * The first capsule header guid + // * The first capsule header flag + // * The first capsule header HeaderSize + // * Below check will be done in ValidateCapsuleByMemoryResource() + // Length > MAX_ADDRESS + // Ptr + sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR) > MAX_ADDRESS + // DataBlock + Length > MAX_ADDRESS + // + CapsuleSize = 0; + CapsuleCount = 0; + Ptr = BlockList; + + if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) { + return NULL; + } + + DEBUG ((DEBUG_INFO, "Ptr - 0x%p\n", Ptr)); + DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length)); + DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer)); + while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { + // + // Make sure the descriptor is aligned at UINT64 in memory + // + if ((UINTN) Ptr & (sizeof(UINT64) - 1)) { + DEBUG ((DEBUG_ERROR, "ERROR: BlockList address failed alignment check\n")); + return NULL; + } + + if (Ptr->Length == 0) { + // + // Descriptor points to another list of block descriptors somewhere + // else. + // + Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer; + if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) { + return NULL; + } + DEBUG ((DEBUG_INFO, "Ptr(C) - 0x%p\n", Ptr)); + DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length)); + DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer)); + } else { + if (!ValidateCapsuleByMemoryResource (MemoryResource, Ptr->Union.DataBlock, Ptr->Length)) { + return NULL; + } + + // + //To enhance the reliability of check-up, the first capsule's header is checked here. + //More reliabilities check-up will do later. + // + if (CapsuleSize == 0) { + // + //Move to the first capsule to check its header. + // + CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock); + // + // Sanity check + // + if (Ptr->Length < sizeof(EFI_CAPSULE_HEADER)) { + DEBUG ((DEBUG_ERROR, "ERROR: Ptr->Length(0x%lx) < sizeof(EFI_CAPSULE_HEADER)\n", Ptr->Length)); + return NULL; + } + // + // Make sure HeaderSize field is valid + // + if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) { + DEBUG ((DEBUG_ERROR, "ERROR: CapsuleHeader->HeaderSize(0x%x) > CapsuleHeader->CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize)); + return NULL; + } + if (IsCapsuleCorrupted (CapsuleHeader)) { + return NULL; + } + CapsuleCount ++; + CapsuleSize = CapsuleHeader->CapsuleImageSize; + } + + if (CapsuleSize >= Ptr->Length) { + CapsuleSize = CapsuleSize - Ptr->Length; + } else { + DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize(0x%lx) < Ptr->Length(0x%lx)\n", CapsuleSize, Ptr->Length)); + // + // Sanity check + // + return NULL; + } + + // + // Move to next BLOCK descriptor + // + Ptr++; + if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) { + return NULL; + } + DEBUG ((DEBUG_INFO, "Ptr(B) - 0x%p\n", Ptr)); + DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length)); + DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer)); + } + } + + if (CapsuleCount == 0) { + // + // No any capsule is found in BlockList + // + DEBUG ((DEBUG_ERROR, "ERROR: CapsuleCount(0x%x) == 0\n", CapsuleCount)); + return NULL; + } + + if (CapsuleSize != 0) { + // + // Capsule data is incomplete. + // + DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize(0x%lx) != 0\n", CapsuleSize)); + return NULL; + } + + return Ptr; +} + +/** + The capsule block descriptors may be fragmented and spread all over memory. + To simplify the coalescing of capsule blocks, first coalesce all the + capsule block descriptors low in memory. + + The descriptors passed in can be fragmented throughout memory. Here + they are relocated into memory to turn them into a contiguous (null + terminated) array. + + @param PeiServices pointer to PEI services table + @param BlockList pointer to the capsule block descriptors + @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero. + @param MemBase base of system memory in which we can work + @param MemSize size of the system memory pointed to by MemBase + + @retval NULL could not relocate the descriptors + @retval Pointer to the base of the successfully-relocated block descriptors. + +**/ +EFI_CAPSULE_BLOCK_DESCRIPTOR * +RelocateBlockDescriptors ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList, + IN UINTN NumDescriptors, + IN UINT8 *MemBase, + IN UINTN MemSize + ) +{ + EFI_CAPSULE_BLOCK_DESCRIPTOR *NewBlockList; + EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrBlockDescHead; + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc; + EFI_CAPSULE_BLOCK_DESCRIPTOR *PrevBlockDescTail; + UINTN BufferSize; + UINT8 *RelocBuffer; + UINTN BlockListSize; + + // + // Get the info on the blocks and descriptors. Since we're going to move + // the descriptors low in memory, adjust the base/size values accordingly here. + // NumDescriptors is the number of legit data descriptors, so add one for + // a terminator. (Already done by caller, no check is needed.) + // + + BufferSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); + NewBlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) MemBase; + if (MemSize < BufferSize) { + return NULL; + } + + MemSize -= BufferSize; + MemBase += BufferSize; + // + // Go through all the blocks and make sure none are in the way + // + TempBlockDesc = BlockList; + while (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) { + if (TempBlockDesc->Length == 0) { + // + // Next block of descriptors + // + TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer; + } else { + // + // If the capsule data pointed to by this descriptor is in the way, + // move it. + // + if (IsOverlapped ( + (UINT8 *) NewBlockList, + BufferSize, + (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock, + (UINTN) TempBlockDesc->Length + )) { + // + // Relocate the block + // + RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, (UINTN) TempBlockDesc->Length); + if (RelocBuffer == NULL) { + return NULL; + } + + CopyMem ((VOID *) RelocBuffer, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length); + DEBUG ((DEBUG_INFO, "Capsule relocate descriptors from/to/size 0x%lX 0x%lX 0x%lX\n", TempBlockDesc->Union.DataBlock, (UINT64)(UINTN)RelocBuffer, TempBlockDesc->Length)); + TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer; + } + TempBlockDesc++; + } + } + // + // Now go through all the block descriptors to make sure that they're not + // in the memory region we want to copy them to. + // + CurrBlockDescHead = BlockList; + PrevBlockDescTail = NULL; + while ((CurrBlockDescHead != NULL) && (CurrBlockDescHead->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { + // + // Get the size of this list then see if it overlaps our low region + // + TempBlockDesc = CurrBlockDescHead; + BlockListSize = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); + while (TempBlockDesc->Length != 0) { + BlockListSize += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); + TempBlockDesc++; + } + + if (IsOverlapped ( + (UINT8 *) NewBlockList, + BufferSize, + (UINT8 *) CurrBlockDescHead, + BlockListSize + )) { + // + // Overlaps, so move it out of the way + // + RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, BlockListSize); + if (RelocBuffer == NULL) { + return NULL; + } + CopyMem ((VOID *) RelocBuffer, (VOID *) CurrBlockDescHead, BlockListSize); + DEBUG ((DEBUG_INFO, "Capsule reloc descriptor block #2\n")); + // + // Point the previous block's next point to this copied version. If + // the tail pointer is null, then this is the first descriptor block. + // + if (PrevBlockDescTail == NULL) { + BlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) RelocBuffer; + } else { + PrevBlockDescTail->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer; + } + } + // + // Save our new tail and jump to the next block list + // + PrevBlockDescTail = TempBlockDesc; + CurrBlockDescHead = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer; + } + // + // Cleared out low memory. Now copy the descriptors down there. + // + TempBlockDesc = BlockList; + CurrBlockDescHead = NewBlockList; + while ((TempBlockDesc != NULL) && (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { + if (TempBlockDesc->Length != 0) { + CurrBlockDescHead->Union.DataBlock = TempBlockDesc->Union.DataBlock; + CurrBlockDescHead->Length = TempBlockDesc->Length; + CurrBlockDescHead++; + TempBlockDesc++; + } else { + TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer; + } + } + // + // Null terminate + // + CurrBlockDescHead->Union.ContinuationPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; + CurrBlockDescHead->Length = 0; + return NewBlockList; +} + +/** + Determine if two buffers overlap in memory. + + @param Buff1 pointer to first buffer + @param Size1 size of Buff1 + @param Buff2 pointer to second buffer + @param Size2 size of Buff2 + + @retval TRUE Buffers overlap in memory. + @retval FALSE Buffer doesn't overlap. + +**/ +BOOLEAN +IsOverlapped ( + UINT8 *Buff1, + UINTN Size1, + UINT8 *Buff2, + UINTN Size2 + ) +{ + // + // If buff1's end is less than the start of buff2, then it's ok. + // Also, if buff1's start is beyond buff2's end, then it's ok. + // + if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) { + return FALSE; + } + + return TRUE; +} + +/** + Given a pointer to a capsule block descriptor, traverse the list to figure + out how many legitimate descriptors there are, and how big the capsule it + refers to is. + + @param Desc Pointer to the capsule block descriptors + @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero. + @param CapsuleSize Optional pointer to where to return the capsule image size + @param CapsuleNumber Optional pointer to where to return the number of capsule + + @retval EFI_NOT_FOUND No descriptors containing data in the list + @retval EFI_SUCCESS Return data is valid + +**/ +EFI_STATUS +GetCapsuleInfo ( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc, + IN OUT UINTN *NumDescriptors OPTIONAL, + IN OUT UINTN *CapsuleSize OPTIONAL, + IN OUT UINTN *CapsuleNumber OPTIONAL + ) +{ + UINTN Count; + UINTN Size; + UINTN Number; + UINTN ThisCapsuleImageSize; + EFI_CAPSULE_HEADER *CapsuleHeader; + + DEBUG ((DEBUG_INFO, "GetCapsuleInfo enter\n")); + + ASSERT (Desc != NULL); + + Count = 0; + Size = 0; + Number = 0; + ThisCapsuleImageSize = 0; + + while (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) { + if (Desc->Length == 0) { + // + // Descriptor points to another list of block descriptors somewhere + // + Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer; + } else { + // + // Sanity Check + // It is needed, because ValidateCapsuleIntegrity() only validate one individual capsule Size. + // While here we need check all capsules size. + // + if (Desc->Length >= (MAX_ADDRESS - Size)) { + DEBUG ((DEBUG_ERROR, "ERROR: Desc->Length(0x%lx) >= (MAX_ADDRESS - Size(0x%x))\n", Desc->Length, Size)); + return EFI_OUT_OF_RESOURCES; + } + Size += (UINTN) Desc->Length; + Count++; + + // + // See if this is first capsule's header + // + if (ThisCapsuleImageSize == 0) { + CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Desc->Union.DataBlock); + // + // This has been checked in ValidateCapsuleIntegrity() + // + Number ++; + ThisCapsuleImageSize = CapsuleHeader->CapsuleImageSize; + } + + // + // This has been checked in ValidateCapsuleIntegrity() + // + ASSERT (ThisCapsuleImageSize >= Desc->Length); + ThisCapsuleImageSize = (UINTN)(ThisCapsuleImageSize - Desc->Length); + + // + // Move to next + // + Desc++; + } + } + // + // If no descriptors, then fail + // + if (Count == 0) { + DEBUG ((DEBUG_ERROR, "ERROR: Count == 0\n")); + return EFI_NOT_FOUND; + } + + // + // checked in ValidateCapsuleIntegrity() + // + ASSERT (ThisCapsuleImageSize == 0); + + if (NumDescriptors != NULL) { + *NumDescriptors = Count; + } + + if (CapsuleSize != NULL) { + *CapsuleSize = Size; + } + + if (CapsuleNumber != NULL) { + *CapsuleNumber = Number; + } + + return EFI_SUCCESS; +} + +/** + Check every capsule header. + + @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER + + @retval FALSE Capsule is OK + @retval TRUE Capsule is corrupted + +**/ +BOOLEAN +IsCapsuleCorrupted ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + // + //A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET. + // + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) { + return TRUE; + } + // + //Make sure the flags combination is supported by the platform. + // + if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { + return TRUE; + } + if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) { + return TRUE; + } + + return FALSE; +} + +/** + Try to verify the integrity of a capsule test pattern before the + capsule gets coalesced. This can be useful in narrowing down + where capsule data corruption occurs. + + The test pattern mode fills in memory with a counting UINT32 value. + If the capsule is not divided up in a multiple of 4-byte blocks, then + things get messy doing the check. Therefore there are some cases + here where we just give up and skip the pre-coalesce check. + + @param PeiServices PEI services table + @param Desc Pointer to capsule descriptors +**/ +VOID +CapsuleTestPatternPreCoalesce ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc + ) +{ + UINT32 *TestPtr; + UINT32 TestCounter; + UINT32 TestSize; + + DEBUG ((DEBUG_INFO, "CapsuleTestPatternPreCoalesce\n")); + + // + // Find first data descriptor + // + while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { + Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer; + } + + if (Desc->Union.ContinuationPointer == 0) { + return ; + } + // + // First one better be long enough to at least hold the test signature + // + if (Desc->Length < sizeof (UINT32)) { + DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce punted #1\n")); + return ; + } + + TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock; + // + // 0x54534554 "TEST" + // + if (*TestPtr != 0x54534554) { + return ; + } + + TestCounter = 0; + TestSize = (UINT32) Desc->Length - 2 * sizeof (UINT32); + // + // Skip over the signature and the size fields in the pattern data header + // + TestPtr += 2; + while (1) { + if ((TestSize & 0x03) != 0) { + DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce punted #2\n")); + return ; + } + + while (TestSize > 0) { + if (*TestPtr != TestCounter) { + DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce failed data corruption check\n")); + return ; + } + + TestSize -= sizeof (UINT32); + TestCounter++; + TestPtr++; + } + Desc++; + while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { + Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer; + } + + if (Desc->Union.ContinuationPointer == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) { + return ; + } + TestSize = (UINT32) Desc->Length; + TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock; + } +} + +/** + Checks for the presence of capsule descriptors. + Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2... + + @param BlockListBuffer Pointer to the buffer of capsule descriptors variables + @param MemoryResource Pointer to the buffer of memory resource descriptor. + @param BlockDescriptorList Pointer to the capsule descriptors list + + @retval EFI_SUCCESS a valid capsule is present + @retval EFI_NOT_FOUND if a valid capsule is not present +**/ +EFI_STATUS +BuildCapsuleDescriptors ( + IN EFI_PHYSICAL_ADDRESS *BlockListBuffer, + IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource, + OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptorList + ) +{ + UINTN Index; + EFI_CAPSULE_BLOCK_DESCRIPTOR *LastBlock; + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlock; + EFI_CAPSULE_BLOCK_DESCRIPTOR *HeadBlock; + + DEBUG ((DEBUG_INFO, "BuildCapsuleDescriptors enter\n")); + + LastBlock = NULL; + HeadBlock = NULL; + TempBlock = NULL; + Index = 0; + + while (BlockListBuffer[Index] != 0) { + // + // Test integrity of descriptors. + // + if (BlockListBuffer[Index] < MAX_ADDRESS) { + TempBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index], MemoryResource); + if (TempBlock != NULL) { + if (LastBlock == NULL) { + LastBlock = TempBlock; + + // + // Return the base of the block descriptors + // + HeadBlock = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index]; + } else { + // + // Combine the different BlockList into single BlockList. + // + LastBlock->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)BlockListBuffer[Index]; + LastBlock->Length = 0; + LastBlock = TempBlock; + } + } + } else { + DEBUG ((DEBUG_ERROR, "ERROR: BlockListBuffer[Index](0x%lx) < MAX_ADDRESS\n", BlockListBuffer[Index])); + } + Index ++; + } + + if (HeadBlock != NULL) { + *BlockDescriptorList = HeadBlock; + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; +} + +/** + The function to coalesce a fragmented capsule in memory. + + Memory Map for coalesced capsule: + MemBase + ---->+---------------------------+<-----------+ + MemSize | ------------------------- | | + | | Capsule [Num-1] | | | + | ------------------------- | | + | | ................ | | | + | ------------------------- | | + | | Capsule [1] | | | + | ------------------------- | | + | | Capsule [0] | | | + | ------------------------- | | + | Capsule Image | | +CapsuleImageBase-->+---------------------------+ + | ------------------------- | | + | | CapsuleOffset[Num-1] | | | + | ------------------------- | | + | | ................ | | CapsuleSize + | ------------------------- | | + | | CapsuleOffset[1] | | | + | ------------------------- | | + | | CapsuleOffset[0] | | | + |---------------------------| | + | | CapsuleNumber | | | + | ------------------------- | | + | | CapsuleAllImageSize | | | + | ------------------------- | | + | PrivateData | | + DestPtr ---->+---------------------------+<-----------+ + | | | + | FreeMem | FreeMemSize + | | | + FreeMemBase --->+---------------------------+<-----------+ + | Terminator | + +---------------------------+ + | BlockDescriptor n | + +---------------------------+ + | ................. | + +---------------------------+ + | BlockDescriptor 1 | + +---------------------------+ + | BlockDescriptor 0 | + +---------------------------+ + | PrivateDataDesc 0 | + MemBase ---->+---------------------------+<----- BlockList + + Caution: This function may receive untrusted input. + The capsule data is external input, so this routine will do basic validation before + coalesce capsule data into memory. + + @param PeiServices General purpose services available to every PEIM. + @param BlockListBuffer Pointer to the buffer of Capsule Descriptor Variables. + @param MemoryResource Pointer to the buffer of memory resource descriptor. + @param MemoryBase Pointer to the base of a block of memory that we can walk + all over while trying to coalesce our buffers. + On output, this variable will hold the base address of + a coalesced capsule. + @param MemorySize Size of the memory region pointed to by MemoryBase. + On output, this variable will contain the size of the + coalesced capsule. + + @retval EFI_NOT_FOUND If we could not find the capsule descriptors. + + @retval EFI_BUFFER_TOO_SMALL + If we could not coalesce the capsule in the memory + region provided to us. + + @retval EFI_SUCCESS Processed the capsule successfully. +**/ +EFI_STATUS +EFIAPI +CapsuleDataCoalesce ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PHYSICAL_ADDRESS *BlockListBuffer, + IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource, + IN OUT VOID **MemoryBase, + IN OUT UINTN *MemorySize + ) +{ + VOID *NewCapsuleBase; + VOID *CapsuleImageBase; + UINTN CapsuleIndex; + UINT8 *FreeMemBase; + UINT8 *DestPtr; + UINTN DestLength; + UINT8 *RelocPtr; + UINTN CapsuleTimes; + UINT64 SizeLeft; + UINT64 CapsuleImageSize; + UINTN CapsuleSize; + UINTN CapsuleNumber; + UINTN DescriptorsSize; + UINTN FreeMemSize; + UINTN NumDescriptors; + BOOLEAN CapsuleBeginFlag; + EFI_STATUS Status; + EFI_CAPSULE_HEADER *CapsuleHeader; + EFI_CAPSULE_PEIM_PRIVATE_DATA PrivateData; + EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateDataPtr; + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList; + EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrentBlockDesc; + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc; + EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc[2]; + + DEBUG ((DEBUG_INFO, "CapsuleDataCoalesce enter\n")); + + CapsuleIndex = 0; + SizeLeft = 0; + CapsuleTimes = 0; + CapsuleImageSize = 0; + PrivateDataPtr = NULL; + CapsuleHeader = NULL; + CapsuleBeginFlag = TRUE; + CapsuleSize = 0; + NumDescriptors = 0; + + // + // Build capsule descriptors list + // + Status = BuildCapsuleDescriptors (BlockListBuffer, MemoryResource, &BlockList); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG_CODE ( + CapsuleTestPatternPreCoalesce (PeiServices, BlockList); + ); + + // + // Get the size of our descriptors and the capsule size. GetCapsuleInfo() + // returns the number of descriptors that actually point to data, so add + // one for a terminator. Do that below. + // + Status = GetCapsuleInfo (BlockList, &NumDescriptors, &CapsuleSize, &CapsuleNumber); + if (EFI_ERROR (Status)) { + return Status; + } + DEBUG ((DEBUG_INFO, "CapsuleSize - 0x%x\n", CapsuleSize)); + DEBUG ((DEBUG_INFO, "CapsuleNumber - 0x%x\n", CapsuleNumber)); + DEBUG ((DEBUG_INFO, "NumDescriptors - 0x%x\n", NumDescriptors)); + if ((CapsuleSize == 0) || (NumDescriptors == 0) || (CapsuleNumber == 0)) { + return EFI_NOT_FOUND; + } + + if (CapsuleNumber - 1 >= (MAX_ADDRESS - (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + sizeof(UINT64))) / sizeof(UINT64)) { + DEBUG ((DEBUG_ERROR, "ERROR: CapsuleNumber - 0x%x\n", CapsuleNumber)); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Initialize our local copy of private data. When we're done, we'll create a + // descriptor for it as well so that it can be put into free memory without + // trashing anything. + // + PrivateData.Signature = EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE; + PrivateData.CapsuleAllImageSize = (UINT64) CapsuleSize; + PrivateData.CapsuleNumber = (UINT64) CapsuleNumber; + PrivateData.CapsuleOffset[0] = 0; + // + // NOTE: Only data in sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) is valid, CapsuleOffset field is uninitialized at this moment. + // The code sets partial length here for Descriptor.Length check, but later it will use full length to reserve those PrivateData region. + // + PrivateDataDesc[0].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) &PrivateData; + PrivateDataDesc[0].Length = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA); + PrivateDataDesc[1].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) BlockList; + PrivateDataDesc[1].Length = 0; + // + // Add PrivateDataDesc[0] in beginning, as it is new descriptor. PrivateDataDesc[1] is NOT needed. + // In addition, one NULL terminator is added in the end. See RelocateBlockDescriptors(). + // + NumDescriptors += 2; + // + // Sanity check + // + if (CapsuleSize >= (MAX_ADDRESS - (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64) + sizeof(UINT64)))) { + DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize - 0x%x\n", CapsuleSize)); + return EFI_BUFFER_TOO_SMALL; + } + // + // Need add sizeof(UINT64) for PrivateData alignment + // + CapsuleSize += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64) + sizeof(UINT64); + BlockList = PrivateDataDesc; + // + // Sanity check + // + if (NumDescriptors >= (MAX_ADDRESS / sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR))) { + DEBUG ((DEBUG_ERROR, "ERROR: NumDescriptors - 0x%x\n", NumDescriptors)); + return EFI_BUFFER_TOO_SMALL; + } + DescriptorsSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); + // + // Sanity check + // + if (DescriptorsSize >= (MAX_ADDRESS - CapsuleSize)) { + DEBUG ((DEBUG_ERROR, "ERROR: DescriptorsSize - 0x%lx, CapsuleSize - 0x%lx\n", (UINT64)DescriptorsSize, (UINT64)CapsuleSize)); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Don't go below some min address. If the base is below it, + // then move it up and adjust the size accordingly. + // + DEBUG ((DEBUG_INFO, "Capsule Memory range from 0x%8X to 0x%8X\n", (UINTN) *MemoryBase, (UINTN)*MemoryBase + *MemorySize)); + if ((UINTN)*MemoryBase < (UINTN) MIN_COALESCE_ADDR) { + if (((UINTN)*MemoryBase + *MemorySize) < (UINTN) MIN_COALESCE_ADDR) { + DEBUG ((DEBUG_ERROR, "ERROR: *MemoryBase + *MemorySize - 0x%x\n", (UINTN)*MemoryBase + *MemorySize)); + return EFI_BUFFER_TOO_SMALL; + } else { + *MemorySize = *MemorySize - ((UINTN) MIN_COALESCE_ADDR - (UINTN) *MemoryBase); + *MemoryBase = (VOID *) (UINTN) MIN_COALESCE_ADDR; + } + } + + if (*MemorySize <= (CapsuleSize + DescriptorsSize)) { + DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize + DescriptorsSize - 0x%x\n", CapsuleSize + DescriptorsSize)); + return EFI_BUFFER_TOO_SMALL; + } + + FreeMemBase = *MemoryBase; + FreeMemSize = *MemorySize; + DEBUG ((DEBUG_INFO, "Capsule Free Memory from 0x%8X to 0x%8X\n", (UINTN) FreeMemBase, (UINTN) FreeMemBase + FreeMemSize)); + + // + // Relocate all the block descriptors to low memory to make further + // processing easier. + // + BlockList = RelocateBlockDescriptors (PeiServices, BlockList, NumDescriptors, FreeMemBase, FreeMemSize); + if (BlockList == NULL) { + // + // Not enough room to relocate the descriptors + // + return EFI_BUFFER_TOO_SMALL; + } + + // + // Take the top of memory for the capsule. UINT64 align up. + // + DestPtr = FreeMemBase + FreeMemSize - CapsuleSize; + DestPtr = (UINT8 *) (((UINTN)DestPtr + sizeof (UINT64) - 1) & ~(sizeof (UINT64) - 1)); + FreeMemBase = (UINT8 *) BlockList + DescriptorsSize; + FreeMemSize = (UINTN) DestPtr - (UINTN) FreeMemBase; + NewCapsuleBase = (VOID *) DestPtr; + CapsuleImageBase = (UINT8 *)NewCapsuleBase + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64); + + PrivateDataPtr = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) NewCapsuleBase; + + // + // Move all the blocks to the top (high) of memory. + // Relocate all the obstructing blocks. Note that the block descriptors + // were coalesced when they were relocated, so we can just ++ the pointer. + // + CurrentBlockDesc = BlockList; + while ((CurrentBlockDesc->Length != 0) || (CurrentBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { + if (CapsuleTimes == 0) { + // + // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA. + // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use. + // + ASSERT (CurrentBlockDesc->Union.DataBlock == (UINT64)(UINTN)&PrivateData); + DestLength = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64); + } else { + DestLength = (UINTN)CurrentBlockDesc->Length; + } + // + // See if any of the remaining capsule blocks are in the way + // + TempBlockDesc = CurrentBlockDesc; + while (TempBlockDesc->Length != 0) { + // + // Is this block in the way of where we want to copy the current descriptor to? + // + if (IsOverlapped ( + (UINT8 *) DestPtr, + (UINTN) DestLength, + (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock, + (UINTN) TempBlockDesc->Length + )) { + // + // Relocate the block + // + RelocPtr = FindFreeMem (BlockList, FreeMemBase, FreeMemSize, (UINTN) TempBlockDesc->Length); + if (RelocPtr == NULL) { + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem ((VOID *) RelocPtr, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length); + DEBUG ((DEBUG_INFO, "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n", + (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) RelocPtr, (UINTN) TempBlockDesc->Length)); + + TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocPtr; + } + // + // Next descriptor + // + TempBlockDesc++; + } + // + // Ok, we made it through. Copy the block. + // we just support greping one capsule from the lists of block descs list. + // + CapsuleTimes ++; + // + //Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA + // + if (CapsuleTimes > 1) { + // + //For every capsule entry point, check its header to determine whether to relocate it. + //If it is invalid, skip it and move on to the next capsule. If it is valid, relocate it. + // + if (CapsuleBeginFlag) { + CapsuleBeginFlag = FALSE; + CapsuleHeader = (EFI_CAPSULE_HEADER*)(UINTN)CurrentBlockDesc->Union.DataBlock; + SizeLeft = CapsuleHeader->CapsuleImageSize; + + // + // No more check here is needed, because IsCapsuleCorrupted() already in ValidateCapsuleIntegrity() + // + ASSERT (CapsuleIndex < CapsuleNumber); + + // + // Relocate this capsule + // + CapsuleImageSize += SizeLeft; + // + // Cache the begin offset of this capsule + // + ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE); + ASSERT ((UINTN)DestPtr >= (UINTN)CapsuleImageBase); + PrivateDataPtr->CapsuleOffset[CapsuleIndex++] = (UINTN)DestPtr - (UINTN)CapsuleImageBase; + } + + // + // Below ASSERT is checked in ValidateCapsuleIntegrity() + // + ASSERT (CurrentBlockDesc->Length <= SizeLeft); + + CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) (CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length); + DEBUG ((DEBUG_INFO, "Capsule coalesce block no.0x%lX from 0x%lX to 0x%lX with size 0x%lX\n",(UINT64)CapsuleTimes, + CurrentBlockDesc->Union.DataBlock, (UINT64)(UINTN)DestPtr, CurrentBlockDesc->Length)); + DestPtr += CurrentBlockDesc->Length; + SizeLeft -= CurrentBlockDesc->Length; + + if (SizeLeft == 0) { + // + //Here is the end of the current capsule image. + // + CapsuleBeginFlag = TRUE; + } + } else { + // + // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA. + // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use. + // + ASSERT (CurrentBlockDesc->Length == sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA)); + ASSERT ((UINTN)DestPtr == (UINTN)NewCapsuleBase); + CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length); + DestPtr += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64); + } + // + //Walk through the block descriptor list. + // + CurrentBlockDesc++; + } + // + // We return the base of memory we want reserved, and the size. + // The memory peim should handle it appropriately from there. + // + *MemorySize = (UINTN) CapsuleSize; + *MemoryBase = (VOID *) NewCapsuleBase; + + ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE); + ASSERT (PrivateDataPtr->CapsuleAllImageSize == CapsuleImageSize); + ASSERT (PrivateDataPtr->CapsuleNumber == CapsuleIndex); + + return EFI_SUCCESS; +} -- cgit 1.2.3-korg