page.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,579 行 · 第 1/3 页
C
1,579 行
Returns:
None
--*/
{
MEMORY_MAP *Entry;
MEMORY_MAP *Entry2;
EFI_LIST_ENTRY *Link2;
ASSERT_LOCKED (&gMemoryLock);
//
// If already freeing the map stack, then return
//
if (mFreeMapStack) {
return ;
}
//
// Move the temporary memory descriptor stack into pool
//
mFreeMapStack += 1;
while (mMapDepth) {
//
// Allocate memory for a entry
//
Entry = CoreAllocatePoolI (EfiRuntimeServicesData, sizeof(MEMORY_MAP));
ASSERT (Entry);
//
// Update to proper entry
//
mMapDepth -= 1;
if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
//
// Move this entry to general pool
//
RemoveEntryList (&mMapStack[mMapDepth].Link);
mMapStack[mMapDepth].Link.ForwardLink = NULL;
*Entry = mMapStack[mMapDepth];
Entry->FromPool = TRUE;
//
// Find insertion location
//
for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
if (Entry2->FromPool && Entry2->Start > Entry->Start) {
break;
}
}
InsertTailList (Link2, &Entry->Link);
} else {
//
// It was removed, don't move it
//
CoreFreePoolI (Entry);
}
}
mFreeMapStack -= 1;
}
STATIC
VOID
RemoveMemoryMapEntry (
MEMORY_MAP *Entry
)
/*++
Routine Description:
Internal function. Removes a descriptor entry.
Arguments:
Entry - The entry to remove
Returns:
None
--*/
{
RemoveEntryList (&Entry->Link);
Entry->Link.ForwardLink = NULL;
if (Entry->FromPool) {
CoreFreePoolI (Entry);
}
}
STATIC
EFI_STATUS
CoreConvertPages (
IN UINT64 Start,
IN UINT64 NumberOfPages,
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:
Start - The first address of the range
Must be page aligned
NumberOfPages - The number of pages to convert
NewType - The new type for the memory range
Returns:
EFI_INVALID_PARAMETER - Invalid parameter
EFI_NOT_FOUND - Could not find a descriptor cover the specified range
or convertion not allowed.
EFI_SUCCESS - Successfully converts the memory range to the specified type.
--*/
{
UINT64 NumberOfBytes;
UINT64 End;
UINT64 RangeEnd;
UINT64 Attribute;
EFI_LIST_ENTRY *Link;
MEMORY_MAP *Entry;
Entry = NULL;
NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
End = Start + NumberOfBytes - 1;
ASSERT (NumberOfPages);
ASSERT ((Start & EFI_PAGE_MASK) == 0);
ASSERT (End > Start) ;
ASSERT_LOCKED (&gMemoryLock);
if (NumberOfPages == 0 || (Start & EFI_PAGE_MASK ) || (Start > (Start + NumberOfBytes))) {
return EFI_INVALID_PARAMETER;
}
//
// Convert the entire range
//
while (Start < End) {
//
// Find the entry that the covers the range
//
for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
if (Entry->Start <= Start && Entry->End > Start) {
break;
}
}
if (Link == &gMemoryMap) {
DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "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 ((EFI_D_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, (UINTN)NewType));
//
// Debug code - verify conversion is allowed
//
if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
DEBUG ((EFI_D_ERROR , "ConvertPages: Incompatible memory types\n"));
return EFI_NOT_FOUND;
}
//
// Update counters for the number of pages allocated to each memory type
//
if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {
if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress &&
Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) {
if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
} else {
mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
}
}
}
if (NewType >= 0 && NewType < EfiMaxMemoryType) {
if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) {
mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages >
gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
}
}
}
//
// Pull range out of descriptor
//
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
//
mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
mMapStack[mMapDepth].FromPool = FALSE;
mMapStack[mMapDepth].Type = Entry->Type;
mMapStack[mMapDepth].Start = RangeEnd+1;
mMapStack[mMapDepth].End = Entry->End;
//
// Inherit Attribute from the Memory Descriptor that is being clipped
//
mMapStack[mMapDepth].Attribute = Entry->Attribute;
Entry->End = Start - 1;
ASSERT (Entry->Start < Entry->End);
Entry = &mMapStack[mMapDepth];
InsertTailList (&gMemoryMap, &Entry->Link);
mMapDepth += 1;
ASSERT (mMapDepth < 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
//
CoreAddRange (NewType, Start, RangeEnd, Attribute);
//
// Move any map descriptor stack to general pool
//
CoreFreeMemoryMapStack ();
//
// Bump the starting address, and convert the next range
//
Start = RangeEnd + 1;
}
//
// Converted the whole range, done
//
return EFI_SUCCESS;
}
STATIC
UINT64
CoreFindFreePagesI (
IN UINT64 MaxAddress,
IN UINT64 NumberOfPages,
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
NumberOfPages - Number of pages needed
NewType - The type of memory the range is going to be turned into
Alignment - Bits to align with
Returns:
The base address of the range, or 0 if the range was not found
--*/
{
UINT64 NumberOfBytes;
UINT64 Target;
UINT64 DescStart;
UINT64 DescEnd;
UINT64 DescNumberOfBytes;
EFI_LIST_ENTRY *Link;
MEMORY_MAP *Entry;
if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
return 0;
}
if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
//
// If MaxAddress is not aligned to the end of a page
//
//
// Change MaxAddress to be 1 page lower
//
MaxAddress -= (EFI_PAGE_MASK + 1);
//
// Set MaxAddress to a page boundary
//
MaxAddress &= ~EFI_PAGE_MASK;
//
// Set MaxAddress to end of the page
//
MaxAddress |= EFI_PAGE_MASK;
}
NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
Target = 0;
for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
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 satisfy the request
//
DescNumberOfBytes = DescEnd - DescStart + 1;
if (DescNumberOfBytes >= NumberOfBytes) {
//
// 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 -= NumberOfBytes - 1;
//
// If we didn't find a match, return 0
//
if ((Target & EFI_PAGE_MASK) != 0) {
return 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
Alignment - Bits to align with
Returns:
The base address of the range, or 0 if the range was not found.
--*/
{
UINT64 NewMaxAddress;
UINT64 Start;
NewMaxAddress = MaxAddress;
if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress;
} else {
if (NewMaxAddress > mDefaultMaximumAddress) {
NewMaxAddress = mDefaultMaximumAddress;
}
}
Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);
if (!Start) {
Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
if (!Start) {
//
// Here means there may be no enough memory to use, so try to go through
// all the memory descript to promote the untested memory directly
//
PromoteMemoryResource ();
//
// Allocate memory again after the memory resource re-arranged
//
Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
}
}
return Start;
}
EFI_BOOTSERVICE
EFI_STATUS
EFIAPI
CoreAllocatePages (
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN NumberOfPages,
IN 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
NumberOfPages - The number of pages to allocate
Memory - A pointer to receive the base allocated memory address
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?