mirror of https://review.coreboot.org/STM.git
273 lines
8.0 KiB
C
273 lines
8.0 KiB
C
/** @file
|
|
STM memory management
|
|
|
|
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php.
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "StmInit.h"
|
|
#include "PeStm.h"
|
|
|
|
void HeapList(int id);
|
|
//#define HEAPCHECK
|
|
|
|
/**
|
|
|
|
This function allocate pages in MSEG.
|
|
|
|
@param Pages the requested pages number
|
|
|
|
@return pages address
|
|
|
|
**/
|
|
|
|
VOID *
|
|
AllocatePages (
|
|
IN UINTN Pages
|
|
)
|
|
{
|
|
UINT64 Address;
|
|
HEAP_HEADER * BlockHeader;
|
|
HEAP_HEADER * PrevBlock;
|
|
HEAP_HEADER * NewBlock;
|
|
BOOLEAN foundBlock;
|
|
BOOLEAN endList;
|
|
|
|
// implements a first fit algorithm
|
|
|
|
// find the first block that fits
|
|
|
|
AcquireSpinLock (&mHostContextCommon.MemoryLock);
|
|
|
|
Address = mHostContextCommon.HeapFree; // get begining of freelist
|
|
|
|
PrevBlock = (HEAP_HEADER *) NULL;
|
|
BlockHeader = (HEAP_HEADER *)(UINTN)Address;
|
|
|
|
foundBlock = FALSE;
|
|
if(BlockHeader == 0)
|
|
{
|
|
endList = TRUE; // we are totally out of space
|
|
}
|
|
else
|
|
{
|
|
endList = FALSE;
|
|
}
|
|
while(!endList)
|
|
{
|
|
if(BlockHeader->BlockLength >= Pages)
|
|
{
|
|
foundBlock = TRUE;
|
|
Address = (UINT64) (UINTN) BlockHeader; // begining of block to return
|
|
break;
|
|
}
|
|
|
|
if(BlockHeader->NextBlock == 0)
|
|
{
|
|
endList = TRUE;
|
|
break;
|
|
}
|
|
PrevBlock = BlockHeader; // remember the previous block;
|
|
BlockHeader = BlockHeader->NextBlock;
|
|
}
|
|
|
|
if(endList)
|
|
{
|
|
DEBUG((EFI_D_ERROR, "AllocatePages(0x%x) fail - no freeblock of the correct size\n", Pages));
|
|
#ifdef HEAPCHECK
|
|
// ReleaseSpinLock (&mHostContextCommon.MemoryLock);
|
|
HeapList(1);
|
|
#endif
|
|
ReleaseSpinLock (&mHostContextCommon.MemoryLock);
|
|
return NULL;
|
|
}
|
|
|
|
// found a block that fits - now need to make adjustments
|
|
|
|
// cases 1 - first in list == change HeapFree
|
|
// 2 - middle of list == change previous pointer
|
|
// 3 - released block at end of list == change previous pointer
|
|
// subcases - block is completely consumed - need to change pointer in previous block
|
|
// - block has leftover space
|
|
|
|
//if (mHostContextCommon.HeapBottom + STM_PAGES_TO_SIZE(Pages) > mHostContextCommon.HeapTop) {
|
|
// DEBUG ((EFI_D_ERROR, "AllocatePages(%x) fail\n", Pages));
|
|
// ReleaseSpinLock (&mHostContextCommon.MemoryLock);
|
|
// //CpuDeadLoop ();
|
|
// return NULL;
|
|
//}
|
|
|
|
// (1) breakup block (if necessary)
|
|
// (2) point HeapFree to the new block (or to the next block in the event the current block is consumed
|
|
|
|
if(BlockHeader->BlockLength == Pages)
|
|
{
|
|
NewBlock = (BlockHeader->NextBlock); // get next block in the list
|
|
}
|
|
else // need to break the block up
|
|
{
|
|
NewBlock = (HEAP_HEADER *)(UINTN)(Address + ((UINT64)(UINTN)STM_PAGES_TO_SIZE(Pages))); // second half of block
|
|
NewBlock->NextBlock = BlockHeader->NextBlock;
|
|
NewBlock->BlockLength = BlockHeader->BlockLength - Pages;
|
|
}
|
|
|
|
if(BlockHeader == (HEAP_HEADER *)(UINTN) mHostContextCommon.HeapFree)
|
|
{
|
|
mHostContextCommon.HeapFree = (UINT64) NewBlock;
|
|
}
|
|
else
|
|
{
|
|
PrevBlock->NextBlock = NewBlock;
|
|
}
|
|
|
|
//Address = mHostContextCommon.HeapTop - STM_PAGES_TO_SIZE(Pages);
|
|
//mHostContextCommon.HeapTop = Address;
|
|
#ifdef HEAPCHECK
|
|
HeapList(2);
|
|
#endif
|
|
ReleaseSpinLock (&mHostContextCommon.MemoryLock);
|
|
ZeroMem ((VOID *)(UINTN)Address, STM_PAGES_TO_SIZE (Pages));
|
|
#ifdef HEAPCHECK
|
|
DEBUG((EFI_D_ERROR, "****Allocating 0x%x pages at 0x%016llx - %d Cleared\n", Pages, Address, STM_PAGES_TO_SIZE (Pages)));
|
|
#endif
|
|
return (VOID *)(UINTN)Address;
|
|
}
|
|
|
|
/**
|
|
|
|
This function free pages in MSEG.
|
|
|
|
@param Address pages address
|
|
@param Pages pages number
|
|
|
|
**/
|
|
VOID
|
|
FreePages (
|
|
IN VOID *Address,
|
|
IN UINTN Pages
|
|
)
|
|
{
|
|
HEAP_HEADER * CurrentBlock;
|
|
HEAP_HEADER * PreviousBlock;
|
|
#ifdef HEAPCHECK
|
|
DEBUG((EFI_D_ERROR, "****Freeing 0x%x pages at 0x%016llx\n", Pages, (UINTN) Address));
|
|
#endif
|
|
AcquireSpinLock (&mHostContextCommon.MemoryLock);
|
|
|
|
// (1) Set header
|
|
// (2) find place in buffer chain
|
|
// (3) coalese(sp?)
|
|
|
|
Address = (void *)((UINTN) Address & ~0xfff); // mask out the lower 12 bits
|
|
|
|
((HEAP_HEADER *)Address)->NextBlock = 0L;
|
|
((HEAP_HEADER *)Address)->BlockLength = Pages;
|
|
|
|
#ifdef HEAPCHECK
|
|
DEBUG((EFI_D_ERROR, "Address->NextBlock: 0x%016llx Address->BlockLength: 0x%016llx\n",
|
|
((HEAP_HEADER *)Address)->NextBlock,
|
|
((HEAP_HEADER *)Address)->BlockLength));
|
|
#endif
|
|
PreviousBlock = 0L;
|
|
CurrentBlock = (HEAP_HEADER *)(UINTN) mHostContextCommon.HeapFree;
|
|
|
|
// find where it belongs
|
|
while( CurrentBlock != 0L)
|
|
{
|
|
if((UINTN)CurrentBlock > (UINTN)Address)
|
|
{
|
|
break;
|
|
}
|
|
|
|
PreviousBlock = CurrentBlock;
|
|
CurrentBlock = CurrentBlock->NextBlock;
|
|
}
|
|
|
|
//link it in
|
|
if(PreviousBlock == 0L)
|
|
{
|
|
// at beginning of list
|
|
((HEAP_HEADER *)Address)->NextBlock = CurrentBlock;
|
|
mHostContextCommon.HeapFree = (UINT64)Address;
|
|
}
|
|
else
|
|
{
|
|
// somewhere in list
|
|
((HEAP_HEADER *)Address)->NextBlock = CurrentBlock;
|
|
PreviousBlock->NextBlock = (HEAP_HEADER *)Address;
|
|
}
|
|
#ifdef HEAPCHECK
|
|
DEBUG((EFI_D_ERROR, "Address->NextBlock: 0x%016llx Address->BlockLength: 0x%016llx\n",
|
|
((HEAP_HEADER *)Address)->NextBlock,
|
|
((HEAP_HEADER *)Address)->BlockLength));
|
|
#endif
|
|
// coalesce
|
|
|
|
// First check the block after
|
|
if(CurrentBlock != 0L)
|
|
{
|
|
if(((UINT64)Address + STM_PAGES_TO_SIZE(Pages)) == (UINT64)(UINTN)CurrentBlock)
|
|
{
|
|
#ifdef HEAPCHECK
|
|
DEBUG((EFI_D_ERROR, "Combined with block after\n"));
|
|
#endif
|
|
((HEAP_HEADER *)Address)->NextBlock = CurrentBlock->NextBlock;
|
|
((HEAP_HEADER *)Address)->BlockLength = ((HEAP_HEADER *)Address)->BlockLength + CurrentBlock->BlockLength;
|
|
#ifdef HEAPCHECK
|
|
DEBUG((EFI_D_ERROR, "Address->NextBlock: 0x%016llx Address->BlockLength: 0x%016llx\n",
|
|
((HEAP_HEADER *)Address)->NextBlock,
|
|
((HEAP_HEADER *)Address)->BlockLength));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// then then block before
|
|
if(PreviousBlock != 0L)
|
|
{
|
|
if(((UINT64)PreviousBlock + STM_PAGES_TO_SIZE((UINT64)PreviousBlock->BlockLength)) == (UINT64)Address)
|
|
{
|
|
#ifdef HEAPCHECK
|
|
DEBUG((EFI_D_ERROR, "Combined with block before\n"));
|
|
|
|
DEBUG((EFI_D_ERROR, "PreviousBlock: 0x%016llx BlockLength: 0x%016llx Add: 0x%016llx\n",
|
|
PreviousBlock,
|
|
STM_PAGES_TO_SIZE((UINT64)PreviousBlock->BlockLength),
|
|
((HEAP_HEADER*) Address)));
|
|
#endif
|
|
PreviousBlock->NextBlock = ((HEAP_HEADER *)Address)->NextBlock;
|
|
PreviousBlock->BlockLength += ((HEAP_HEADER *) Address)->BlockLength;
|
|
}
|
|
}
|
|
|
|
// if ((UINT64)(UINTN)Address == mHostContextCommon.HeapTop) {
|
|
// mHostContextCommon.HeapTop += STM_PAGES_TO_SIZE(Pages);
|
|
// }
|
|
#ifdef HEAPCHECK
|
|
HeapList(3);
|
|
#endif
|
|
ReleaseSpinLock (&mHostContextCommon.MemoryLock);
|
|
return ;
|
|
}
|
|
|
|
void HeapList(int id)
|
|
{
|
|
HEAP_HEADER * CurrentBlock = (HEAP_HEADER *)(UINTN) mHostContextCommon.HeapFree;
|
|
|
|
DEBUG((EFI_D_ERROR, " ***HeapList %d Start***\n", id));
|
|
|
|
while(CurrentBlock != 0L)
|
|
{
|
|
DEBUG((EFI_D_ERROR, " Block: 0x%llx BlockLength: 0x%x NextBlock: 0x%llx\n", CurrentBlock, CurrentBlock->BlockLength, CurrentBlock->NextBlock));
|
|
CurrentBlock = CurrentBlock->NextBlock;
|
|
}
|
|
|
|
DEBUG((EFI_D_ERROR, " ***HeapList %d Done***\n", id));
|
|
}
|