From b7c51c9cf4864df6aabb99a1ae843becd577237c Mon Sep 17 00:00:00 2001 From: raywu Date: Fri, 15 Jun 2018 00:00:50 +0800 Subject: init. 1AQQW051 --- Core/EM/Capsule2_0/Capsule2_0.c | 870 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 870 insertions(+) create mode 100644 Core/EM/Capsule2_0/Capsule2_0.c (limited to 'Core/EM/Capsule2_0/Capsule2_0.c') diff --git a/Core/EM/Capsule2_0/Capsule2_0.c b/Core/EM/Capsule2_0/Capsule2_0.c new file mode 100644 index 0000000..e29e544 --- /dev/null +++ b/Core/EM/Capsule2_0/Capsule2_0.c @@ -0,0 +1,870 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2012, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/Capsule2_0/Capsule2_0.c 3 4/16/14 3:12a Chaseliu $ +// +// $Revision: 3 $ +// +// $Date: 4/16/14 3:12a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/Capsule2_0/Capsule2_0.c $ +// +// 3 4/16/14 3:12a Chaseliu +// [TAG] EIP163569 +// [Category] Improvement +// [Description] Update for support 2014 BIOS Security Disclosures. +// [Files] +// Library\PeiLib.c +// Library\EfiLib.c +// Core\EM\NVRAM\NVRAMDXE.c +// Core\EM\Capsule2_0\Capsule2_0.c +// Core\CORE_DXE\FwVolBlock.c +// +// 2 4/16/13 5:42a Thomaschen +// Fixed for EIP106722. +// +// 7 3/07/14 5:14p Artems +// EIP 154318 +// Added fixes addressed in review comment +// +// 6 2/28/14 5:54p Artems +// EIP 154318: fixed vulnerability with capsule block descriptors count +// overflow +// +// 5 2/07/13 5:18p Artems +// [TAG] EIP106722 +// [Category] Bug Fix +// [Severity] Critical +// [Symptom] Win8 firmware update doesn't work +// [RootCause] For Win8 update capsule CapsuleRecovery device didn't +// skip capsule header +// [Solution] Added unique GUID to distinguish between AFU and Win8 +// capsule update +// [Files] Capsule2_0.c CapsuleRecovery.c Capsule.h +// +// 4 11/30/12 6:10p Artems +// [TAG] EIP107134 +// [Category] Improvement +// [Description] Potential security holes in Aptio 4 Capsule eModule +// [Files] Capsule2_0.c +// +// 3 7/31/12 6:18p Artems +// [TAG] EIP N/A +// [Category] Improvement +// [Description] Added support for APTIO_FW_UPDATE capsule +// [Files] Capsule2_0.c +// +// 2 7/20/12 10:44a Artems +// [TAG] EIP93520 +// [Category] New Feature +// [Description] Support of Microsoft ESRT spec +// [Files] Capsule.c +// +// 1 5/24/12 4:22p Artems +// [TAG] EIP74625 +// [Category] New Feature +// [Description] New Capsule PPI required by latest Intel's MRC code +// [Files] Capsule2_0.cif +// Capsule2_0.sdl +// Capsule2_0.mak +// Capsule2_0.c +// Capsule2_0.h +// Capsule2_0Runtime.c +// Capsule2_0Bds.c +// +// +//********************************************************************** +// +// +// Name: Capsule2_0.c +// +// Description: Capsule PPI implementation +// +// +//********************************************************************** + +#include +#include +#include +#include +#include "Capsule2_0.h" + +static EFI_GUID CapsuleVariableGuid = EFI_CAPSULE_AMI_GUID; +static EFI_GUID AmiCapsuleHobGuid = AMI_CAPSULE_HOB_GUID; + +static PEI_CAPSULE_PPI CapsulePpi = { + CoreCapsuleCoalesce, + CoreCheckCapsuleUpdate, + CoreCapsuleCreateState +}; + +static EFI_PEI_PPI_DESCRIPTOR PpiList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiCapsulePpiGuid, + &CapsulePpi + } +}; + +// +//---------------------------------------------------------------------------- +// Procedure: Capsule20PeiInit +// +// Description: +// This function installs capsule PPI +// +// Input: +// IN EFI_FFS_FILE_HEADER *FfsHeader - pointer to this file header +// IN EFI_PEI_SERVICES **PeiServices - pointer to PEI_SERVICES +// +// Output: +// None +// +//---------------------------------------------------------------------------- +// +EFI_STATUS EFIAPI Capsule20PeiInit ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices +) +{ + EFI_STATUS Status; + + Status = CoreCheckCapsuleUpdate(PeiServices); + if(!EFI_ERROR(Status)) + Status = (*PeiServices)->InstallPpi(PeiServices, PpiList); + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: CoreCapsuleCoalesce +// +// Description: +// This function coalesces capsule data in continuous block of memory +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices - pointer to PEI_SERVICES +// IN OUT VOID **MemoryBase - pointer to start of available memory +// IN OUT UINTN *MemSize - pointer to available memory size +// +// Output: +// EFI_SUCCESS - capsule coalesced successfully +// EFI_ERROR - not enough memory to complete operation +// +//---------------------------------------------------------------------------- +// +EFI_STATUS CoreCapsuleCoalesce ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT VOID **MemoryBase, + IN OUT UINTN *MemSize +) +{ + EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr; + UINTN Size; + EFI_STATUS Status; + VOID *Start = *MemoryBase; + UINTN BufferSize = *MemSize; + UINTN NoOfChunks; + + Ptr = GetCapsuleLocation(PeiServices); + if(Ptr == NULL) + return EFI_NOT_FOUND; + + Size = GetCapsuleDataSize(Ptr, &NoOfChunks); + if(Size == 0 || Size > MAX_CAPSULE_SIZE) + return EFI_NOT_FOUND; + + if(Size > BufferSize) + return EFI_BUFFER_TOO_SMALL; + +/* First try to find continuous block, not overlapped with capsule data */ + Status = FindFreeBuffer(Ptr, Size, &Start, BufferSize, TRUE); + if(!EFI_ERROR(Status)) { + CoalesceCapsule(Ptr, Start, Size); + *MemoryBase = Start; + *MemSize = Size; + return EFI_SUCCESS; + } + +/* Large enough buffer not found try to coalesce capsule piece by piece */ +/* Get buffer to store mailbox information */ +/* we will allocate buffer from the bottom of available memory */ + Status = FindFreeBuffer(Ptr, sizeof(CAPSULE_BLOCK) * NoOfChunks, &Start, BufferSize, FALSE); + if(EFI_ERROR(Status)) + return Status; +/* recalculate available buffer size */ + BufferSize = (UINTN)Start - (UINTN)(*MemoryBase); + if(Size > BufferSize) + return EFI_BUFFER_TOO_SMALL; + +/* store mailbox info for future use */ + SaveCapsulePointers(Ptr, NoOfChunks, (CAPSULE_BLOCK *)Start); + + Status = CoalesceCapsuleByParts((CAPSULE_BLOCK *)Start, NoOfChunks, *MemoryBase, BufferSize); + if(!EFI_ERROR(Status)) { + *MemSize = Size; //since we will coalesce from start of available memory *MemoryBase value will be valid + } + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: CoreCheckCapsuleUpdate +// +// Description: +// This function checks if capsule is present +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices - pointer to PEI_SERVICES +// +// Output: +// EFI_SUCCESS - capsule present +// EFI_NOT_FOUND - capsule not present or is beyond the 4GB boundaries +// +//---------------------------------------------------------------------------- +// +EFI_STATUS CoreCheckCapsuleUpdate ( + IN EFI_PEI_SERVICES **PeiServices +) +{ + EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr; + + Ptr = GetCapsuleLocation(PeiServices); + return (Ptr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// Procedure: CoreCapsuleCreateState +// +// Description: +// This function copies coalesced capsule into reserved block of memory and creates HOB +// with capsule parameters +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices - pointer to PEI_SERVICES +// IN VOID *CapsuleBase - coalesced capsule start address +// IN UINTN CapsuleSize - capsule size +// +// Output: +// EFI_SUCCESS - capsule present +// EFI_ERROR - not enough memory to perform operation +// +//---------------------------------------------------------------------------- +// +EFI_STATUS CoreCapsuleCreateState( + IN EFI_PEI_SERVICES **PeiServices, + IN VOID *CapsuleBase, + IN UINTN CapsuleSize +) +{ + EFI_STATUS Status; + UINTN TotalSize = 0; + EFI_CAPSULE_HEADER *Cap; + VOID *SaveCap; + AMI_CAPSULE_HOB *Hob; + UINTN Pages; + EFI_PHYSICAL_ADDRESS Save; + static EFI_GUID AmiFwCapsuleGuid = APTIO_FW_CAPSULE_GUID; + static EFI_GUID W8FwUpdateImageCapsuleGuid = W8_FW_UPDATE_IMAGE_CAPSULE_GUID; + + static EFI_GUID RecoveryBootModeGuid = EFI_PEI_BOOT_IN_RECOVERY_MODE_PEIM_PPI; + static EFI_PEI_PPI_DESCRIPTOR RecoveryModePpi = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &RecoveryBootModeGuid, NULL + }; + + Cap = (EFI_CAPSULE_HEADER *)CapsuleBase; + + while(TotalSize < CapsuleSize) { + Pages = EFI_SIZE_TO_PAGES(Cap->CapsuleImageSize); + Status = (*PeiServices)->AllocatePages(PeiServices, EfiBootServicesData, Pages, &Save); + if(EFI_ERROR(Status)) + return Status; + + SaveCap = (VOID *)(UINTN)Save; + MemCpy(SaveCap, Cap, Cap->CapsuleImageSize); + + Status = (*PeiServices)->CreateHob(PeiServices, EFI_HOB_TYPE_GUID_EXTENSION, sizeof(AMI_CAPSULE_HOB), &Hob); + if(EFI_ERROR(Status)) + return Status; + + Hob->Header.Name = AmiCapsuleHobGuid; + Hob->CapsuleData = (EFI_PHYSICAL_ADDRESS)(UINTN)SaveCap; + Hob->CapsuleGuid = Cap->CapsuleGuid; + Hob->CapsuleLength = Cap->CapsuleImageSize; + + if(!guidcmp(&(Cap->CapsuleGuid), &AmiFwCapsuleGuid) || + !guidcmp(&(Cap->CapsuleGuid), &W8FwUpdateImageCapsuleGuid)) { + (*PeiServices)->SetBootMode(PeiServices, BOOT_ON_FLASH_UPDATE); + (*PeiServices)->InstallPpi(PeiServices, &RecoveryModePpi); + } + + TotalSize += Cap->CapsuleImageSize; + (UINT8 *)Cap += Cap->CapsuleImageSize; + } + return EFI_SUCCESS; +} + + +/* ----------- Capsule service functions ------------ */ + +// +//---------------------------------------------------------------------------- +// Procedure: GetCapsuleLocation +// +// Description: +// This function returns pointer to capsule mailbox +// +// Input: +// IN EFI_PEI_SERVICES **PeiServices - pointer to PEI_SERVICES +// +// Output: +// EFI_CAPSULE_BLOCK_DESCRIPTOR * - pointer to mailbox, or NULL +// +//---------------------------------------------------------------------------- +// +EFI_CAPSULE_BLOCK_DESCRIPTOR * GetCapsuleLocation( + IN EFI_PEI_SERVICES **PeiServices +) +{ + EFI_STATUS Status; + UINTN VarSize = sizeof (EFI_PHYSICAL_ADDRESS); + EFI_PHYSICAL_ADDRESS MailBox = 0; + + Status = PeiGetVariable(PeiServices, CAPSULE_UPDATE_VAR, &CapsuleVariableGuid, NULL, &VarSize, &MailBox); + PEI_TRACE((-1, PeiServices, "Get capsule variable %r, addr %lx\n", Status, MailBox)); + if(EFI_ERROR(Status)) + return NULL; + + if(MailBox >= MAX_CAPSULE_ADDRESS) + return NULL; //no support for Capsule above 4GB + + return (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)MailBox; +} + +// +//---------------------------------------------------------------------------- +// Procedure: GetCapsuleDataSize +// +// Description: +// This function returns capsule size calculated from mailbox data +// +// Input: +// IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr - pointer to capsule mailbox +// OUT UINTN *NoOfChunks - pointer where to store quantity of capsule pieces +// +// Output: +// UINTN - capsule size in bytes or 0 +// +//---------------------------------------------------------------------------- +// +UINTN GetCapsuleDataSize( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr, + OUT UINTN *NoOfChunks +) +{ + UINT64 Result = 0; + UINTN Chunks = 0; + + do { + if(Ptr->DataBlock >= MAX_CAPSULE_ADDRESS) //pointer above 4GB + return 0; + + if(Ptr->Length != 0) { + if(Ptr->Length > MAX_CAPSULE_SIZE - Result) + return 0; + Result += Ptr->Length; + Chunks++; + Ptr++; + } else if (Ptr->DataBlock != NULL) { + if(Ptr == (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)(Ptr->ContinuationPointer)) + //when continuation pointer points to itself it's either error or malicious capsule, we won't process it + return 0; + Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)(Ptr->ContinuationPointer); + } else { + break; + } + } while(Chunks <= MAX_CAPSULE_BLOCK_DESCRIPTOR_COUNT); + + if(Chunks <= MAX_CAPSULE_BLOCK_DESCRIPTOR_COUNT) { + *NoOfChunks = Chunks; + return (UINTN)Result; + } else + return 0; +} + +// +//---------------------------------------------------------------------------- +// Procedure: BufferOverlap +// +// Description: +// This function checks if two buffers overlap each other +// +// Input: +// IN MEMORY_BLOCK *Buffer1 - buffer1 parameters +// IN MEMORY_BLOCK *Buffer2 - buffer2 parameters +// +// Output: +// TRUE - buffers overlap, FALSE otherwise +// +//---------------------------------------------------------------------------- +// +BOOLEAN BufferOverlap( + IN MEMORY_BLOCK *Buffer1, + IN MEMORY_BLOCK *Buffer2 +) +{ + return ((Buffer2->Address > (Buffer1->Address + Buffer1->Size)) || + (Buffer1->Address > (Buffer2->Address + Buffer2->Size))) ? FALSE : TRUE; +} + +// +//---------------------------------------------------------------------------- +// Procedure: AdjustBuffer +// +// Description: +// This function moves one block of memory within free range to avoid overlap +// with another buffer +// +// Input: +// IN MEMORY_BLOCK *Free - free memory range parameters +// IN MEMORY_BLOCK *Unmovable - parameters of overlapping buffer that can't be moved +// IN OUT MEMORY_BLOCK *Movable - parameters of overlapping buffer that can be moved +// IN BOOLEAN FromTop - flag of moving direction in free range(TRUE - move from top, FALSE - +// move from bottom +// +// Output: +// EFI_SUCCESS - buffer moved successfully +// EFI_BUFFER_TOO_SMALL - not enough memory to move buffer +// +//---------------------------------------------------------------------------- +// +EFI_STATUS AdjustBuffer( + IN MEMORY_BLOCK *Free, + IN MEMORY_BLOCK *Unmovable, + IN OUT MEMORY_BLOCK *Movable, + IN BOOLEAN FromTop +) +{ + if(!BufferOverlap(Unmovable, Movable)) + return EFI_SUCCESS; + + if(FromTop) { +/* Move movable block to the end of unmovalbe */ + Movable->Address = Unmovable->Address + Unmovable->Size; + } else { +/* Move movable block before unmovable */ + Movable->Address = Unmovable->Address - Movable->Size; + } + + return (BufferOverlap(Unmovable, Free)) ? EFI_BUFFER_TOO_SMALL : EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// Procedure: FindFreeBuffer +// +// Description: +// This function searches for free continuous block of memory of required size +// +// Input: +// IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr - pointer to capsule mailbox +// IN UINTN RequiredSize - size of buffer required +// IN OUT VOID **BaseAddress - on input pointer to start of free memory, on output +// start of requested buffer +// IN UINTN AvailableSize - size of free memory +// IN BOOLEAN FromTop - flag of moving direction in free range(TRUE - move from top, FALSE - +// move from bottom +// +// Output: +// EFI_SUCCESS - buffer moved successfully +// EFI_BUFFER_TOO_SMALL - not enough memory to move buffer +// +//---------------------------------------------------------------------------- +// +EFI_STATUS FindFreeBuffer( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr, + IN UINTN RequiredSize, + IN OUT VOID **BaseAddress, + IN UINTN AvailableSize, + IN BOOLEAN FromTop +) +{ + EFI_STATUS Status; + MEMORY_BLOCK FreeMemory; + MEMORY_BLOCK RequiredMemory; + MEMORY_BLOCK Unmovable; + + FreeMemory.Address = (UINT32)(UINTN)(*BaseAddress); + FreeMemory.Size = AvailableSize; + + RequiredMemory.Size = RequiredSize; + + if(FromTop) { +/* start looking for available space from the top of available buffer */ + RequiredMemory.Address = FreeMemory.Address; + } else { +/* start looking for available space from the bottom of available buffer */ + RequiredMemory.Address = AvailableSize - RequiredSize; + } + + do { + /* First check if we overlapped with mailbox itself */ + Unmovable.Address = (UINT32)Ptr; + Unmovable.Size = sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR); + Status = AdjustBuffer(&FreeMemory, &Unmovable, &RequiredMemory, FromTop); + if(EFI_ERROR(Status)) + return Status; + + if(Ptr->Length != 0) { + /* Now check if we overlapped with DataBlock */ + Unmovable.Address = (UINT32)(Ptr->DataBlock); + Unmovable.Size = (UINT32)(Ptr->Length); + Status = AdjustBuffer(&FreeMemory, &Unmovable, &RequiredMemory, FromTop); + Ptr++; + } else if (Ptr->DataBlock != NULL) { + Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)(Ptr->ContinuationPointer); + } else { + break; //we've reached end of mailbox + } + } while (!EFI_ERROR(Status)); + + if(!EFI_ERROR(Status)) { + *BaseAddress = (VOID *)(UINTN)RequiredMemory.Address; + } + + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: CoalesceCapsule +// +// Description: +// This function coalesces capsule from mailbox to continuous block of memory +// +// Input: +// IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr - pointer to capsule mailbox +// IN VOID *Start - pointer to start of continuous block of memory +// IN UINTN Size - size of continuous block of memory +// +// Output: +// None +// +//---------------------------------------------------------------------------- +// +VOID CoalesceCapsule( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr, + IN VOID *Start, + IN UINTN Size +) +{ + UINT8 *Walker = (UINT8 *)Start; + UINT64 Stop = 0; + + do { + if(Ptr->Length != 0) { + MemCpy(Walker, (VOID *)(UINTN)(Ptr->DataBlock), (UINTN)Ptr->Length); + Walker += Ptr->Length; + Stop += Ptr->Length; + Ptr++; + } else if(Ptr->DataBlock != NULL) { + Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)(Ptr->ContinuationPointer); + } else { + break; //we've reached end of mailbox + } + } while (Stop <= Size); +} + +// +//---------------------------------------------------------------------------- +// Procedure: SaveCapsulePointers +// +// Description: +// This function relocates and reformats capsule mailbox for further processing +// +// Input: +// IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr - pointer to capsule mailbox +// IN UINTN ArraySize - size of array to store capsule mailbox pointers +// OUT CAPSULE_BLOCK *Array - pointer where to store capsule mailbox pointers +// +// Output: +// None +// +//---------------------------------------------------------------------------- +// +VOID SaveCapsulePointers( + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr, + IN UINTN ArraySize, + OUT CAPSULE_BLOCK *Array +) +{ + UINTN i = 0; + do { + if(Ptr->Length != 0) { + Array[i].OriginalAddress = (UINT32)Ptr->DataBlock; + Array[i].Size = (UINT32)Ptr->Length; + Array[i].RelocatedAddress = 0; + Array[i].Attributes = 0; + i++; + Ptr++; + } else if(Ptr->DataBlock != NULL) { + Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)(Ptr->ContinuationPointer); + } else { + break; + } + } while(i <= ArraySize); +} + +// +//---------------------------------------------------------------------------- +// Procedure: FindOverlaps +// +// Description: +// This function checks if given memory block overlaps with other blocks of capsule +// +// Input: +// IN CAPSULE_BLOCK *Array - pointer to capsule blocks array +// IN UINTN ArraySize - size of array of capsule blocks +// IN MEMORY_BLOCK *Probe - pointer to memory block to check against +// +// Output: +// UINTN - number of overlaps found or 0 if there are no overlaps +// +//---------------------------------------------------------------------------- +// +UINTN FindOverlaps( + IN CAPSULE_BLOCK *Array, + IN UINTN ArraySize, + IN MEMORY_BLOCK *Probe +) +{ + UINTN i; + MEMORY_BLOCK Unmovable; + UINTN Overlap = 0; + + for(i = 0; i < ArraySize; i++) { + if(Array[i].Attributes & CAPSULE_BLOCK_PROCESSING || + Array[i].Attributes & CAPSULE_BLOCK_DONE) + continue; + + Unmovable.Address = (Array[i].Attributes & CAPSULE_BLOCK_RELOCATED) ? + Array[i].RelocatedAddress : Array[i].OriginalAddress; + Unmovable.Size = Array[i].Size; + if(BufferOverlap(&Unmovable, Probe)) { + Overlap++; + Array[i].Attributes |= CAPSULE_BLOCK_OVERLAPPING; + } + } + return Overlap; +} + +// +//---------------------------------------------------------------------------- +// Procedure: FindFreeBufferEx +// +// Description: +// This function searches for continuous memory block in free range, and if not found +// in already processed capsule blocks +// +// Input: +// IN CAPSULE_BLOCK *Array - pointer to capsule blocks array +// IN UINTN ArraySize - size of array of capsule blocks +// IN MEMORY_BLOCK *Available - available memory block parameters +// IN MEMORY_BLOCK *Reserved - occupied memory block parameters +// IN OUT MEMORY_BLOCK *Free - parameters for block that requires allocation +// +// Output: +// EFI_SUCCESS - block relocated successfully +// EFI_BUFFER_TOO_SMALL - not enough memory to perform operation +// +//---------------------------------------------------------------------------- +// +EFI_STATUS FindFreeBufferEx( + IN CAPSULE_BLOCK *Array, + IN UINTN ArraySize, + IN MEMORY_BLOCK *Available, + IN MEMORY_BLOCK *Reserved, + IN OUT MEMORY_BLOCK *Free +) +{ + UINTN i; + MEMORY_BLOCK Unmovable; + EFI_STATUS Status; + + Free->Address = Available->Address; + + for(i = 0; i < ArraySize; i++) { + if(Array[i].Attributes & CAPSULE_BLOCK_PROCESSING || + Array[i].Attributes & CAPSULE_BLOCK_DONE) + continue; + + Unmovable.Address = (Array[i].Attributes & CAPSULE_BLOCK_RELOCATED) ? + Array[i].RelocatedAddress : Array[i].OriginalAddress; + Unmovable.Size = Array[i].Size; + Status = AdjustBuffer(Available, &Unmovable, Free, TRUE); + if(EFI_ERROR(Status)) + break; + } + + if(!EFI_ERROR(Status)) { + return Status; //buffer found + } +/* try to find free space in previously processed chunks */ + for(i = 0; i < ArraySize; i++) { + if(Array[i].Attributes & CAPSULE_BLOCK_PROCESSING || Free->Size > Array[i].Size) + continue; + + if(Array[i].Attributes & CAPSULE_BLOCK_DONE && + !(Array[i].Attributes & CAPSULE_BLOCK_RELOCATED) ) { + /* if chunk was processed but not relocated, original address may be free */ + Free->Address = Array[i].OriginalAddress; + if(!BufferOverlap(Free, Reserved)) { + return EFI_SUCCESS; + } + } + } + return EFI_BUFFER_TOO_SMALL; +} + +// +//---------------------------------------------------------------------------- +// Procedure: RelocateOverlaps +// +// Description: +// This function moves capsule blocks that overlap with reserved block +// +// Input: +// IN CAPSULE_BLOCK *Array - pointer to capsule blocks array +// IN UINTN ArraySize - size of array of capsule blocks +// IN MEMORY_BLOCK *Available - available memory block parameters +// IN MEMORY_BLOCK *Reserved - occupied memory block parameters +// +// Output: +// EFI_SUCCESS - block relocated successfully +// EFI_BUFFER_TOO_SMALL - not enough memory to perform operation +// +//---------------------------------------------------------------------------- +// +EFI_STATUS RelocateOverlaps( + IN CAPSULE_BLOCK *Array, + IN UINTN ArraySize, + IN MEMORY_BLOCK *Available, + IN MEMORY_BLOCK *Reserved +) +{ + UINTN i; + MEMORY_BLOCK Free; + VOID *Source; + EFI_STATUS Status; + + for(i = 0; i < ArraySize; i++) { + if(!(Array[i].Attributes & CAPSULE_BLOCK_OVERLAPPING)) + continue; + + Free.Size = Array[i].Size; + Status = FindFreeBufferEx(Array, ArraySize, Available, Reserved, &Free); + if(EFI_ERROR(Status)) + return Status; + + Source = (Array[i].Attributes & CAPSULE_BLOCK_RELOCATED) ? + (VOID *)Array[i].RelocatedAddress : (VOID *)Array[i].OriginalAddress; + MemCpy((VOID *)(Free.Address), Source, Array[i].Size); + Array[i].Attributes |= CAPSULE_BLOCK_RELOCATED; + Array[i].Attributes &= ~CAPSULE_BLOCK_OVERLAPPING; + Array[i].RelocatedAddress = Free.Address; + } + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// Procedure: CoalesceCapsuleByParts +// +// Description: +// This function coalesces capsule from capsule blocks +// +// Input: +// IN CAPSULE_BLOCK *Array - pointer to capsule blocks array +// IN UINTN ArraySize - size of array of capsule blocks +// IN VOID *Buffer - pointer to start of continuous block of memory +// IN UINTN BufferSize - size of continuous block of memory +// +// Output: +// EFI_SUCCESS - block relocated successfully +// EFI_BUFFER_TOO_SMALL - not enough memory to perform operation +// +//---------------------------------------------------------------------------- +// +EFI_STATUS CoalesceCapsuleByParts( + IN CAPSULE_BLOCK *Array, + IN UINTN ArraySize, + IN VOID *Buffer, + IN UINTN BufferSize +) +{ + UINTN i; + UINTN Overlap; + VOID *Source; + EFI_STATUS Status; + MEMORY_BLOCK Available; + MEMORY_BLOCK Reserved; + MEMORY_BLOCK Current; + + Current.Address = (UINT32)Buffer; + Reserved.Address = Current.Address; + Reserved.Size = 0; + Available.Size = BufferSize; + + for(i = 0; i < ArraySize; i++) { + Array[i].Attributes |= CAPSULE_BLOCK_PROCESSING; + Current.Size = Array[i].Size; + Available.Address = Current.Address + Current.Size; + Available.Size -= Array[i].Size; //reserve space + Reserved.Size += Array[i].Size; + Overlap = FindOverlaps(Array, ArraySize, &Current); + if(Overlap > 0) { + Status = RelocateOverlaps(Array, ArraySize, &Available, &Reserved); + if(EFI_ERROR(Status)) + return Status; + } + + Source = (Array[i].Attributes & CAPSULE_BLOCK_RELOCATED) ? + (VOID *)(Array[i].RelocatedAddress) : (VOID *)(Array[i].OriginalAddress); + MemCpy((VOID *)(Current.Address), Source, Array[i].Size); + Current.Address += Array[i].Size; + Array[i].Attributes &= ~CAPSULE_BLOCK_PROCESSING; + Array[i].Attributes |= CAPSULE_BLOCK_DONE; + } + + return EFI_SUCCESS; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2012, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** \ No newline at end of file -- cgit v1.2.3