NT4/private/ntos/nthals/halalpha/memory.c
2020-09-30 17:12:29 +02:00

576 lines
15 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1992, 1993 Digital Equipment Corporation
Module Name:
memory.c
Abstract:
Provides routines to allow tha HAL to map physical memory
Author:
Jeff McLeman (DEC) 11-June-1992
Revision History:
Joe Notarangelo 20-Oct-1993
- Fix bug where physical address was rounded up without referencing
AlignmentOffset, resulting in an incorrect physical address
- Remove magic numbers
- Create a routine to dump all of the descriptors to the debugger
Environment:
Phase 0 initialization only
--*/
#include "halp.h"
#define __1KB (1024)
MEMORY_ALLOCATION_DESCRIPTOR HalpExtraAllocationDescriptor;
ULONG
HalpAllocPhysicalMemory(
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN ULONG MaxPhysicalAddress,
IN ULONG NoPages,
IN BOOLEAN AlignOn64k
)
/*++
Routine Description:
Carves out N pages of physical memory from the memory descriptor
list in the desired location. This function is to be called only
during phase zero initialization. (ie, before the kernel's memory
management system is running)
Arguments:
LoaderBlock - Supplies a pointer to the loader parameter block which
contains the system memory descriptors.
MaxPhysicalAddress - Supplies the maximum address below which the memory
must be allocated.
NoPages - Supplies the number of pages to allocate.
AlignOn64k - Supplies a boolean that specifies if the requested memory
allocation must start on a 64K boundary.
Return Value:
The pyhsical address or NULL if the memory could not be obtained.
--*/
{
ULONG AlignmentMask;
ULONG AlignmentOffset;
PMEMORY_ALLOCATION_DESCRIPTOR BestFitDescriptor;
ULONG BestFitAlignmentOffset;
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
PLIST_ENTRY NextMd;
ULONG MaxPageAddress;
ULONG PhysicalAddress;
MaxPageAddress = MaxPhysicalAddress >> PAGE_SHIFT;
AlignmentMask = (__64K >> PAGE_SHIFT) - 1;
BestFitDescriptor = NULL;
BestFitAlignmentOffset = AlignmentMask + 1;
//
// Scan the memory allocation descriptors for an eligible descriptor from
// which we can allocate the requested block of memory.
//
NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
Descriptor = CONTAINING_RECORD(NextMd,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if( AlignOn64k ){
AlignmentOffset =
((Descriptor->BasePage + AlignmentMask) & ~AlignmentMask) -
Descriptor->BasePage;
} else {
AlignmentOffset = 0;
}
//
// Search for a block of memory which is contains a memory chunk
// that is greater than size pages, and has a physical address less
// than MAXIMUM_PHYSICAL_ADDRESS.
//
if ((Descriptor->MemoryType == LoaderFree ||
Descriptor->MemoryType == MemoryFirmwareTemporary) &&
(Descriptor->PageCount >= NoPages + AlignmentOffset) &&
(Descriptor->BasePage + NoPages + AlignmentOffset <
MaxPageAddress) )
{
//
// Check for a perfect fit where we need not split the descriptor
// because AlignmentOffset == 0. No need to search further if
// there is a perfect fit.
//
if( AlignmentOffset == 0 ){
BestFitDescriptor = Descriptor;
BestFitAlignmentOffset = AlignmentOffset;
break;
}
//
// If not a perfect fit check for the best fit so far.
//
if( AlignmentOffset < BestFitAlignmentOffset ){
BestFitDescriptor = Descriptor;
BestFitAlignmentOffset = AlignmentOffset;
}
}
NextMd = NextMd->Flink;
}
//
// Verify that we have found an eligible descriptor.
//
ASSERT( BestFitDescriptor != NULL );
if( BestFitDescriptor == NULL ){
return (ULONG)NULL;
}
//
// Compute the physical address of the memory block we have found.
//
PhysicalAddress = (BestFitDescriptor->BasePage + BestFitAlignmentOffset)
<< PAGE_SHIFT;
//
// Adjust the memory descriptors to account for the memory we have
// allocated.
//
if (BestFitAlignmentOffset == 0) {
BestFitDescriptor->BasePage += NoPages;
BestFitDescriptor->PageCount -= NoPages;
if (BestFitDescriptor->PageCount == 0) {
//
// The whole block was allocated,
// Remove the entry from the list completely.
//
RemoveEntryList(&BestFitDescriptor->ListEntry);
}
} else {
//
// The descriptor will be split into 3 pieces, the beginning
// segment up to our allocation, our allocation, and the trailing
// segment. We have one spare memory descriptor to handle this
// case, use it if it is not already used otherwise preserve as
// much memory as possible.
//
if( (BestFitDescriptor->PageCount - NoPages - BestFitAlignmentOffset)
== 0 ){
//
// The third segment is empty, use the original descriptor to
// map the first segment.
//
BestFitDescriptor->PageCount -= NoPages;
} else {
if( HalpExtraAllocationDescriptor.PageCount == 0 ){
//
// The extra descriptor can be used to map the third segment.
//
HalpExtraAllocationDescriptor.PageCount =
BestFitDescriptor->PageCount - NoPages -
BestFitAlignmentOffset;
HalpExtraAllocationDescriptor.BasePage =
BestFitDescriptor->BasePage + NoPages +
BestFitAlignmentOffset;
HalpExtraAllocationDescriptor.MemoryType = MemoryFree;
InsertTailList(
&BestFitDescriptor->ListEntry,
&HalpExtraAllocationDescriptor.ListEntry );
//
// Use the original descriptor to map the first segment.
//
BestFitDescriptor->PageCount = BestFitAlignmentOffset;
} else {
//
// We need to split the original descriptor into 3 segments
// but we've already used the spare descriptor. Use the
// original descriptor to map the largest segment.
//
ULONG WastedPages;
if( (BestFitDescriptor->PageCount - BestFitAlignmentOffset -
NoPages) > BestFitAlignmentOffset ){
WastedPages = BestFitAlignmentOffset;
//
// Map the third segment using the original descriptor.
//
BestFitDescriptor->BasePage += BestFitAlignmentOffset +
NoPages;
BestFitDescriptor->PageCount -= BestFitAlignmentOffset +
NoPages;
} else {
WastedPages = BestFitDescriptor->PageCount -
BestFitAlignmentOffset - NoPages;
//
// Map the first segment using the original descriptor.
//
BestFitDescriptor->PageCount = BestFitAlignmentOffset;
} //end if( (BestFitDescriptor->PageCount - BestFitAlignm ...
//
// Report that we have had to waste pages.
//
DbgPrint( "HalpAllocPhysicalMemory: wasting %d pages\n",
WastedPages );
} //end if( HalpExtraAllocationDescriptor.PageCount == 0 )
} //end if( (BestFitDescriptor->PageCount - NoPages - BestFitAlign ...
} //end if (BestFitAlignmentOffset == 0)
return PhysicalAddress;
}
ULONGLONG
HalpGetMemorySize(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
Computes the size of the memory from the descriptor list.
Arguments:
LoaderBlock - Supplies a pointer to the loader parameter block.
Return Value:
Size of Memory in Bytes.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
PLIST_ENTRY NextMd;
ULONG PageCounts = 0;
//
// Scan the memory allocation descriptors and
// compute the Total pagecount
//
NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
Descriptor = CONTAINING_RECORD(NextMd,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
//
// ignore bad memory descriptors.
//
if(Descriptor->MemoryType != LoaderBad){
PageCounts += Descriptor->PageCount;
}
NextMd = NextMd->Flink;
}
return (PageCounts << PAGE_SHIFT) ;
}
TYPE_OF_MEMORY
HalpGetMemoryType (
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN ULONG PageAddress,
OUT PULONG EndPageAddressInDesc
)
/*++
Routine Description:
This routine checks to see how the specified address is mapped.
Arguments:
LoaderBlock - Supplies a pointer to the loader parameter block.
PageAddress - The page address of memory to probe.
Return Value:
The memory type of the specified address, if it is mapped. If the
address is not mapped, then LoaderMaximum is returned.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
PLIST_ENTRY NextMd;
ULONG PageCounts = 0;
TYPE_OF_MEMORY MemoryType = LoaderMaximum;
NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
Descriptor = CONTAINING_RECORD(NextMd,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if ((PageAddress >= Descriptor->BasePage) &&
(PageAddress <
Descriptor->BasePage + Descriptor->PageCount)) {
MemoryType = Descriptor->MemoryType;
*EndPageAddressInDesc = Descriptor->BasePage +
Descriptor->PageCount - 1;
break; // we found the descriptor.
}
NextMd = NextMd->Flink;
}
return MemoryType;
}
ULONGLONG
HalpGetContiguousMemorySize(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
Computes the size of initial contiguous memory from the
descriptor list. Contiguous memory means, that there is
no hole or Bad memory in this range.
Arguments:
LoaderBlock - Supplies a pointer to the loader parameter block.
Return Value:
Size of Memory in Bytes.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
PLIST_ENTRY NextMd;
ULONG PageCounts = 0;
TYPE_OF_MEMORY MemoryType;
ULONG EndPageAddressInDesc = 0;
//
// Start from Page Address 0 and go until we hit a page
// with no descriptor or Bad Descriptor.
//
MemoryType = HalpGetMemoryType(LoaderBlock,
PageCounts,
&EndPageAddressInDesc
);
while(MemoryType != LoaderMaximum && MemoryType != LoaderBad){
PageCounts = EndPageAddressInDesc + 1;
MemoryType = HalpGetMemoryType(LoaderBlock,
PageCounts,
&EndPageAddressInDesc
);
}
return (PageCounts << PAGE_SHIFT) ;
}
#if HALDBG
VOID
HalpDumpMemoryDescriptors(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
Print the contents of the memory descriptors built by the
firmware and OS loader and passed through to the kernel.
This routine is intended as a sanity check that the descriptors
have been prepared properly and that no memory has been wasted.
Arguments:
LoaderBlock - Supplies a pointer to the loader parameter block.
Return Value:
None.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
PLIST_ENTRY NextMd;
ULONG PageCounts[LoaderMaximum];
PCHAR MemoryTypeStrings[] = {
"ExceptionBlock",
"SystemBlock",
"Free",
"Bad",
"LoadedProgram",
"FirmwareTemporary",
"FirmwarePermanent",
"OsloaderHeap",
"OsloaderStack",
"SystemCode",
"HalCode",
"BootDriver",
"ConsoleInDriver",
"ConsoleOutDriver",
"StartupDpcStack",
"StartupKernelStack",
"StartupPanicStack",
"StartupPcrPage",
"StartupPdrPage",
"RegistryData",
"MemoryData",
"NlsData",
"SpecialMemory"
};
ULONG i;
//
// Clear the summary information structure.
//
RtlZeroMemory( PageCounts, sizeof(ULONG) * LoaderMaximum );
//
// Scan the memory allocation descriptors print each descriptor and
// collect summary information.
//
NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
Descriptor = CONTAINING_RECORD(NextMd,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if( (Descriptor->MemoryType >= LoaderExceptionBlock) &&
(Descriptor->MemoryType < LoaderMaximum) )
{
PageCounts[Descriptor->MemoryType] += Descriptor->PageCount;
DbgPrint( "%08x: %08x Type = %s\n",
(Descriptor->BasePage << PAGE_SHIFT) | KSEG0_BASE,
( ( (Descriptor->BasePage + Descriptor->PageCount)
<< PAGE_SHIFT) - 1) | KSEG0_BASE,
MemoryTypeStrings[Descriptor->MemoryType] );
} else {
DbgPrint( "%08x: %08x Unrecognized Memory Type = %x\n",
(Descriptor->BasePage << PAGE_SHIFT) | KSEG0_BASE,
( ( (Descriptor->BasePage + Descriptor->PageCount)
<< PAGE_SHIFT) - 1) | KSEG0_BASE,
Descriptor->MemoryType );
DbgPrint( "Unrecognized memory type\n" );
}
NextMd = NextMd->Flink;
}
//
// Print the summary information.
//
for( i=LoaderExceptionBlock; i<LoaderMaximum; i++ ){
//
// Only print those memory types that have non-zero allocations.
//
if( PageCounts[i] != 0 ){
DbgPrint( "%8dK %s\n",
(PageCounts[i] << PAGE_SHIFT) / __1K,
MemoryTypeStrings[i] );
}
}
return;
}
#endif //HALDBG