mirror of
https://github.com/reactos/reactos.git
synced 2024-09-10 21:04:26 +00:00
717 lines
20 KiB
C
717 lines
20 KiB
C
/*
|
|
* COPYRIGHT: See COPYING.ARM in the top level directory
|
|
* PROJECT: ReactOS UEFI Boot Library
|
|
* FILE: boot/environ/lib/mm/heapalloc.c
|
|
* PURPOSE: Boot Library Memory Manager Heap Allocator
|
|
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include "bl.h"
|
|
|
|
/* DATA VARIABLES ************************************************************/
|
|
|
|
#define BL_HEAP_POINTER_FLAG_BITS 3
|
|
|
|
typedef struct _BL_HEAP_POINTER
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
ULONG_PTR BufferFree : 1;
|
|
ULONG_PTR BufferOnHeap : 1;
|
|
ULONG_PTR NotUsed : 1;
|
|
ULONG_PTR BufferPointer : ((8 * sizeof(ULONG_PTR)) - BL_HEAP_POINTER_FLAG_BITS);
|
|
};
|
|
PVOID P;
|
|
};
|
|
} BL_HEAP_POINTER, *PBL_HEAP_POINTER;
|
|
|
|
typedef struct _BL_FREE_HEAP_ENTRY
|
|
{
|
|
BL_HEAP_POINTER BufferNext;
|
|
BL_HEAP_POINTER BufferPrevious;
|
|
BL_HEAP_POINTER FreeNext;
|
|
BL_HEAP_POINTER FreePrevious;
|
|
} BL_FREE_HEAP_ENTRY, *PBL_FREE_HEAP_ENTRY;
|
|
|
|
typedef struct _BL_BUSY_HEAP_ENTRY
|
|
{
|
|
BL_HEAP_POINTER BufferNext;
|
|
BL_HEAP_POINTER BufferPrevious;
|
|
UCHAR Buffer[ANYSIZE_ARRAY];
|
|
} BL_BUSY_HEAP_ENTRY, *PBL_BUSY_HEAP_ENTRY;
|
|
|
|
typedef struct _BL_HEAP_BOUNDARIES
|
|
{
|
|
LIST_ENTRY ListEntry;
|
|
ULONG_PTR HeapEnd;
|
|
ULONG_PTR HeapLimit;
|
|
ULONG_PTR HeapBase;
|
|
PBL_BUSY_HEAP_ENTRY HeapStart;
|
|
} BL_HEAP_BOUNDARIES, *PBL_HEAP_BOUNDARIES;
|
|
|
|
ULONG HapInitializationStatus;
|
|
LIST_ENTRY MmHeapBoundaries;
|
|
ULONG HapMinimumHeapSize;
|
|
ULONG HapAllocationAttributes;
|
|
PBL_FREE_HEAP_ENTRY* MmFreeList;
|
|
|
|
/* INLINES *******************************************************************/
|
|
|
|
FORCEINLINE
|
|
PBL_FREE_HEAP_ENTRY
|
|
MmHapDecodeLink (
|
|
_In_ BL_HEAP_POINTER Link
|
|
)
|
|
{
|
|
/* Decode the buffer pointer by ignoring the flags */
|
|
return (PBL_FREE_HEAP_ENTRY)(Link.BufferPointer << BL_HEAP_POINTER_FLAG_BITS);
|
|
}
|
|
|
|
FORCEINLINE
|
|
ULONG
|
|
MmHapBufferSize (
|
|
_In_ PVOID FreeEntry
|
|
)
|
|
{
|
|
PBL_FREE_HEAP_ENTRY Entry = FreeEntry;
|
|
|
|
/* The space between the next buffer header and this one is the size */
|
|
return (ULONG_PTR)MmHapDecodeLink(Entry->BufferNext) - (ULONG_PTR)Entry;
|
|
}
|
|
|
|
FORCEINLINE
|
|
ULONG
|
|
MmHapUserBufferSize (
|
|
_In_ PVOID FreeEntry
|
|
)
|
|
{
|
|
PBL_FREE_HEAP_ENTRY Entry = FreeEntry;
|
|
|
|
/* Get the size of the buffer as the user sees it */
|
|
return MmHapBufferSize(Entry) - FIELD_OFFSET(BL_BUSY_HEAP_ENTRY, Buffer);
|
|
}
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
NTSTATUS
|
|
MmHapHeapAllocatorExtend (
|
|
_In_ ULONG ExtendSize
|
|
)
|
|
{
|
|
ULONG HeapSize, AlignedSize, HeapLimit;
|
|
PBL_HEAP_BOUNDARIES Heap, NewHeap;
|
|
NTSTATUS Status;
|
|
PBL_BUSY_HEAP_ENTRY HeapBase = NULL;
|
|
|
|
/* Compute a new heap, and add 2 more pages for the free list */
|
|
HeapSize = ExtendSize + (2 * PAGE_SIZE);
|
|
if (HeapSize < ExtendSize)
|
|
{
|
|
return STATUS_INTEGER_OVERFLOW;
|
|
}
|
|
|
|
/* Make sure the new heap is at least the minimum configured size */
|
|
if (HapMinimumHeapSize > HeapSize)
|
|
{
|
|
HeapSize = HapMinimumHeapSize;
|
|
}
|
|
|
|
/* Align it on a page boundary */
|
|
AlignedSize = ALIGN_UP_BY(HeapSize, PAGE_SIZE);
|
|
if (!AlignedSize)
|
|
{
|
|
return STATUS_INTEGER_OVERFLOW;
|
|
}
|
|
|
|
/* Check if we already have a heap */
|
|
if (!IsListEmpty(&MmHeapBoundaries))
|
|
{
|
|
/* Find the first heap*/
|
|
Heap = CONTAINING_RECORD(MmHeapBoundaries.Flink,
|
|
BL_HEAP_BOUNDARIES,
|
|
ListEntry);
|
|
|
|
/* Check if we have a page free above the heap */
|
|
HeapLimit = Heap->HeapLimit + PAGE_SIZE;
|
|
if (HeapLimit <= Heap->HeapEnd)
|
|
{
|
|
EfiPrintf(L"Heap extension TODO\r\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
/* We do not -- allocate one */
|
|
Status = MmPapAllocatePagesInRange((PVOID*)&HeapBase,
|
|
BlLoaderHeap,
|
|
AlignedSize >> PAGE_SHIFT,
|
|
HapAllocationAttributes,
|
|
0,
|
|
NULL,
|
|
0);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
EfiPrintf(L"HEAP ALLOCATION FAILED\r\n");
|
|
EfiStall(1000000);
|
|
return Status;
|
|
}
|
|
|
|
/* Set the heap bottom, limit, and top */
|
|
NewHeap = (PBL_HEAP_BOUNDARIES)HeapBase->Buffer;
|
|
NewHeap->HeapBase = (ULONG_PTR)HeapBase;
|
|
NewHeap->HeapLimit = (ULONG_PTR)HeapBase + AlignedSize;
|
|
NewHeap->HeapStart = (PBL_BUSY_HEAP_ENTRY)(NewHeap + 1);
|
|
|
|
/* Set the buffer links */
|
|
HeapBase->BufferPrevious.P = NULL;
|
|
HeapBase->BufferNext.P = NewHeap->HeapStart;
|
|
|
|
/* Set the buffer at the top of the heap and mark it as being free */
|
|
NewHeap->HeapStart->BufferPrevious.P = HeapBase;
|
|
NewHeap->HeapStart->BufferNext.P = NewHeap->HeapStart;
|
|
NewHeap->HeapStart->BufferNext.BufferFree = 1;
|
|
NewHeap->HeapStart->BufferNext.BufferOnHeap = 1;
|
|
|
|
/* Is this the first heap ever? */
|
|
if (IsListEmpty(&MmHeapBoundaries))
|
|
{
|
|
/* We will host the free list at the top of the heap */
|
|
MmFreeList = (PBL_FREE_HEAP_ENTRY*)((ULONG_PTR)NewHeap->HeapLimit - 8 * sizeof(PBL_FREE_HEAP_ENTRY));
|
|
NewHeap->HeapLimit = (ULONG_PTR)MmFreeList;
|
|
RtlZeroMemory(MmFreeList, 8 * sizeof(PBL_FREE_HEAP_ENTRY));
|
|
}
|
|
|
|
/* Remove a page on top */
|
|
HeapLimit = NewHeap->HeapLimit;
|
|
NewHeap->HeapEnd = NewHeap->HeapLimit;
|
|
NewHeap->HeapLimit -= PAGE_SIZE;
|
|
|
|
/* Add us into the heap list */
|
|
InsertTailList(&MmHeapBoundaries, &NewHeap->ListEntry);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
MmHapGetBucketId (
|
|
_In_ ULONG Size
|
|
)
|
|
{
|
|
ULONG BucketIndex = 0;
|
|
|
|
/* Use the last bucket if this is a large allocation */
|
|
if (Size >= PAGE_SIZE)
|
|
{
|
|
return 7;
|
|
}
|
|
|
|
/* Otherwise, use a higher index for each new power of two */
|
|
while (Size >> BucketIndex)
|
|
{
|
|
BucketIndex++;
|
|
}
|
|
|
|
/* Allocations are at least 16 bytes (2^4 = 5th index) */
|
|
return BucketIndex - 5;
|
|
}
|
|
|
|
VOID
|
|
MmHapReportHeapCorruption (
|
|
_In_ PBL_FREE_HEAP_ENTRY BufferEntry
|
|
)
|
|
{
|
|
#if 0
|
|
BOOLEAN DebuggerEnabled;
|
|
|
|
BlStatusPrint(L"Heap corruption in the links surrounding %p!\r\n", BufferEntry);
|
|
|
|
DebuggerEnabled = BlBdDebuggerEnabled();
|
|
if (DebuggerEnabled)
|
|
{
|
|
BlStatusPrint(L"\n*** Fatal Error 0x%08x :\n (0x%p, 0x%p, 0x%p, 0x%p)\n\r\n", 2, BufferEntry, NULL, NULL, NULL);
|
|
__debugbreak();
|
|
}
|
|
#else
|
|
EfiPrintf(L"Heap corruption in the links surrounding %p!\r\n", BufferEntry);
|
|
#endif
|
|
}
|
|
|
|
PVOID
|
|
MmHapCheckFreeLinks (
|
|
_In_ PVOID BufferEntry
|
|
)
|
|
{
|
|
PBL_FREE_HEAP_ENTRY Prev, Next;
|
|
PBL_FREE_HEAP_ENTRY Entry = BufferEntry;
|
|
|
|
/* Get the previous and next free pointers */
|
|
Prev = MmHapDecodeLink(Entry->FreePrevious);
|
|
Next = MmHapDecodeLink(Entry->FreeNext);
|
|
|
|
/* Make sure that both the previous and next entries point to this one */
|
|
if (((Next) && (MmHapDecodeLink(Next->FreePrevious)) != Entry) ||
|
|
((Prev) && (MmHapDecodeLink(Prev->FreeNext)) != Entry))
|
|
{
|
|
/* They don't, so the free headers are corrupted */
|
|
MmHapReportHeapCorruption(Entry);
|
|
return NULL;
|
|
}
|
|
|
|
/* They do, return the free entry as valid */
|
|
return Entry;
|
|
}
|
|
|
|
PVOID
|
|
MmHapCheckBufferLinks (
|
|
_In_ PVOID BufferEntry
|
|
)
|
|
{
|
|
PBL_FREE_HEAP_ENTRY Prev, Next;
|
|
PBL_FREE_HEAP_ENTRY Entry = BufferEntry;
|
|
|
|
/* Get the previous and next buffer pointers */
|
|
Prev = MmHapDecodeLink(Entry->BufferPrevious);
|
|
Next = MmHapDecodeLink(Entry->BufferNext);
|
|
|
|
/* Make sure that both the previous and next entries point to this one */
|
|
if (((Next) && (MmHapDecodeLink(Next->BufferPrevious)) != Entry) ||
|
|
((Prev) && (MmHapDecodeLink(Prev->BufferNext)) != Entry))
|
|
{
|
|
/* They don't, so the heap headers are corrupted */
|
|
MmHapReportHeapCorruption(Entry);
|
|
return NULL;
|
|
}
|
|
|
|
/* They, do the entry is valid */
|
|
return Entry;
|
|
}
|
|
|
|
PBL_FREE_HEAP_ENTRY
|
|
MmHapRemoveBufferFromFreeList (
|
|
_In_ PBL_FREE_HEAP_ENTRY FreeEntry
|
|
)
|
|
{
|
|
PBL_FREE_HEAP_ENTRY Prev, Next;
|
|
|
|
/* Firest, make sure the free entry is valid */
|
|
FreeEntry = MmHapCheckFreeLinks(FreeEntry);
|
|
if (!FreeEntry)
|
|
{
|
|
return FreeEntry;
|
|
}
|
|
|
|
/* Get the previous and next entry */
|
|
Prev = MmHapDecodeLink(FreeEntry->FreePrevious);
|
|
Next = MmHapDecodeLink(FreeEntry->FreeNext);
|
|
|
|
/* Update the next entry to point to our previous entry */
|
|
if (Next)
|
|
{
|
|
Next->FreePrevious.P = Prev;
|
|
}
|
|
|
|
/* Are we at the head? */
|
|
if (Prev)
|
|
{
|
|
/* Nope, so update our previous entry to point to our next entry */
|
|
Prev->FreeNext.P = Next;
|
|
}
|
|
else
|
|
{
|
|
/* Yep, so update the appropriate bucket listhead */
|
|
MmFreeList[MmHapGetBucketId(MmHapBufferSize(FreeEntry))] = Prev;
|
|
}
|
|
|
|
/* Return the (now removed) entry */
|
|
return FreeEntry;
|
|
}
|
|
|
|
PBL_FREE_HEAP_ENTRY
|
|
MmHapCoalesceFreeBuffer (
|
|
_In_ PBL_FREE_HEAP_ENTRY FreeEntry
|
|
)
|
|
{
|
|
PBL_FREE_HEAP_ENTRY Prev, Next;
|
|
|
|
/* First make sure that this is a valid buffer entry */
|
|
if (!MmHapCheckBufferLinks(FreeEntry))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Get the next entry and check if it's free */
|
|
Next = MmHapDecodeLink(FreeEntry->BufferNext);
|
|
if (!(Next->BufferNext.BufferOnHeap) && (Next->BufferNext.BufferFree))
|
|
{
|
|
/* Remove the next buffer from the free list since we're coalescing */
|
|
Next = MmHapRemoveBufferFromFreeList(Next);
|
|
if (!Next)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* The forward link of the *new* free buffer should now point to us */
|
|
MmHapDecodeLink(Next->BufferNext)->BufferPrevious.P = FreeEntry;
|
|
|
|
/* Our forward link should point to the *new* free buffer as well */
|
|
FreeEntry->BufferNext.P = MmHapDecodeLink(Next->BufferNext);
|
|
|
|
/* Mark our buffer as free */
|
|
FreeEntry->BufferNext.BufferFree = 1;
|
|
}
|
|
|
|
/* Get the previous entry and check if it's free */
|
|
Prev = MmHapDecodeLink(FreeEntry->BufferPrevious);
|
|
if (!(Prev) || !(Prev->BufferNext.BufferFree))
|
|
{
|
|
return FreeEntry;
|
|
}
|
|
|
|
/* It's free, so remove it */
|
|
Prev = MmHapRemoveBufferFromFreeList(Prev);
|
|
if (!Prev)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* The previous link of our next buffer should now point to our *previous* */
|
|
MmHapDecodeLink(FreeEntry->BufferNext)->BufferPrevious.P = Prev;
|
|
|
|
/* Our previous link should point the next free buffer now */
|
|
Prev->BufferNext.P = MmHapDecodeLink(FreeEntry->BufferNext);
|
|
|
|
/* Set the new freed buffer as the previous buffer, and mark it free */
|
|
FreeEntry = Prev;
|
|
FreeEntry->BufferNext.BufferFree = 1;
|
|
return FreeEntry;
|
|
}
|
|
|
|
PBL_FREE_HEAP_ENTRY
|
|
MmHapAddToFreeList (
|
|
_In_ PBL_BUSY_HEAP_ENTRY Entry,
|
|
_In_ ULONG Flags
|
|
)
|
|
{
|
|
PBL_FREE_HEAP_ENTRY FreeEntry, Head;
|
|
ULONG BucketId;
|
|
BL_LIBRARY_PARAMETERS LocalParameters;
|
|
|
|
/* First, check if the entry is valid */
|
|
Entry = MmHapCheckBufferLinks(Entry);
|
|
if (!Entry)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Check if we should zero the entry */
|
|
LocalParameters = BlpLibraryParameters;
|
|
if ((LocalParameters.LibraryFlags & BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE) &&
|
|
!(Flags))
|
|
{
|
|
/* Yep, zero it out */
|
|
RtlZeroMemory(Entry->Buffer, MmHapUserBufferSize(Entry));
|
|
}
|
|
|
|
/* Now mark the entry as free */
|
|
Entry->BufferNext.BufferFree = 1;
|
|
|
|
/* Now that this buffer is free, try to coalesce it */
|
|
FreeEntry = MmHapCoalesceFreeBuffer((PBL_FREE_HEAP_ENTRY)Entry);
|
|
if (!FreeEntry)
|
|
{
|
|
return FreeEntry;
|
|
}
|
|
|
|
/* Compute the bucket ID for the free list */
|
|
BucketId = MmHapGetBucketId(MmHapBufferSize(Entry));
|
|
|
|
/* Get the current head for this bucket, if one exists */
|
|
Head = MmFreeList ? MmFreeList[BucketId] : NULL;
|
|
|
|
/* Update the head's backlink to point to this newly freed entry */
|
|
if (Head)
|
|
{
|
|
Head->FreePrevious.P = FreeEntry;
|
|
}
|
|
|
|
/* Nobody behind us, the old head in front of us */
|
|
FreeEntry->FreePrevious.P = NULL;
|
|
FreeEntry->FreeNext.P = Head;
|
|
|
|
/* Put us at the head of list now, and return the entry */
|
|
MmFreeList[BucketId] = FreeEntry;
|
|
return FreeEntry;
|
|
}
|
|
|
|
PBL_BUSY_HEAP_ENTRY
|
|
MmHapFindBufferInFreeList (
|
|
_In_ ULONG Size
|
|
)
|
|
{
|
|
PBL_FREE_HEAP_ENTRY FreeEntry = NULL;
|
|
PBL_BUSY_HEAP_ENTRY NextEntry;
|
|
ULONG BucketId;
|
|
|
|
/* Get the appropriate bucket for our size */
|
|
BucketId = MmHapGetBucketId(Size);
|
|
if (BucketId >= 8)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Keep going as long as we don't have a free entry */
|
|
while (!FreeEntry)
|
|
{
|
|
/* Fet the first free entry in this list */
|
|
FreeEntry = MmFreeList ? MmFreeList[BucketId] : NULL;
|
|
|
|
/* Loop as long as there's entries in the list */
|
|
while (FreeEntry)
|
|
{
|
|
/* Can this free entry satisfy our needs? */
|
|
if (MmHapBufferSize(FreeEntry) >= Size)
|
|
{
|
|
/* All good */
|
|
break;
|
|
}
|
|
|
|
/* It cannot, keep going to the next one */
|
|
FreeEntry = MmHapDecodeLink(FreeEntry->FreeNext);
|
|
}
|
|
|
|
/* Try the next list -- have we exhausted all the lists? */
|
|
if (++BucketId >= 8)
|
|
{
|
|
/* Have we not found an entry yet? Fail if so... */
|
|
if (!FreeEntry)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We should have an entry if we're here. Remove it from the free list */
|
|
NT_ASSERT(FreeEntry != NULL);
|
|
FreeEntry = MmHapRemoveBufferFromFreeList(FreeEntry);
|
|
if (!FreeEntry)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Make sure it's not corrupted */
|
|
FreeEntry = MmHapCheckBufferLinks(FreeEntry);
|
|
if (!FreeEntry)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Do we have space for at least another buffer? */
|
|
if ((MmHapBufferSize(FreeEntry) - Size) >= sizeof(BL_FREE_HEAP_ENTRY))
|
|
{
|
|
/* Go to where the new next buffer will start */
|
|
NextEntry = (PBL_BUSY_HEAP_ENTRY)((ULONG_PTR)FreeEntry + Size);
|
|
|
|
/* Make the new next buffer point to the next buffer */
|
|
NextEntry->BufferNext.P = MmHapDecodeLink(FreeEntry->BufferNext);
|
|
|
|
/* Make the old next buffer point back to the new one */
|
|
MmHapDecodeLink(FreeEntry->BufferNext)->BufferPrevious.P = NextEntry;
|
|
|
|
/* Point the new next buffer point back to us */
|
|
NextEntry->BufferPrevious.P = FreeEntry;
|
|
|
|
/* Point us to the new next buffer */
|
|
FreeEntry->BufferNext.P = NextEntry;
|
|
|
|
/* And insert the new next buffer into the free list */
|
|
MmHapAddToFreeList(NextEntry, 1);
|
|
}
|
|
|
|
/* Return the entry, which is now allocated */
|
|
return (PBL_BUSY_HEAP_ENTRY)FreeEntry;
|
|
}
|
|
|
|
NTSTATUS
|
|
MmHaInitialize (
|
|
_In_ ULONG HeapSize,
|
|
_In_ ULONG HeapAttributes
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* No free list to begin with */
|
|
MmFreeList = NULL;
|
|
|
|
/* Configure the minimum heap size and allocation attributes */
|
|
HapMinimumHeapSize = ALIGN_UP_BY(HeapSize, PAGE_SIZE);
|
|
HapAllocationAttributes = HeapAttributes & 0x20000;
|
|
|
|
/* Initialize the heap boundary list */
|
|
InitializeListHead(&MmHeapBoundaries);
|
|
|
|
/* Initialize a heap big enough to handle a one pointer long allocation */
|
|
Status = MmHapHeapAllocatorExtend(sizeof(PVOID));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* The heap is ready! */
|
|
HapInitializationStatus = 1;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Return initialization status */
|
|
return Status;
|
|
}
|
|
|
|
PVOID
|
|
BlMmAllocateHeap (
|
|
_In_ SIZE_T Size
|
|
)
|
|
{
|
|
ULONG BufferSize;
|
|
PBL_HEAP_BOUNDARIES Heap;
|
|
PBL_BUSY_HEAP_ENTRY BusyEntry, FreeEntry, NextEntry;
|
|
|
|
/* Ignore heap allocation if the heap allocator isn't ready yet */
|
|
if (HapInitializationStatus != 1)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Align the buffer size to the minimum size required */
|
|
BufferSize = ALIGN_UP_BY(Size + FIELD_OFFSET(BL_BUSY_HEAP_ENTRY, Buffer),
|
|
FIELD_OFFSET(BL_BUSY_HEAP_ENTRY, Buffer));
|
|
|
|
/* Watch out for overflow */
|
|
if (BufferSize <= Size)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Make sure it's at least big enough to hold a free entry later on */
|
|
if (BufferSize < sizeof(BL_FREE_HEAP_ENTRY))
|
|
{
|
|
BufferSize = sizeof(BL_FREE_HEAP_ENTRY);
|
|
}
|
|
|
|
/* Loop while we try to allocate memory */
|
|
while (1)
|
|
{
|
|
/* Find a free buffer for this allocation */
|
|
BusyEntry = MmHapFindBufferInFreeList(BufferSize);
|
|
if (BusyEntry)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* We couldn't find a free buffer. Do we have any heaps? */
|
|
if (!IsListEmpty(&MmHeapBoundaries))
|
|
{
|
|
/* Get the current heap */
|
|
Heap = CONTAINING_RECORD(MmHeapBoundaries.Flink,
|
|
BL_HEAP_BOUNDARIES,
|
|
ListEntry);
|
|
|
|
/* Check if we have space in the heap page for this allocation? */
|
|
FreeEntry = Heap->HeapStart;
|
|
NextEntry = (PBL_BUSY_HEAP_ENTRY)((ULONG_PTR)FreeEntry + BufferSize);
|
|
|
|
if ((NextEntry >= FreeEntry) &&
|
|
((ULONG_PTR)NextEntry <=
|
|
Heap->HeapLimit - FIELD_OFFSET(BL_BUSY_HEAP_ENTRY, Buffer)))
|
|
{
|
|
/* Update the heap top pointer past this allocation */
|
|
Heap->HeapStart = NextEntry;
|
|
|
|
/* Make this allocation point to the slot */
|
|
FreeEntry->BufferNext.P = Heap->HeapStart;
|
|
|
|
/* And make the free heap entry point back to us */
|
|
Heap->HeapStart->BufferPrevious.P = FreeEntry;
|
|
|
|
/* Mark the heap entry as being free and on the heap */
|
|
Heap->HeapStart->BufferNext.BufferFree = 1;
|
|
Heap->HeapStart->BufferNext.BufferOnHeap = 1;
|
|
|
|
/* The previously freed entry on the heap page is now ours */
|
|
BusyEntry = FreeEntry;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We have no heaps or space on any heap -- extend the heap and retry */
|
|
if (!NT_SUCCESS(MmHapHeapAllocatorExtend(BufferSize)))
|
|
{
|
|
EfiPrintf(L"Heap extension failed!\r\n");
|
|
return NULL;
|
|
}
|
|
|
|
EfiPrintf(L"Heap extended -- trying again\r\n");
|
|
}
|
|
|
|
/* Clear all the bits, marking this entry as allocated */
|
|
BusyEntry->BufferNext.P = MmHapDecodeLink(BusyEntry->BufferNext);
|
|
|
|
/* Return the entry's data buffer */
|
|
//EfiPrintf(L"Returning buffer at 0x%p\r\n", &BusyEntry->Buffer);
|
|
return &BusyEntry->Buffer;
|
|
}
|
|
|
|
NTSTATUS
|
|
BlMmFreeHeap (
|
|
_In_ PVOID Buffer
|
|
)
|
|
{
|
|
PBL_BUSY_HEAP_ENTRY BusyEntry;
|
|
PBL_HEAP_BOUNDARIES Heap;
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
/* If the heap is not initialized, fail */
|
|
if (HapInitializationStatus != 1)
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* Get the heap header */
|
|
//EfiPrintf(L"Freeing entry at: %p\r\n", Buffer);
|
|
if (Buffer)
|
|
{
|
|
/* Don't free heap until we discover the corruption */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
BusyEntry = CONTAINING_RECORD(Buffer, BL_BUSY_HEAP_ENTRY, Buffer);
|
|
|
|
/* Loop all the heaps */
|
|
NextEntry = MmHeapBoundaries.Flink;
|
|
while (NextEntry != &MmHeapBoundaries)
|
|
{
|
|
/* Get the current heap in the list */
|
|
Heap = CONTAINING_RECORD(NextEntry, BL_HEAP_BOUNDARIES, ListEntry);
|
|
|
|
/* Is this entry part of this heap? */
|
|
if (((ULONG_PTR)Heap->HeapBase <= (ULONG_PTR)BusyEntry) &&
|
|
((ULONG_PTR)BusyEntry < (ULONG_PTR)Heap->HeapStart))
|
|
{
|
|
/* Ignore double-free */
|
|
if (BusyEntry->BufferNext.BufferFree)
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* It is -- add it to the free list */
|
|
MmHapAddToFreeList(BusyEntry, 0);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* It isn't, move to the next heap */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
/* The entry is not on any valid heap */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|