📄 page.c
字号:
Internal function. Removes a descrptor entry.
Arguments:
Entry - The entry to remove
Returns:
None.
--*/
{
RemoveEntryList (&Entry->Link);
Entry->Link.Flink = NULL;
if (Entry->FromPool) {
FreePoolI (Entry);
}
}
STATIC
EFI_STATUS
ConvertPages (
IN BOOLEAN LoadConvert,
IN UINT64 Start,
IN UINT64 NoPages,
IN EFI_MEMORY_TYPE NewType
)
/*++
Routine Description:
Internal function. Converts a memory range to the specified type.
The range must exist in the memory map.
Arguments:
LoadConvert - Signifies that the range is being converted on behalf
of the loader
Start - The first address of the range.
Must be page aligned.
NoPages - The number of pages to convert
NewType - The new type for the memory range
Returns:
Status.
--*/
{
UINT64 NoBytes, End, RangeEnd, Attribute;
LIST_ENTRY *Link;
MEMORY_MAP *Entry;
NoBytes = LShiftU64(NoPages, EFI_PAGE_SHIFT);
End = Start + NoBytes - 1;
ASSERT (!EfiAtRuntime);
ASSERT (NoPages);
ASSERT ((Start & EFI_PAGE_MASK) == 0);
ASSERT (End > Start) ;
ASSERT_LOCKED (&MemoryLock);
if (!NoPages || (Start & EFI_PAGE_MASK) || (Start > Start + NoBytes)) {
return EFI_INVALID_PARAMETER;
}
//
// Convert the entire range
//
while (Start < End) {
//
// Find the entry that the covers the range
//
for (Link = MemoryMap.Flink; Link != &MemoryMap; Link = Link->Flink) {
Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
if (Entry->Start <= Start && Entry->End > Start) {
break;
}
}
if (Link == &MemoryMap) {
DEBUG((D_ERROR, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
return EFI_NOT_FOUND;
}
//
// Convert range to the end, or to the end of the descriptor
// if that's all we've got
//
RangeEnd = End;
if (Entry->End < End) {
RangeEnd = Entry->End;
}
DEBUG((D_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType));
//
// Debug code - verify conversion is allowed
//
if (!LoadConvert &&
!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
DEBUG((D_ERROR, "ConvertPages: Incompatible memory types\n"));
return EFI_NOT_FOUND;
}
//
// Memory map being altered
//
MemoryMapKey += 1;
//
// Pull range out of descritpr
//
if (Entry->Start == Start) {
// clip start
Entry->Start = RangeEnd + 1;
} else if (Entry->End == RangeEnd) {
// clip end
Entry->End = Start - 1;
} else {
// pull it out of the center. clip current
// add a new one
MapStack[MapDepth].Signature = MEMORY_MAP_SIGNATURE;
MapStack[MapDepth].FromPool = FALSE;
MapStack[MapDepth].Type = Entry->Type;
MapStack[MapDepth].Start = RangeEnd+1;
MapStack[MapDepth].End = Entry->End;
//
// Inherit Attribute from the Memory Descriptor that is being clipped
//
MapStack[MapDepth].Attribute = Entry->Attribute;
Entry->End = Start - 1;
ASSERT (Entry->Start < Entry->End);
Entry = &MapStack[MapDepth];
InsertTailList (&MemoryMap, &Entry->Link);
MapDepth += 1;
ASSERT (MapDepth < MAX_MAP_DEPTH);
}
//
// The new range inherits the same Attribute as the Entry it is being cut out of.
//
Attribute = Entry->Attribute;
//
// If the descriptor is empty, then remove it from the map
//
if (Entry->Start == Entry->End + 1) {
RemoveMemoryMapEntry (Entry);
Entry = NULL;
}
//
// Add our new range in
//
AddRange (NewType, Start, RangeEnd, Attribute);
//
// Move any map descriptor stack to general pool
//
FreeMemoryMapStack ();
//
// Bump the starting address, and convert the next range
//
Start = RangeEnd + 1;
}
//
// Coverted the whole range, done
//
return EFI_SUCCESS;
}
STATIC
UINT64
FindFreePagesI (
IN UINT64 MaxAddress,
IN UINT64 NoPages,
IN EFI_MEMORY_TYPE NewType,
IN UINTN Alignment
)
/*++
Routine Description:
Internal function. Finds a consecutive free page range below
the requested address
Arguments:
MaxAddress - The address that the range must be below
NoPages - Number of pages needed
NewType - The type of memory the range is going to be turned into
Returns:
The base address of the range, or 0 if the range was not found.
--*/
{
UINT64 NoBytes, Target;
UINT64 DescStart, DescEnd, DescNoBytes;
LIST_ENTRY *Link;
MEMORY_MAP *Entry;
if (MaxAddress < EFI_PAGE_MASK) {
return 0;
}
if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
// if MaxAddress is not aligned to the end of a page
MaxAddress -= (EFI_PAGE_MASK + 1); // Change MaxAddress to be 1 page lower
MaxAddress &= ~EFI_PAGE_MASK; // set MaxAddress to a page boundary
MaxAddress |= EFI_PAGE_MASK; // set MaxAddress to end of the page
}
if (!NoPages) {
return 0;
}
NoBytes = LShiftU64(NoPages, EFI_PAGE_SHIFT);
Target = 0;
for (Link = MemoryMap.Flink; Link != &MemoryMap; Link = Link->Flink) {
Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
//
// If it's not a free entry, don't bother with it
//
if (Entry->Type != EfiConventionalMemory) {
continue;
}
DescStart = Entry->Start;
DescEnd = Entry->End;
//
// If desc is past max allowed address, skip it
//
if (DescStart >= MaxAddress) {
continue;
}
//
// If desc ends past max allowed address, clip the end
//
if (DescEnd >= MaxAddress) {
DescEnd = MaxAddress;
}
DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
//
// Compute the number of bytes we can used from this
// descriptor, and see it's enough to statisfy the request
//
// DescNoBytes = Entry->End - Entry->Start + 1;
DescNoBytes = DescEnd - DescStart + 1;
if (DescNoBytes >= NoBytes) {
//
// If this is the best match so far remember it
//
if (DescEnd > Target) {
Target = DescEnd;
}
}
}
//
// If this is a grow down, adjust target to be the allocation base
//
Target -= NoBytes - 1;
//
// If we didn't find a match, return 0
//
if (Target & EFI_PAGE_MASK) {
Target = 0;
}
return Target;
}
STATIC
UINT64
FindFreePages (
IN UINT64 MaxAddress,
IN UINT64 NoPages,
IN EFI_MEMORY_TYPE NewType,
IN UINTN Alignment
)
/*++
Routine Description:
Internal function. Finds a consecutive free page range below
the requested address
Arguments:
MaxAddress - The address that the range must be below
NoPages - Number of pages needed
NewType - The type of memory the range is going to be turned into
Returns:
The base address of the range, or 0 if the range was not found.
--*/
{
UINT64 NewMaxAddress;
UINT64 Start;
NewMaxAddress = MaxAddress;
switch (NewType) {
case EfiRuntimeServicesCode:
if (MaxAddress > EfiWatermarkRuntimeServicesCode) {
NewMaxAddress = EfiWatermarkRuntimeServicesCode;
}
break;
case EfiRuntimeServicesData:
if (MaxAddress > EfiWatermarkRuntimeServicesData) {
NewMaxAddress = EfiWatermarkRuntimeServicesData;
}
break;
case EfiBootServicesCode:
if (MaxAddress > EfiWatermarkBootServicesCode) {
NewMaxAddress = EfiWatermarkBootServicesCode;
}
break;
case EfiBootServicesData:
if (MaxAddress > EfiWatermarkBootServicesData) {
NewMaxAddress = EfiWatermarkBootServicesData;
}
break;
case EfiLoaderCode:
case EfiLoaderData:
case EfiACPIReclaimMemory:
case EfiACPIMemoryNVS:
case EfiReservedMemoryType:
if (MaxAddress > EfiWatermarkDefault) {
NewMaxAddress = EfiWatermarkDefault;
}
break;
}
Start = FindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);
if (!Start) {
Start = FindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
}
return Start;
}
EFI_STATUS
BOOTSERVICE
BootServiceAllocatePages (
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN NoPages,
OUT EFI_PHYSICAL_ADDRESS *Memory
)
/*++
Routine Description:
Allocates pages from the memory map.
Arguments:
Type - The type of allocation to perform
MemoryType - The type of memory to turn the allocated pages into.
NoPages - The number of pages to allocate
Memory - A pointer to recieve the base allocated memory address
Returns:
Status. On success, Memory is filled in with the base address allocated
--*/
{
if (MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) {
return EFI_INVALID_PARAMETER;
}
return AllocatePages(Type,MemoryType,NoPages,Memory);
}
EFI_STATUS
AllocatePages (
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN NoPages,
OUT EFI_PHYSICAL_ADDRESS *Memory
)
/*++
Routine Description:
Allocates pages from the memory map.
Arguments:
Type - The type of allocation to perform
MemoryType - The type of memory to turn the allocated pages into.
NoPages - The number of pages to allocate
Memory - A pointer to recieve the base allocated memory address
Returns:
Status. On success, Memory is filled in with the base address allocated
--*/
{
EFI_STATUS Status;
UINT64 Start, MaxAddress;
UINTN Alignment;
if (Type < AllocateAnyPages || Type >= MaxAllocateType) {
return EFI_INVALID_PARAMETER;
}
if (EfiAtRuntime) {
return EFI_UNSUPPORTED;
}
Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
if (MemoryType == EfiACPIReclaimMemory ||
MemoryType == EfiACPIMemoryNVS ||
MemoryType == EfiRuntimeServicesCode ||
MemoryType == EfiRuntimeServicesData ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -