#include "precomp.h"
#pragma hdrstop
//
// SEGMENT_HEADER is the header that resides at the beginning of every
// segment of memory managed by this package. For non-growable heaps,
// there is only one segment for the entire heap. For growable heaps,
// segments are created as needed whenever there is not enough free space
// to satisfy an allocation request.
//
typedef struct _SEGMENT_HEADER {
struct _SEGMENT_HEADER *Next;
ULONG Size;
ULONG Spare[ 2 ]; // Make sizeof match granularity
} SEGMENT_HEADER, *PSEGMENT_HEADER;
//
// FREE_HEADER is the header that resides at the beginning of every
// free block of memory managed by this package. All free blocks are
// linked together on a free list rooted in the heap header. The segment
// field of a free header prevents free blocks in different segments from
// being coalesced.
//
typedef struct _FREE_HEADER {
struct _FREE_HEADER *Next;
ULONG Size;
struct _SEGMENT_HEADER *Segment;
ULONG Spare;
} FREE_HEADER, *PFREE_HEADER;
//
// BUSY_HEADER is the header that resides at the beginning of allocated
// block of memory managed by this package. When the block is
// allocated, the Busy structure is valid. The address that the user
// sees actually points to the byte following the header. When the
// block is on the free list, the Free structure is valid.
//
typedef struct _BUSY_HEADER {
struct _SEGMENT_HEADER *Segment;
ULONG Size;
HANDLE HandleValue;
ULONG Spare;
} BUSY_HEADER, *PBUSY_HEADER;
//
// Flags are stored in the low order two bits of the first word of the
// header. This is possible, since all blocks are aligned on 16 byte
// boundaries. To make walking the free list fast, the flag value for
// a free block is zero, so we can use the Next pointer without modification.
//
#define FLAGS_FREE 0x00000000
#define FLAGS_BUSY 0x00000001
#define FLAGS_MASK 0x00000003
//
// All allocations are made as a multiple of ALLOCATION_GRANULARITY.
// The size requested is rounded up to a multiple of the allocation
// granularity. The size of an allocation header is then added and
// that is the amount of memory that is actually allocated.
//
#define ALLOCATION_GRANULARITY 16 // bytes
//
// HEAP_HEADER is the header for a heap. All access to the heap is
// synchronized by the Lock field.
//
typedef struct _HEAP_HEADER {
//
// Heap routines use Length to determine if the heap is valid.
//
ULONG Length;
//
// If the ZeroExtraMemory field is true, then the heap allocation
// logic will zero initialize any extra space at the end of an allocated
// block, due to rounding up to the ALIGNMENT_GRANULARITY amount.
//
BOOLEAN ZeroExtraMemory;
//
// The address of the first valid address at the begining of the
// heap. Used for validating pointers passed to AlFreeHeap
//
PVOID ValidAddress;
//
// The address of the first address of memory beyond the end of the heap
//
PVOID EndAddress;
//
// FreeList is the header for the heap free list.
//
ULONG Spare; // Make free list align on granularity
FREE_HEADER FreeList;
} HEAP_HEADER, *PHEAP_HEADER;
//
// The heap is constructed out of a memory descriptor
// block that is below the descriptor for the loaded program. This block
// also accomodates the loaded program stack. It is essential therefore
// to estimate the stack space requirement for your arc program. (16 pages
// should be enough.) The StackPages and HeapPages are 4K each.
//
#define HEAP_ZERO_EXTRA_MEMORY 0x00000008
//
// Define memory allocation descriptor listhead and heap storage variables.
//
ULONG AlHeapFree;
ULONG AlHeapLimit;
PVOID HeapHandle;
PVOID
AlRtCreateHeap(
IN ULONG Flags,
IN PVOID HeapBase,
IN ULONG Size
)
/*++
Routine Description:
This routine initializes a heap.
Arguments:
Flags - Specifies optional attributes of the heap.
Valid Flags Values:
HEAP_ZERO_EXTRA_MEMORY. to make sure that extra memory passed
in is zeroed out.
HeapBase - if not NULL, this specifies the base address for memory
to use as the heap. If NULL, memory is allocated by these routines.
Size - Size of the block of memory passed in to be used as a heap
Return Value:
PVOID - a pointer to be used in accessing the created heap.
--*/
{
PHEAP_HEADER Heap = NULL;
PFREE_HEADER FreeBlock;
Heap = (PHEAP_HEADER)HeapBase;
Heap->Length = sizeof( HEAP_HEADER );
Heap->ZeroExtraMemory = (BOOLEAN)((Flags & HEAP_ZERO_EXTRA_MEMORY) ? TRUE : FALSE);
Heap->ValidAddress = (PCH)Heap + ((sizeof(*Heap) + (ALLOCATION_GRANULARITY-1)) & ~(ALLOCATION_GRANULARITY-1));
Heap->EndAddress = (PCH)Heap + Size;
//
// Initialize the free list to be a single block that starts immediately
// after the heap header.
//
FreeBlock = (PFREE_HEADER)Heap->ValidAddress;
FreeBlock->Next = NULL;
FreeBlock->Size = (ULONG)Heap->EndAddress -
(ULONG)FreeBlock;
FreeBlock->Segment = NULL;
Heap->FreeList.Next = FreeBlock;
Heap->FreeList.Size = 0;
Heap->FreeList.Segment = NULL;
return( (PVOID)Heap );
} // AlRtCreateHeap
#if DBG
BOOLEAN
DumpHeapSegment(
BOOLEAN DumpHeap,
PHEAP_HEADER Heap,
PVOID FirstValidBlock,
PVOID FirstInvalidBlock,
PULONG CountOfFreeBlocks
)
{
PVOID CurrentBlock = FirstValidBlock;
PFREE_HEADER FreeBlock;
PBUSY_HEADER BusyBlock;
while (CurrentBlock < FirstInvalidBlock) {
BusyBlock = CurrentBlock;
FreeBlock = CurrentBlock;
if (((ULONG)BusyBlock->Segment & FLAGS_MASK) == FLAGS_BUSY) {
if (DumpHeap) {
AlPrint( " %08lx: BUSY Flags=%lx Size: %lx Segment: %lx\n",
BusyBlock,
(ULONG)BusyBlock->Segment & FLAGS_MASK,
BusyBlock->Size,
(ULONG)BusyBlock->Segment & ~FLAGS_MASK
);
}
CurrentBlock = (PCH)CurrentBlock + BusyBlock->Size;
}
else
if (((ULONG)FreeBlock->Next & FLAGS_MASK) == FLAGS_FREE) {
*CountOfFreeBlocks += 1;
if (DumpHeap) {
AlPrint( " %08lx: FREE Next=%lx Size: %lx Segment: %lx\n",
FreeBlock,
FreeBlock->Next,
FreeBlock->Size,
FreeBlock->Segment
);
}
CurrentBlock = (PCH)CurrentBlock + FreeBlock->Size;
}
else {
if (DumpHeap) {
AlPrint( "*** Invalid heap block at %lx\n", CurrentBlock );
}
return( FALSE );
}
}
if (CurrentBlock != FirstInvalidBlock) {
if (DumpHeap) {
AlPrint( "*** Heap segment ends at %lx instead of %lx\n",
CurrentBlock, FirstInvalidBlock
);
}
return( FALSE );
}
return( TRUE );
}
BOOLEAN
AlRtValidateHeap(
IN PVOID HeapHandle,
IN BOOLEAN DumpHeap
)
{
PHEAP_HEADER Heap = (PHEAP_HEADER)HeapHandle;
PFREE_HEADER FreeBlock;
BOOLEAN HeapValid = TRUE;
ULONG LengthOfFreeList;
ULONG CountOfFreeBlocks;
//
// Validate that HeapAddress points to a HEAP_HEADER structure.
//
if (Heap->Length != sizeof( HEAP_HEADER )) {
if (DumpHeap) {
AlPrint( "AlRtHEAP: Invalid heap header- %lx\n", Heap );
}
HeapValid = FALSE;
goto exit;
}
if (DumpHeap) {
AlPrint( "Heap at %lx, Length=%lx\n", Heap, Heap->Length );
AlPrint( " FreeList: Head=%lx\n", Heap->FreeList.Next );
AlPrint( " Heap: End Address = %lx\n",Heap->EndAddress);
}
if (Heap->FreeList.Size != 0) {
if (DumpHeap) {
AlPrint( "*** head of free list is invalid (size)\n" );
}
HeapValid = FALSE;
goto exit;
}
LengthOfFreeList = 0;
FreeBlock = Heap->FreeList.Next;
while (FreeBlock) {
if (DumpHeap) {
AlPrint( " %08lx: Next=%lx Size: %lx Segment: %lx\n",
FreeBlock,
FreeBlock->Next,
FreeBlock->Size,
FreeBlock->Segment
);
}
if (((ULONG)FreeBlock->Next & FLAGS_MASK) != FLAGS_FREE) {
if (DumpHeap) {
AlPrint( "*** free list element is not a valid free block\n" );
}
HeapValid = FALSE;
goto exit;
}
LengthOfFreeList += 1;
FreeBlock = FreeBlock->Next;
}
CountOfFreeBlocks = 0;
if (DumpHeap) {
AlPrint( " Heap Blocks starting at %lx:\n", Heap->ValidAddress );
}
HeapValid = DumpHeapSegment( DumpHeap,
Heap,
Heap->ValidAddress,
Heap->EndAddress,
&CountOfFreeBlocks
);
if (!HeapValid) {
goto exit;
}
if (LengthOfFreeList != CountOfFreeBlocks) {
if (DumpHeap) {
AlPrint( "*** Number of free blocks in arena (%ld) does not match number in the free list (%ld)\n",
CountOfFreeBlocks,
LengthOfFreeList
);
}
HeapValid = FALSE;
goto exit;
}
exit:
return( HeapValid );
} // AlRtValidateHeap
#else
BOOLEAN
AlRtValidateHeap(
IN PVOID HeapHandle,
IN BOOLEAN DumpHeap
)
{
return( TRUE );
}
#endif
PVOID
AlRtAllocateHeap(
IN PVOID HeapHandle,
IN ULONG Size
)
{
PHEAP_HEADER Heap = (PHEAP_HEADER)HeapHandle;
ULONG allocationSize;
// PSEGMENT_HEADER Segment;
PFREE_HEADER FreeBlock;
PFREE_HEADER PreviousFreeBlock;
PFREE_HEADER NewFreeBlock;
PBUSY_HEADER BusyBlock;
//
// Validate that HeapAddress points to a HEAP_HEADER structure.
//
if (Heap->Length != sizeof( HEAP_HEADER )) {
#if DBG
AlPrint( "ALHEAP: Invalid heap header- %lx\n", Heap );
#endif // DBG
return( NULL );
}
//
// Additional check, see if the heap is valid, call the heap validation
// code, requesting it to not dump stuff.
//
if(!AlRtValidateHeap( HeapHandle, FALSE)) {
#if DBG
AlPrint("Heap validation failed\n");
#endif
return ( NULL );
}
//
// Round the requested size up to the allocation granularity. Note
// that if the request is for 0 bytes, we still allocate memory.
//
allocationSize = ((Size ? Size : ALLOCATION_GRANULARITY) +
sizeof( BUSY_HEADER ) +
ALLOCATION_GRANULARITY -
1
) & ~(ALLOCATION_GRANULARITY - 1);
if (allocationSize < Size) {
#if DBG
AlPrint( "ALHEAP: Invalid heap size - %lx\n", Size );
// RtlpBreakPointHeap();
#endif // DBG
return( NULL );
}
//
// Point to the free list header.
//
FreeBlock = &Heap->FreeList;
#if DBG
if (FreeBlock->Size != 0) {
AlPrint( "ALHEAP: Heap free list HEAD hosed at %lx\n", FreeBlock );
// RtlpBreakPointHeap();
return( NULL );
}
#endif // DBG
//
// Continuous loop. We'll break out of the loop when we've found
// (or created) some free memory.
//
while (TRUE) {
//
// Have we reached the end of the free list?
//
if (FreeBlock->Next == NULL)
return( NULL );
else {
//
// Point to the next free block, saving a pointer to the
// previous one.
//
PreviousFreeBlock = FreeBlock;
FreeBlock = PreviousFreeBlock->Next;
}
#if DBG
if (FreeBlock->Size == 0) {
AlPrint( "ALHEAP: Heap free list ENTRY hosed at %lx\n",
FreeBlock
);
// RtlpBreakPointHeap();
return( NULL );
}
#endif // DBG
//
// We haven't exhausted the free list yet. If this block is
// large enough for what we need, break out of the while loop.
//
if (FreeBlock->Size >= allocationSize) {
break;
}
} // while ( TRUE )
//
// We have found a free block that is large enough to hold what the
// user requested. If it's exactly the right size, simply point the
// previous free block to the successor of this free block. If it's
// larger than what we want, we allocate from the front of the block,
// leaving the trailing part free. Exactly the right size is fuzzy,
// as if we decide to split we need at least enough extra space for
// a free header plus some space to statisfy an allocation.
//
if ((FreeBlock->Size - allocationSize) < (2 * sizeof( FREE_HEADER ))) {
//
// If the amount of extra space is less than twice the size of
// a free header, just give the caller all the space, as the
// extra amount is too small to waste a free block on.
//
allocationSize = FreeBlock->Size;
//
// Exactly the right size. Point previous free block to the
// next free block.
//
PreviousFreeBlock->Next = FreeBlock->Next;
}
else {
//
// More memory than we need. Make the trailing part of the block
// into a free block. Point the previous block to the new block
// and the new block to the next block.
//
NewFreeBlock = (PFREE_HEADER)((PCH)FreeBlock + allocationSize);
PreviousFreeBlock->Next = NewFreeBlock;
NewFreeBlock->Next = FreeBlock->Next;
NewFreeBlock->Size = FreeBlock->Size - allocationSize;
NewFreeBlock->Segment = FreeBlock->Segment;
}
//
// Set up the header for the allocated block.
//
BusyBlock = (PBUSY_HEADER)FreeBlock;
BusyBlock->Segment = (PSEGMENT_HEADER)((ULONG)FreeBlock->Segment |
FLAGS_BUSY
);
BusyBlock->Size = allocationSize;
BusyBlock->HandleValue = NULL;
if (Heap->ZeroExtraMemory) {
ULONG extraSize;
extraSize = allocationSize - Size - sizeof( BUSY_HEADER );
memset( (PCHAR)BusyBlock + (allocationSize - extraSize),
0,
extraSize
);
}
#if DBG
BusyBlock->Spare = 0;
#endif
//
// Return the address of the user portion of the allocated block.
// This is the byte following the header.
//
return( (PVOID)(BusyBlock + 1) );
} // AlRtAllocateHeap
PVOID
AlRtFreeHeap(
IN PVOID HeapHandle,
IN PVOID BaseAddress
)
{
PHEAP_HEADER Heap = (PHEAP_HEADER)HeapHandle;
PFREE_HEADER FreeBlock;
PFREE_HEADER PreviousFreeBlock;
PFREE_HEADER SecondPrevFreeBlock;
PBUSY_HEADER BusyBlock;
PSEGMENT_HEADER BusySegment;
ULONG BusyFlags;
ULONG BusySize;
if (BaseAddress == NULL) {
return( NULL );
}
//
// Validate that HeapAddress points to a HEAP_HEADER structure.
//
if (Heap->Length != sizeof( HEAP_HEADER )) {
#if DBG
AlPrint( "ALHEAP: Invalid heap header- %lx\n", Heap );
// RtlpBreakPointHeap();
#endif // DBG
return( BaseAddress );
}
//
// Additional check, see if the heap is valid, call the heap validation
// code, requesting it to not dump stuff.
//
if(!AlRtValidateHeap( HeapHandle, FALSE)) {
#if DBG
AlPrint("Heap validation failed\n");
#endif
return ( BaseAddress );
}
//
// Get the 'real' address of the allocation unit. (That is, the
// address of the allocation header.) Make sure the address lies
// within the bounds of the valid portion of the heap.
//
BusyBlock = (PBUSY_HEADER)BaseAddress - 1;
BusyFlags = (ULONG)BusyBlock->Segment & FLAGS_MASK;
BusySegment = (PSEGMENT_HEADER)((ULONG)BusyBlock->Segment & ~FLAGS_MASK);
BusySize = BusyBlock->Size;
if (BusyFlags != FLAGS_BUSY
#if DBG
|| (BusySegment == NULL &&
((PCHAR)BusyBlock < (PCHAR)Heap->ValidAddress ||
(PCHAR)BusyBlock >= (PCHAR)Heap->EndAddress
)
) ||
(BusySegment != NULL &&
(BusyBlock < (PBUSY_HEADER)(BusySegment+1) ||
BusyBlock >= (PBUSY_HEADER)((ULONG)BusySegment + BusySegment->Size)
)
) ||
(BusySize < ALLOCATION_GRANULARITY
) ||
(BusySize & (ALLOCATION_GRANULARITY-1) != 0
)
#endif // DBG
) {
#if DBG
AlPrint( "ALHEAP: Invalid Address specified to AlRtFreeHeap( %lx, %lx )\n",
Heap,
BaseAddress
);
// RtlpBreakPointHeap();
#endif // DBG
return( BaseAddress );
}
//
// Free blocks are stored in the free list in ascending order by
// base address. As we search the free list to find the place for
// this block, we remember the previous two free blocks that we
// passed through. These are used during combining of adjacent
// free blocks.
//
SecondPrevFreeBlock = NULL;
PreviousFreeBlock = &Heap->FreeList;
#if DBG
if (PreviousFreeBlock->Size != 0) {
AlPrint( "ALHEAP: Heap free list HEAD hosed at %lx\n",
PreviousFreeBlock
);
// RtlpBreakPointHeap();
return( BaseAddress );
}
#endif // DBG
//
// Continuous loop. We'll break out of the loop when we've found
// the first block of free memory whose address is larger than the
// address of the block being freed. (Or the end of the free list.)
//
while (TRUE) {
//
// Get the address of the next free block. If we've exhausted
// the free list, break out of the loop -- the block we're
// freeing goes at the end of the list.
//
FreeBlock = PreviousFreeBlock->Next;
if (FreeBlock == NULL) {
break;
}
#if DBG
if (FreeBlock->Size == 0) {
AlPrint( "ALHEAP: Heap free list ENTRY hosed at %lx\n",
FreeBlock
);
// RtlpBreakPointHeap();
return( BaseAddress );
}
#endif // DBG
//
// If the address of the current block is higher than the
// address of the block we're freeing, break out of the loop.
// The freed block goes immediately before the current block.
//
if (FreeBlock > (PFREE_HEADER)BusyBlock) {
break;
}
//
// We haven't found the spot yet. Remember the last two blocks.
//
SecondPrevFreeBlock = PreviousFreeBlock;
PreviousFreeBlock = FreeBlock;
} // while ( TRUE )
//
// We've found the place for the block we're freeing. If the previous
// block is adjacent to this one, merge the two by summing their sizes,
// adjusting the address of the block being freed, and making the second
// previous block the first previous block. (Note that the previous
// block may actually be the listhead. In this case, the if condition
// will never be true, because the Size of the listhead is 0.)
//
if (((PCH)PreviousFreeBlock + PreviousFreeBlock->Size) == (PCH)BusyBlock &&
PreviousFreeBlock->Segment == BusySegment
) {
BusySize += PreviousFreeBlock->Size;
BusyBlock = (PBUSY_HEADER)PreviousFreeBlock;
PreviousFreeBlock = SecondPrevFreeBlock;
#if DBG
}
else
if ((PreviousFreeBlock != &Heap->FreeList) &&
((PCH)PreviousFreeBlock + PreviousFreeBlock->Size) > (PCH)BusyBlock
) {
AlPrint( "ALHEAP: Heap free list overlaps freed block at %lx\n",
BusyBlock
);
// RtlpBreakPointHeap();
return( BaseAddress );
#endif // DBG
}
//
// If the block being freed is adjacent to the current block, merge
// the two by summing their sizes and making the next block the
// current block. (Note that the current block may not exist, in
// which case FreeBlock == NULL, and the if condition will not be
// true.)
//*** There is an assumption here that we'll never EVER use the
//*** very highest part of the address space for user mode allocatable
//*** memory!
//
if (((PCH)BusyBlock + BusySize) == (PCH)FreeBlock &&
FreeBlock->Segment == BusySegment
) {
BusySize += FreeBlock->Size;
FreeBlock = FreeBlock->Next;
#if DBG
if (FreeBlock != NULL) {
if (FreeBlock->Size == 0) {
AlPrint( "ALHEAP: Heap free list ENTRY hosed at %lx\n",
FreeBlock
);
// RtlpBreakPointHeap();
return( BaseAddress );
}
}
}
else
if ((FreeBlock != NULL) &&
((PCH)BusyBlock + BusySize) > (PCH)FreeBlock
) {
AlPrint( "ALHEAP: Freed block overlaps heap free list at %lx\n",
BusyBlock
);
// RtlpBreakPointHeap();
return( BaseAddress );
#endif // DBG
}
//
// Done merging. Update the free list and the free block header.
//*** May want to reclaim (i.e., release) pages sometime. That is,
//*** if we find ourselves with oodles of contiguous pages on the
//*** free list, we could delete them from our address space. On
//*** the other hand, it probably doesn't cost very much to keep
//*** them around, and if the process needed that much memory once,
//*** it's likely to need it again.
//
PreviousFreeBlock->Next = (PFREE_HEADER)BusyBlock;
((PFREE_HEADER)BusyBlock)->Next = FreeBlock;
((PFREE_HEADER)BusyBlock)->Size = BusySize;
((PFREE_HEADER)BusyBlock)->Segment = BusySegment;
//
// Release the free list lock and return to the caller.
//
return( NULL );
} // AlRtFreeHeap
PVOID
AlRtReAllocateHeap(
IN PVOID HeapHandle,
IN PVOID BaseAddress,
IN ULONG Size
)
{
PHEAP_HEADER Heap = (PHEAP_HEADER)HeapHandle;
PVOID NewBaseAddress;
ULONG allocationSize;
PBUSY_HEADER BusyBlock;
PBUSY_HEADER ExtraBusyBlock;
PSEGMENT_HEADER BusySegment;
ULONG BusyFlags;
ULONG BusySize;
LONG DeltaSize;
//
// Validate that HeapAddress points to a HEAP_HEADER structure.
//
if (Heap->Length != sizeof( HEAP_HEADER )) {
#if DBG
AlPrint( "ALHEAP: Invalid heap header- %lx\n", Heap );
// RtlpBreakPointHeap();
#endif // DBG
return( NULL );
}
//
// Additional check, see if the heap is valid, call the heap validation
// code, requesting it to not dump stuff.
//
if(!AlRtValidateHeap( HeapHandle, FALSE)) {
#if DBG
AlPrint("Heap validation failed\n");
#endif
return ( NULL );
}
//
// Round the requested size up to the allocation granularity. Note
// that if the request is for 0 bytes, we still allocate memory.
//
allocationSize = ((Size ? Size : ALLOCATION_GRANULARITY) +
sizeof( BUSY_HEADER ) +
ALLOCATION_GRANULARITY -
1
) & ~(ALLOCATION_GRANULARITY - 1);
if (allocationSize < Size) {
#if DBG
AlPrint( "ALHEAP: Invalid heap size - %lx\n", Size );
// RtlpBreakPointHeap();
#endif // DBG
return( NULL );
}
if (BaseAddress == NULL) {
#if DBG
AlPrint( "ALHEAP: Invalid heap address - %lx\n", BaseAddress );
// RtlpBreakPointHeap();
#endif // DBG
return( NULL );
}
//
// Get the 'real' address of the allocation unit. (That is, the
// address of the allocation header.) Make sure the address lies
// within the bounds of the valid portion of the heap.
//
BusyBlock = (PBUSY_HEADER)BaseAddress - 1;
BusySize = BusyBlock->Size;
BusySegment = (PSEGMENT_HEADER)((ULONG)BusyBlock->Segment & ~FLAGS_MASK);
BusyFlags = (ULONG)BusyBlock->Segment & FLAGS_MASK;
if (BusyFlags != FLAGS_BUSY
#if DBG
|| (BusySegment == NULL &&
((PCHAR)BusyBlock < (PCHAR)Heap->ValidAddress ||
(PCHAR)BusyBlock >= (PCHAR)Heap->EndAddress
)
) ||
(BusySegment != NULL &&
(BusyBlock < (PBUSY_HEADER)(BusySegment+1) ||
BusyBlock >= (PBUSY_HEADER)((ULONG)BusySegment + BusySegment->Size)
)
) ||
(BusySize < ALLOCATION_GRANULARITY
) ||
(BusySize & (ALLOCATION_GRANULARITY-1) != 0
)
#endif // DBG
) {
#if DBG
AlPrint( "ALHEAP: Invalid Address specified to AlRtFreeHeap( %lx, %lx )\n",
Heap,
BaseAddress
);
// RtlpBreakPointHeap();
#endif // DBG
return( NULL );
}
//
// See if new size less than or equal to the current size.
//
DeltaSize = (LONG)(BusySize - allocationSize);
if (DeltaSize >= 0) {
//
// Then shrinking block. If amount of shrinkage is less than
// the size of a free block, then nothing to do.
//
if (DeltaSize < sizeof( FREE_HEADER )) {
if (Heap->ZeroExtraMemory) {
memset( (PCHAR)BusyBlock + (allocationSize - DeltaSize),0,
DeltaSize
);
}
return( BaseAddress );
}
//
// Otherwise, shrink size of this block to new size, and make extra
// space at end look like another busy block and call AlRtFreeHeap
// to free it.
//
BusyBlock->Size = allocationSize;
ExtraBusyBlock = (PBUSY_HEADER)((PCH)BusyBlock + allocationSize);
ExtraBusyBlock->Segment = BusyBlock->Segment;
ExtraBusyBlock->Size = (ULONG)(DeltaSize);
#if DBG
ExtraBusyBlock->Spare = 0;
#endif
AlRtFreeHeap( HeapHandle, (PVOID)(ExtraBusyBlock+1) );
if (Heap->ZeroExtraMemory) {
ULONG extraSize;
extraSize = allocationSize - Size - sizeof( BUSY_HEADER );
memset( (PCHAR)BusyBlock + (allocationSize - extraSize),0,
extraSize
);
}
return( BaseAddress );
}
//
// Otherwise growing block, so allocate a new block with the bigger
// size, copy the contents of the old block to the new block and then
// free the old block. Return the address of the new block.
//
NewBaseAddress = AlRtAllocateHeap( HeapHandle, Size );
if (NewBaseAddress != NULL) {
#if DBG
ExtraBusyBlock = (PBUSY_HEADER)NewBaseAddress - 1;
ExtraBusyBlock->Spare = 0;
#endif
memmove( NewBaseAddress,
BaseAddress,
BusySize - sizeof( BUSY_HEADER )
);
AlRtFreeHeap( HeapHandle, BaseAddress );
}
return( NewBaseAddress );
}
ARC_STATUS
AlMemoryInitialize (
ULONG StackPages,
ULONG HeapPages
)
/*++
Routine Description:
This routine allocates stack space for the OS loader, initializes
heap storage, and initializes the memory allocation list.
Arguments:
None.
Return Value:
ESUCCESS is returned if the initialization is successful. Otherwise,
ENOMEM is returned.
--*/
{
PMEMORY_DESCRIPTOR FreeDescriptor;
PMEMORY_DESCRIPTOR ProgramDescriptor;
//
// Find the memory descriptor that describes the allocation for the OS
// loader itself.
//
ProgramDescriptor = NULL;
while ((ProgramDescriptor = ArcGetMemoryDescriptor(ProgramDescriptor)) != NULL) {
if (ProgramDescriptor->MemoryType == MemoryLoadedProgram) {
break;
}
}
//
// If a loaded program memory descriptor was found, then it must be
// for the OS loader since that is the only program that can be loaded.
// If a loaded program memory descriptor was not found, then firmware
// is not functioning properly and an unsuccessful status is returned.
//
if (ProgramDescriptor == NULL) {
return ENOMEM;
}
//
// Find the free memory descriptor that is just below the loaded
// program in memory. There should be several megabytes of free
// memory just preceeding the OS loader.
//
FreeDescriptor = NULL;
while ((FreeDescriptor = ArcGetMemoryDescriptor(FreeDescriptor)) != NULL) {
if ((FreeDescriptor->MemoryType == MemoryFree) &&
(FreeDescriptor->PageCount >= (StackPages+HeapPages))) {
break;
}
}
//
// If a free memory descriptor was not found that describes the free
// memory just below the OS loader, then firmware is not functioning
// properly and an unsuccessful status is returned.
//
if (FreeDescriptor == NULL) {
return ENOMEM;
}
//
// Check to determine if enough free memory is available for the OS
// loader stack and the heap area. If enough memory is not available,
// then return an unsuccessful status.
//
if (FreeDescriptor->PageCount < (StackPages + HeapPages)) {
return ENOMEM;
}
//
// Compute the address of the loader heap, initialize the heap
// allocation variables, and zero the heap memory.
//
AlHeapFree = KSEG0_BASE | ((ProgramDescriptor->BasePage -
(StackPages + HeapPages)) << PAGE_SHIFT);
AlHeapLimit = AlHeapFree + (HeapPages << PAGE_SHIFT);
memset((PVOID)AlHeapFree, 0,HeapPages << PAGE_SHIFT);
//
// Changed to new heap allocater
//
if ((HeapHandle = AlRtCreateHeap
(
HEAP_ZERO_EXTRA_MEMORY,
(PVOID)AlHeapFree,
HeapPages << PAGE_SHIFT
))
== NULL)
return ENOMEM;
else
return ESUCCESS;
}
//
// AlAllocateHeap.
//
// Heap space allocator. Size is in bytes required.
PVOID
AlAllocateHeap (
IN ULONG Size
)
{
return (AlRtAllocateHeap
(
HeapHandle,
Size
));
}
// 3. AlDeallocateHeap
//
// Heap Deallocation needs to be defined and implemented.
//
//
PVOID
AlDeallocateHeap (
IN PVOID HeapAddress
)
{
return (AlRtFreeHeap
(
HeapHandle,
HeapAddress
));
}
//
// 4. AlReallocateHeap
//
//
//
PVOID
AlReallocateHeap (
IN PVOID HeapAddress,
IN ULONG NewSize
)
{
return (AlRtReAllocateHeap
(
HeapHandle,
HeapAddress,
NewSize
));
}
//
// 5. AlValidateHeap
//
// Heap validation
//
//
BOOLEAN
AlValidateHeap(
IN BOOLEAN DumpHeap
)
{
return (AlRtValidateHeap
(
HeapHandle,
DumpHeap
));
}