Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1256 lines
38 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
blmemory.c
Abstract:
This module implements the OS loader memory allocation routines.
Author:
David N. Cutler (davec) 19-May-1991
Revision History:
--*/
#include "bldr.h"
#define MIN(_a,_b) (((_a) <= (_b)) ? (_a) : (_b))
#define MAX(_a,_b) (((_a) >= (_b)) ? (_a) : (_b))
//
// PPC needs to allocate initial structures from high memory, in order to
// leave room in low memory for KSEG0.
//
#if !defined(_PPC_)
ALLOCATION_POLICY BlMemoryAllocationPolicy = BlAllocateBestFit;
ALLOCATION_POLICY BlHeapAllocationPolicy = BlAllocateBestFit;
#else
ALLOCATION_POLICY BlMemoryAllocationPolicy = BlAllocateHighestFit;
ALLOCATION_POLICY BlHeapAllocationPolicy = BlAllocateHighestFit;
#endif
//
// Define memory allocation descriptor listhead and heap storage variables.
//
ULONG BlHeapFree;
ULONG BlHeapLimit;
PLOADER_PARAMETER_BLOCK BlLoaderBlock;
#if DBG
ULONG TotalHeapAbandoned = 0;
#endif
VOID
BlSetAllocationPolicy (
IN ALLOCATION_POLICY MemoryAllocationPolicy,
IN ALLOCATION_POLICY HeapAllocationPolicy
)
{
BlMemoryAllocationPolicy = MemoryAllocationPolicy;
BlHeapAllocationPolicy = HeapAllocationPolicy;
return;
}
VOID
BlInsertDescriptor (
IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
/*++
Routine Description:
This routine inserts a memory descriptor in the memory allocation list.
It inserts the new descriptor in sorted order, based on the starting
page of the block. It also merges adjacent blocks of free memory.
Arguments:
ListHead - Supplies the address of the memory allocation list head.
NewDescriptor - Supplies the address of the descriptor that is to be
inserted.
Return Value:
None.
--*/
{
PLIST_ENTRY ListHead = &BlLoaderBlock->MemoryDescriptorListHead;
PLIST_ENTRY PreviousEntry;
PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor;
PLIST_ENTRY NextEntry;
PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
//
// Find the first descriptor in the list that starts above the new
// descriptor. The new descriptor goes in front of this descriptor.
//
PreviousEntry = ListHead;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (NewDescriptor->BasePage < NextDescriptor->BasePage) {
break;
}
PreviousEntry = NextEntry;
PreviousDescriptor = NextDescriptor;
NextEntry = NextEntry->Flink;
}
//
// If the new descriptor doesn't describe free memory, just insert it
// in the list in front of the previous entry. Otherwise, check to see
// if free blocks can be merged.
//
if (NewDescriptor->MemoryType != LoaderFree) {
InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
} else {
//
// If the previous block also describes free memory, and it's
// contiguous with the new block, merge them by adding the
// page count from the new
//
// On Alpha, do not merge across the 1GB line, as the initialization
// code assumes any memory descriptor that starts in KSEG0 also ends
// in KSEG0.
//
if ((PreviousEntry != ListHead) &&
(PreviousDescriptor->MemoryType == LoaderFree) &&
#if defined(_ALPHA_)
(NewDescriptor->BasePage != (0x40000000 >> PAGE_SHIFT)) &&
#endif
((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
NewDescriptor->BasePage)) {
PreviousDescriptor->PageCount += NewDescriptor->PageCount;
NewDescriptor = PreviousDescriptor;
} else {
InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
}
if ((NextEntry != ListHead) &&
(NextDescriptor->MemoryType == LoaderFree) &&
((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage)) {
NewDescriptor->PageCount += NextDescriptor->PageCount;
BlRemoveDescriptor(NextDescriptor);
}
}
return;
}
ARC_STATUS
BlMemoryInitialize (
VOID
)
/*++
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_ALLOCATION_DESCRIPTOR AllocationDescriptor;
PMEMORY_DESCRIPTOR HeapDescriptor;
PMEMORY_DESCRIPTOR StackDescriptor;
PMEMORY_DESCRIPTOR MemoryDescriptor;
PMEMORY_DESCRIPTOR ProgramDescriptor;
ULONG EndPage;
ULONG HeapAndStackPages;
ULONG StackPages;
ULONG StackBasePage;
//
// Find the memory descriptor that describes the allocation for the OS
// loader itself.
//
// On PPC, there can be multiple descriptors of type MemoryLoadedProgram.
// (See lib\ppc\ntsetup.c for more information.) All but one of these
// will reside above 8 MB. It is the one below 8 MB that we want.
//
ProgramDescriptor = NULL;
while ((ProgramDescriptor = ArcGetMemoryDescriptor(ProgramDescriptor)) != NULL) {
if (ProgramDescriptor->MemoryType == MemoryLoadedProgram) {
#if !defined(_PPC_)
break;
#else
if (ProgramDescriptor->BasePage < ((8*1024*1024) >> PAGE_SHIFT)) {
break;
}
#endif
}
}
//
// 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;
}
#if !defined(_PPC_)
//
// 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.
//
StackPages = BL_STACK_PAGES;
HeapAndStackPages = BL_HEAP_PAGES + BL_STACK_PAGES;
StackDescriptor = NULL;
HeapDescriptor = NULL;
while ((HeapDescriptor = ArcGetMemoryDescriptor(HeapDescriptor)) != NULL) {
if (((HeapDescriptor->MemoryType == MemoryFree) ||
(HeapDescriptor->MemoryType == MemoryFreeContiguous)) &&
((HeapDescriptor->BasePage + HeapDescriptor->PageCount) ==
ProgramDescriptor->BasePage)) {
break;
}
}
//
// If a free memory descriptor was not found that describes the free
// memory just below the OS loader, or the memory descriptor is not
// large enough for the OS loader stack and heap, then try and find
// a suitable one.
//
if ((HeapDescriptor == NULL) ||
(HeapDescriptor->PageCount < (BL_HEAP_PAGES + BL_STACK_PAGES))) {
HeapDescriptor = NULL;
while ((HeapDescriptor = ArcGetMemoryDescriptor(HeapDescriptor)) != NULL) {
if (((HeapDescriptor->MemoryType == MemoryFree) ||
(HeapDescriptor->MemoryType == MemoryFreeContiguous)) &&
(HeapDescriptor->PageCount >= (BL_HEAP_PAGES + BL_STACK_PAGES))) {
break;
}
}
}
if (HeapDescriptor != NULL) {
StackBasePage = HeapDescriptor->BasePage + HeapDescriptor->PageCount - BL_STACK_PAGES;
}
#else // defined(_PPC_)
//
// Some ARC firmwares (IBM and Motorola) put the loader stack
// immediately below the program, but do not mark the stack memory
// as in use, depending on the loader to mark it. Other firmwares
// (Open Firmware) put the loader stack elsewhere and mark it as
// FirmwareTemporary. We can't tell which one we're on, so if there
// is free memory just below the loader program, we need to assume
// that BL_STACK_PAGES of it is the stack. On Open Firmware
// machines, this means that we waste some memory, because there is
// free memory below the program but it's really free, not stack
// memory. Such is life.
//
// This does not impact our goal of avoiding very low memory for
// everything except blocks that really must be in KSEG0, because
// all current firmwares put the loader at 0x600000, which should be
// well above the KSEG0 line.
//
// Just to be sure, however, we put the loader heap as high as
// possible.
//
// The first step here is to find free memory just below the loaded
// program. If there are at least BL_STACK_PAGES there, we mark
// those pages as OsloaderStack and stay away from them. If not, we
// assume that the firmware has put the stack elsewhere and marked
// it appropriately. In either case, we allocate the loader heap
// separately.
//
StackPages = 0;
HeapAndStackPages = BL_HEAP_PAGES;
StackDescriptor = NULL;
while ((StackDescriptor = ArcGetMemoryDescriptor(StackDescriptor)) != NULL) {
if (((StackDescriptor->MemoryType == MemoryFree) ||
(StackDescriptor->MemoryType == MemoryFreeContiguous)) &&
((StackDescriptor->BasePage + StackDescriptor->PageCount) ==
ProgramDescriptor->BasePage)) {
if (StackDescriptor->PageCount >= BL_STACK_PAGES) {
StackPages = BL_STACK_PAGES;
StackBasePage = StackDescriptor->BasePage + StackDescriptor->PageCount - StackPages;
}
break;
}
}
//
// Now allocate the heap as high as possible.
//
HeapDescriptor = NULL;
MemoryDescriptor = NULL;
while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) {
if (((MemoryDescriptor->MemoryType == MemoryFree) ||
(MemoryDescriptor->MemoryType == MemoryFreeContiguous)) &&
(MemoryDescriptor->PageCount >= BL_HEAP_PAGES)) {
if ((HeapDescriptor == NULL) ||
((HeapDescriptor != NULL) &&
(MemoryDescriptor->BasePage > HeapDescriptor->BasePage))) {
HeapDescriptor = MemoryDescriptor;
}
}
}
#endif // defined(_PPC_)
//
// A suitable descriptor could not be found, return an unsuccessful
// status.
//
if (HeapDescriptor == NULL) {
return(ENOMEM);
}
//
// Compute the address of the loader heap, initialize the heap
// allocation variables, and zero the heap memory.
//
EndPage = HeapDescriptor->BasePage + HeapDescriptor->PageCount;
BlHeapFree = KSEG0_BASE | ((EndPage - HeapAndStackPages) << PAGE_SHIFT);
//
// always reserve enough space in the heap for one more memory
// descriptor, so we can go create more heap if we run out.
//
BlHeapLimit = (BlHeapFree + (BL_HEAP_PAGES << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
RtlZeroMemory((PVOID)BlHeapFree, BL_HEAP_PAGES << PAGE_SHIFT);
//
// Allocate and initialize the loader parameter block.
//
BlLoaderBlock =
(PLOADER_PARAMETER_BLOCK)BlAllocateHeap(sizeof(LOADER_PARAMETER_BLOCK));
if (BlLoaderBlock == NULL) {
return ENOMEM;
}
InitializeListHead(&BlLoaderBlock->LoadOrderListHead);
InitializeListHead(&BlLoaderBlock->MemoryDescriptorListHead);
//
// Copy the memory descriptor list from firmware into the local heap and
// deallocate the loader heap and stack from the free memory descriptor.
//
MemoryDescriptor = NULL;
while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) {
AllocationDescriptor =
(PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
if (AllocationDescriptor == NULL) {
return ENOMEM;
}
AllocationDescriptor->MemoryType =
(TYPE_OF_MEMORY)MemoryDescriptor->MemoryType;
if (MemoryDescriptor->MemoryType == MemoryFreeContiguous) {
AllocationDescriptor->MemoryType = LoaderFree;
} else if (MemoryDescriptor->MemoryType == MemorySpecialMemory) {
AllocationDescriptor->MemoryType = LoaderSpecialMemory;
}
AllocationDescriptor->BasePage = MemoryDescriptor->BasePage;
AllocationDescriptor->PageCount = MemoryDescriptor->PageCount;
if (MemoryDescriptor == HeapDescriptor) {
AllocationDescriptor->PageCount -= HeapAndStackPages;
}
if (MemoryDescriptor == StackDescriptor) {
AllocationDescriptor->PageCount -= StackPages;
}
BlInsertDescriptor(AllocationDescriptor);
}
//
// Allocate a memory descriptor for the loader stack.
//
if (StackPages != 0) {
AllocationDescriptor =
(PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
if (AllocationDescriptor == NULL) {
return ENOMEM;
}
AllocationDescriptor->MemoryType = LoaderOsloaderStack;
AllocationDescriptor->BasePage = StackBasePage;
AllocationDescriptor->PageCount = BL_STACK_PAGES;
BlInsertDescriptor(AllocationDescriptor);
}
//
// Allocate a memory descriptor for the loader heap.
//
AllocationDescriptor =
(PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
if (AllocationDescriptor == NULL) {
return ENOMEM;
}
AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
AllocationDescriptor->BasePage = EndPage - HeapAndStackPages;
AllocationDescriptor->PageCount = BL_HEAP_PAGES;
BlInsertDescriptor(AllocationDescriptor);
return ESUCCESS;
}
ARC_STATUS
BlAllocateAlignedDescriptor (
IN TYPE_OF_MEMORY MemoryType,
IN ULONG BasePage,
IN ULONG PageCount,
IN ULONG Alignment,
OUT PULONG ActualBase
)
/*++
Routine Description:
This routine allocates memory and generates one of more memory
descriptors to describe the allocated region. The first attempt
is to allocate the specified region of memory (at BasePage).
If the memory is not free, then the smallest region of free
memory that satisfies the request is allocated. The Alignment
parameter can be used to force the block to be allocated at a
particular alignment.
Arguments:
MemoryType - Supplies the memory type that is to be assigend to
the generated descriptor.
BasePage - Supplies the base page number of the desired region.
If 0, no particular base page is required.
PageCount - Supplies the number of pages required.
Alignment - Supplies the required alignment, in pages. (E.g.,
with 4K page size, 16K alignment requires Alignment == 4.)
If 0, no particular alignment is required.
N.B. If BasePage is not 0, and the specified BasePage is
available, Alignment is ignored. It is up to the caller
to specify a BasePage that meets the caller's alignment
requirement.
ActualBase - Supplies a pointer to a variable that receives the
page number of the allocated region.
Return Value:
ESUCCESS is returned if an available block of free memory can be
allocated. Otherwise, return a unsuccessful status.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
PLIST_ENTRY NextEntry;
LONG Offset;
ARC_STATUS Status;
ULONG AlignedBasePage;
//
// Simplify the alignment checks by changing 0 to 1.
//
if (Alignment == 0) {
Alignment = 1;
}
//
// Attempt to find a free memory descriptor that encompasses the
// specified region or a free memory descriptor that is large
// enough to satisfy the request.
//
FreeDescriptor = NULL;
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (NextDescriptor->MemoryType == LoaderFree) {
Offset = BasePage - NextDescriptor->BasePage;
if ((Offset >= 0) &&
(NextDescriptor->PageCount >= (ULONG)(Offset + PageCount))) {
Status = BlGenerateDescriptor(NextDescriptor,
MemoryType,
BasePage,
PageCount);
*ActualBase = BasePage;
return Status;
} else {
AlignedBasePage = (NextDescriptor->BasePage + (Alignment - 1)) & ~(Alignment - 1);
Offset = AlignedBasePage - NextDescriptor->BasePage;
if ((Offset + PageCount) <= NextDescriptor->PageCount) {
//
// This block will work. If the allocation policy is
// LowestFit, take this block (the memory list is sorted).
// Otherwise, if this block best meets the allocation
// policy, remember it and keep looking.
//
if (BlMemoryAllocationPolicy == BlAllocateLowestFit) {
FreeDescriptor = NextDescriptor;
break;
}
if ((FreeDescriptor == NULL) ||
(BlMemoryAllocationPolicy == BlAllocateHighestFit) ||
((FreeDescriptor != NULL) &&
(NextDescriptor->PageCount < FreeDescriptor->PageCount))) {
FreeDescriptor = NextDescriptor;
}
}
}
}
NextEntry = NextEntry->Flink;
}
//
// If a free region that satisfies the request was found, then allocate
// the space from that descriptor. Otherwise, return an unsuccessful status.
//
// If allocating lowest-fit or best-fit, allocate from the start of the block,
// rounding up to the required alignment. If allocating highest-fit, allocate
// from the end of the block, rounding down to the required alignment.
//
if (FreeDescriptor != NULL) {
AlignedBasePage = FreeDescriptor->BasePage + (Alignment - 1);
if (BlMemoryAllocationPolicy == BlAllocateHighestFit) {
AlignedBasePage = FreeDescriptor->BasePage + FreeDescriptor->PageCount - PageCount;
}
AlignedBasePage = AlignedBasePage & ~(Alignment - 1);
*ActualBase = AlignedBasePage;
return BlGenerateDescriptor(FreeDescriptor,
MemoryType,
AlignedBasePage,
PageCount);
} else {
return ENOMEM;
}
}
PVOID
BlAllocateHeapAligned (
IN ULONG Size
)
/*++
Routine Description:
This routine allocates memory from the OS loader heap. The memory
will be allocated on a cache line boundary.
Arguments:
Size - Supplies the size of block required in bytes.
Return Value:
If a free block of memory of the specified size is available, then
the address of the block is returned. Otherwise, NULL is returned.
--*/
{
PVOID Buffer;
Buffer = BlAllocateHeap(Size + BlDcacheFillSize - 1);
if (Buffer != NULL) {
//
// round up to a cache line boundary
//
Buffer = ALIGN_BUFFER(Buffer);
}
return(Buffer);
}
PVOID
BlAllocateHeap (
IN ULONG Size
)
/*++
Routine Description:
This routine allocates memory from the OS loader heap.
Arguments:
Size - Supplies the size of block required in bytes.
Return Value:
If a free block of memory of the specified size is available, then
the address of the block is returned. Otherwise, NULL is returned.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR AllocationDescriptor;
PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
PLIST_ENTRY NextEntry;
ULONG NewHeapPages;
ULONG LastAttempt;
ULONG Block;
//
// Round size up to next allocation boundary and attempt to allocate
// a block of the requested size.
//
Size = (Size + (BL_GRANULARITY - 1)) & (~(BL_GRANULARITY - 1));
Block = BlHeapFree;
if ((BlHeapFree + Size) <= BlHeapLimit) {
BlHeapFree += Size;
return (PVOID)Block;
} else {
#if DBG
TotalHeapAbandoned += (BlHeapLimit - BlHeapFree);
BlLog((LOG_ALL_W,"ABANDONING %d bytes of heap; total abandoned %d\n",
(BlHeapLimit - BlHeapFree), TotalHeapAbandoned));
#endif
//
// Our heap is full. BlHeapLimit always reserves enough space
// for one more MEMORY_ALLOCATION_DESCRIPTOR, so use that to
// go try and find more free memory we can use.
//
AllocationDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)BlHeapLimit;
//
// Attempt to find a free memory descriptor big enough to hold this
// allocation or BL_HEAP_PAGES, whichever is bigger.
//
NewHeapPages = ((Size + sizeof(MEMORY_ALLOCATION_DESCRIPTOR) + (PAGE_SIZE-1)) >> PAGE_SHIFT);
if (NewHeapPages < BL_HEAP_PAGES) {
NewHeapPages = BL_HEAP_PAGES;
}
do {
FreeDescriptor = NULL;
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if ((NextDescriptor->MemoryType == LoaderFree) &&
(NextDescriptor->PageCount >= NewHeapPages)) {
//
// This block will work. If the allocation policy is
// LowestFit, take this block (the memory list is sorted).
// Otherwise, if this block best meets the allocation
// policy, remember it and keep looking.
//
if (BlHeapAllocationPolicy == BlAllocateLowestFit) {
FreeDescriptor = NextDescriptor;
break;
}
if ((FreeDescriptor == NULL) ||
(BlHeapAllocationPolicy == BlAllocateHighestFit) ||
((FreeDescriptor != NULL) &&
(NextDescriptor->PageCount < FreeDescriptor->PageCount))) {
FreeDescriptor = NextDescriptor;
}
}
NextEntry = NextEntry->Flink;
}
//
// If we were unable to find a block of the desired size, memory
// must be getting tight, so try again, this time looking just
// enough to keep us going. (The first time through, we try to
// allocate at least BL_HEAP_PAGES.)
//
if (FreeDescriptor != NULL) {
break;
}
LastAttempt = NewHeapPages;
NewHeapPages = ((Size + sizeof(MEMORY_ALLOCATION_DESCRIPTOR) + (PAGE_SIZE-1)) >> PAGE_SHIFT);
if (NewHeapPages == LastAttempt) {
break;
}
} while (TRUE);
if (FreeDescriptor == NULL) {
//
// No free memory left.
//
return(NULL);
}
//
// We've found a descriptor that's big enough. Just carve a
// piece off the end and use that for our heap. If we're taking
// all of the memory from the descriptor, remove it from the
// memory list. (This wastes a descriptor, but that's life.)
//
FreeDescriptor->PageCount -= NewHeapPages;
if (FreeDescriptor->PageCount == 0) {
BlRemoveDescriptor(FreeDescriptor);
}
//
// Initialize our new descriptor and add it to the list.
//
AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
AllocationDescriptor->BasePage = FreeDescriptor->BasePage +
FreeDescriptor->PageCount;
AllocationDescriptor->PageCount = NewHeapPages;
BlInsertDescriptor(AllocationDescriptor);
//
// initialize new heap values and return pointer to newly
// alloc'd memory.
//
BlHeapFree = KSEG0_BASE | (AllocationDescriptor->BasePage << PAGE_SHIFT);
BlHeapLimit = (BlHeapFree + (NewHeapPages << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
RtlZeroMemory((PVOID)BlHeapFree, NewHeapPages << PAGE_SHIFT);
Block = BlHeapFree;
if ((BlHeapFree + Size) < BlHeapLimit) {
BlHeapFree += Size;
return(PVOID)Block;
} else {
//
// we should never get here
//
return(NULL);
}
}
}
VOID
BlGenerateNewHeap (
IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
IN ULONG BasePage,
IN ULONG PageCount
)
/*++
Routine Description:
This routine allocates a new heap block from the specified memory
descriptor, avoiding the region specified by BasePage and PageCount.
The caller must ensure that this region does not encompass the entire
block.
The allocated heap block may be as small as a single page.
Arguments:
MemoryDescriptor - Supplies a pointer to a free memory descriptor
from which the heap block is to be allocated.
BasePage - Supplies the base page number of the excluded region.
PageCount - Supplies the number of pages in the excluded region.
Return Value:
None.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR AllocationDescriptor;
ULONG NewHeapPages;
ULONG AvailableAtFront;
ULONG AvailableAtBack;
//
// BlHeapLimit always reserves enough space for one more
// MEMORY_ALLOCATION_DESCRIPTOR, so use that to describe the
// new heap block.
//
AllocationDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)BlHeapLimit;
//
// Allocate the new heap from either the front or the back of the
// specified descriptor, whichever fits best. We'd like to allocate
// BL_HEAP_PAGES pages, but we'll settle for less.
//
AvailableAtFront = BasePage - MemoryDescriptor->BasePage;
AvailableAtBack = (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) -
(BasePage + PageCount);
if ((AvailableAtFront == 0) ||
((AvailableAtBack != 0) && (AvailableAtBack < AvailableAtFront))) {
NewHeapPages = MIN(AvailableAtBack, BL_HEAP_PAGES);
AllocationDescriptor->BasePage =
MemoryDescriptor->BasePage + MemoryDescriptor->PageCount - NewHeapPages;
} else {
NewHeapPages = MIN(AvailableAtFront, BL_HEAP_PAGES);
AllocationDescriptor->BasePage = MemoryDescriptor->BasePage;
MemoryDescriptor->BasePage += NewHeapPages;
}
MemoryDescriptor->PageCount -= NewHeapPages;
//
// Initialize our new descriptor and add it to the list.
//
AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
AllocationDescriptor->PageCount = NewHeapPages;
BlInsertDescriptor(AllocationDescriptor);
//
// Initialize new heap values.
//
BlHeapFree = KSEG0_BASE | (AllocationDescriptor->BasePage << PAGE_SHIFT);
BlHeapLimit = (BlHeapFree + (NewHeapPages << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
RtlZeroMemory((PVOID)BlHeapFree, NewHeapPages << PAGE_SHIFT);
return;
}
ARC_STATUS
BlGenerateDescriptor (
IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
IN MEMORY_TYPE MemoryType,
IN ULONG BasePage,
IN ULONG PageCount
)
/*++
Routine Description:
This routine allocates a new memory descriptor to describe the
specified region of memory which is assumed to lie totally within
the specified region which is free.
Arguments:
MemoryDescriptor - Supplies a pointer to a free memory descriptor
from which the specified memory is to be allocated.
MemoryType - Supplies the type that is assigned to the allocated
memory.
BasePage - Supplies the base page number.
PageCount - Supplies the number of pages.
Return Value:
ESUCCESS is returned if a descriptor(s) is successfully generated.
Otherwise, return an unsuccessful status.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor1;
PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor2;
LONG Offset;
TYPE_OF_MEMORY OldType;
BOOLEAN SecondDescriptorNeeded;
//
// If the specified region totally consumes the free region, then no
// additional descriptors need to be allocated. If the specified region
// is at the start or end of the free region, then only one descriptor
// needs to be allocated. Otherwise, two additional descriptors need to
// be allocated.
//
Offset = BasePage - MemoryDescriptor->BasePage;
if ((Offset == 0) && (PageCount == MemoryDescriptor->PageCount)) {
//
// The specified region totally consumes the free region.
//
MemoryDescriptor->MemoryType = MemoryType;
} else {
//
// Mark the entire given memory descriptor as in use. If we are
// out of heap, BlAllocateHeap will search for a new descriptor
// to grow the heap and this prevents both routines from trying
// to use the same descriptor.
//
OldType = MemoryDescriptor->MemoryType;
MemoryDescriptor->MemoryType = LoaderSpecialMemory;
//
// A memory descriptor must be generated to describe the allocated
// memory.
//
SecondDescriptorNeeded =
(BOOLEAN)((BasePage != MemoryDescriptor->BasePage) &&
((ULONG)(Offset + PageCount) != MemoryDescriptor->PageCount));
NewDescriptor1 =
(PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
//
// If allocation of the first additional memory descriptor failed,
// then generate new heap using the block from which we are
// allocating. This can only be done if the block is free.
//
// Note that BlGenerateNewHeap cannot fail, because we know there is
// at least one more page in the block than we want to take from it.
//
// Note also that the allocation following BlGenerateNewHeap is
// guaranteed to succeed.
//
if (NewDescriptor1 == NULL) {
if (OldType != LoaderFree) {
MemoryDescriptor->MemoryType = OldType;
return ENOMEM;
}
BlGenerateNewHeap(MemoryDescriptor, BasePage, PageCount);
NewDescriptor1 =
(PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
}
//
// If a second descriptor is needed, allocate it. As above, if the
// allocation fails, generate new heap using our block.
//
// Note that if BlGenerateNewHeap was called above, the first call
// to BlAllocateHeap below will not fail. (So we won't call
// BlGenerateNewHeap twice.)
//
if (SecondDescriptorNeeded) {
NewDescriptor2 =
(PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
if (NewDescriptor2 == NULL) {
if (OldType != LoaderFree) {
MemoryDescriptor->MemoryType = OldType;
return ENOMEM;
}
NewDescriptor2 =
(PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
}
}
NewDescriptor1->MemoryType = MemoryType;
NewDescriptor1->BasePage = BasePage;
NewDescriptor1->PageCount = PageCount;
if (BasePage == MemoryDescriptor->BasePage) {
//
// The specified region lies at the start of the free region.
//
MemoryDescriptor->BasePage += PageCount;
MemoryDescriptor->PageCount -= PageCount;
MemoryDescriptor->MemoryType = OldType;
} else if ((ULONG)(Offset + PageCount) == MemoryDescriptor->PageCount) {
//
// The specified region lies at the end of the free region.
//
MemoryDescriptor->PageCount -= PageCount;
MemoryDescriptor->MemoryType = OldType;
} else {
//
// The specified region lies in the middle of the free region.
//
NewDescriptor2->MemoryType = LoaderFree;
NewDescriptor2->BasePage = BasePage + PageCount;
NewDescriptor2->PageCount =
MemoryDescriptor->PageCount - (PageCount + Offset);
MemoryDescriptor->PageCount = Offset;
MemoryDescriptor->MemoryType = OldType;
BlInsertDescriptor(NewDescriptor2);
}
BlInsertDescriptor(NewDescriptor1);
}
return ESUCCESS;
}
PMEMORY_ALLOCATION_DESCRIPTOR
BlFindMemoryDescriptor(
IN ULONG BasePage
)
/*++
Routine Description:
Finds the memory allocation descriptor that contains the given page.
Arguments:
BasePage - Supplies the page whose allocation descriptor is to be found.
Return Value:
!= NULL - Pointer to the requested memory allocation descriptor
== NULL - indicates no memory descriptor contains the given page
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor=NULL;
PLIST_ENTRY NextEntry;
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
MemoryDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if ((MemoryDescriptor->BasePage <= BasePage) &&
(MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > BasePage)) {
//
// Found it.
//
break;
}
NextEntry = NextEntry->Flink;
}
if (NextEntry == &BlLoaderBlock->MemoryDescriptorListHead) {
return(NULL);
} else {
return(MemoryDescriptor);
}
}
#ifdef SETUP
PMEMORY_ALLOCATION_DESCRIPTOR
BlFindFreeMemoryBlock(
IN ULONG PageCount
)
/*++
Routine Description:
Find a free memory block of at least a given size (using a best-fit
algorithm) or find the largest free memory block.
Arguments:
PageCount - supplies the size in pages of the block. If this is 0,
then find the largest free block.
Return Value:
Pointer to the memory allocation descriptor for the block or NULL if
no block could be found matching the search criteria.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
PMEMORY_ALLOCATION_DESCRIPTOR FoundMemoryDescriptor=NULL;
PLIST_ENTRY NextEntry;
ULONG LargestSize = 0;
ULONG SmallestLeftOver = (ULONG)(-1);
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
MemoryDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (MemoryDescriptor->MemoryType == LoaderFree) {
if(PageCount) {
//
// Looking for a block of a specific size.
//
if((MemoryDescriptor->PageCount >= PageCount)
&& (MemoryDescriptor->PageCount - PageCount < SmallestLeftOver))
{
SmallestLeftOver = MemoryDescriptor->PageCount - PageCount;
FoundMemoryDescriptor = MemoryDescriptor;
}
} else {
//
// Looking for the largest free block.
//
if(MemoryDescriptor->PageCount > LargestSize) {
LargestSize = MemoryDescriptor->PageCount;
FoundMemoryDescriptor = MemoryDescriptor;
}
}
}
NextEntry = NextEntry->Flink;
}
return(FoundMemoryDescriptor);
}
ULONG
BlDetermineTotalMemory(
VOID
)
/*++
Routine Description:
Determine the total amount of memory in the machine.
Arguments:
None.
Return Value:
Total amount of memory in the system, in bytes.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
PLIST_ENTRY NextEntry;
ULONG PageCount;
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
PageCount = 0;
while(NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
MemoryDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
PageCount += MemoryDescriptor->PageCount;
#if i386
//
// Note: on x86 machines, we never use the 40h pages below the 16
// meg line (bios shadow area). But we want to account for them here,
// so check for this case.
//
if(MemoryDescriptor->BasePage + MemoryDescriptor->PageCount == 0xfc0) {
PageCount += 0x40;
}
#endif
NextEntry = NextEntry->Flink;
}
return(PageCount << PAGE_SHIFT);
}
#endif // def SETUP