page.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,579 行 · 第 1/3 页
C
1,579 行
/*++
Copyright (c) 2004 - 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
page.c
Abstract:
EFI Memory page management
Revision History
--*/
#include "imem.h"
#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
//
// Entry for tracking the memory regions for each memory type to help cooalese like memory types
//
typedef struct {
EFI_PHYSICAL_ADDRESS BaseAddress;
EFI_PHYSICAL_ADDRESS MaximumAddress;
UINT64 CurrentNumberOfPages;
UINTN InformationIndex;
} EFI_MEMORY_TYPE_STAISTICS;
//
// MemoryMap - The current memory map
//
UINTN mMemoryMapKey = 0;
//
// mMapStack - space to use as temp storage to build new map descriptors
// mMapDepth - depth of new descriptor stack
//
#define MAX_MAP_DEPTH 6
UINTN mMapDepth = 0;
MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
UINTN mFreeMapStack = 0;
BOOLEAN mMemoryTypeInformationInitialized = FALSE;
EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiReservedMemoryType
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiLoaderCode
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiLoaderData
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiBootServicesCode
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiBootServicesData
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiRuntimeServicesCode
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiRuntimeServicesData
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiConventionalMemory
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiUnusableMemory
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiACPIReclaimMemory
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiACPIMemoryNVS
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiMemoryMappedIO
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiMemoryMappedIOPortSpace
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiPalCode
{ 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType } // EfiMaxMemoryType
};
EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS;
EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
{ EfiReservedMemoryType, 0 },
{ EfiLoaderCode, 0 },
{ EfiLoaderData, 0 },
{ EfiBootServicesCode, 0 },
{ EfiBootServicesData, 0 },
{ EfiRuntimeServicesCode, 0 },
{ EfiRuntimeServicesData, 0 },
{ EfiConventionalMemory, 0 },
{ EfiUnusableMemory, 0 },
{ EfiACPIReclaimMemory, 0 },
{ EfiACPIMemoryNVS, 0 },
{ EfiMemoryMappedIO, 0 },
{ EfiMemoryMappedIOPortSpace, 0 },
{ EfiPalCode, 0 },
{ EfiMaxMemoryType, 0 }
};
//
// Internal prototypes
//
VOID
PromoteMemoryResource (
VOID
);
STATIC
VOID
CoreAddRange (
IN EFI_MEMORY_TYPE Type,
IN EFI_PHYSICAL_ADDRESS Start,
IN EFI_PHYSICAL_ADDRESS End,
IN UINT64 Attribute
);
STATIC
VOID
CoreFreeMemoryMapStack (
VOID
);
STATIC
EFI_STATUS
CoreConvertPages (
IN UINT64 Start,
IN UINT64 NumberOfPages,
IN EFI_MEMORY_TYPE NewType
);
STATIC
VOID
RemoveMemoryMapEntry (
MEMORY_MAP *Entry
);
VOID
CoreAcquireMemoryLock (
VOID
)
/*++
Routine Description:
Enter critical section by gaining lock on gMemoryLock
Arguments:
None
Returns:
None
--*/
{
CoreAcquireLock (&gMemoryLock);
}
VOID
CoreReleaseMemoryLock (
VOID
)
/*++
Routine Description:
Exit critical section by releasing lock on gMemoryLock
Arguments:
None
Returns:
None
--*/
{
CoreReleaseLock (&gMemoryLock);
}
VOID
PromoteMemoryResource (
VOID
)
/*++
Routine Description:
Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
Arguments:
None
Returns:
None
--*/
{
EFI_LIST_ENTRY *Link;
EFI_GCD_MAP_ENTRY *Entry;
DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "Promote the memory resource\n"));
CoreAcquireGcdMemoryLock ();
Link = mGcdMemorySpaceMap.ForwardLink;
while (Link != &mGcdMemorySpaceMap) {
Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
Entry->EndAddress < EFI_MAX_ADDRESS &&
(Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
//
// Update the GCD map
//
Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
Entry->Capabilities |= EFI_MEMORY_TESTED;
Entry->ImageHandle = gDxeCoreImageHandle;
Entry->DeviceHandle = NULL;
//
// Add to allocable system memory resource
//
CoreAddRange (
EfiConventionalMemory,
Entry->BaseAddress,
Entry->EndAddress,
Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
);
CoreFreeMemoryMapStack ();
}
Link = Link->ForwardLink;
}
CoreReleaseGcdMemoryLock ();
return;
}
VOID
CoreAddMemoryDescriptor (
IN EFI_MEMORY_TYPE Type,
IN EFI_PHYSICAL_ADDRESS Start,
IN UINT64 NumberOfPages,
IN UINT64 Attribute
)
/*++
Routine Description:
Called to initialize the memory map and add descriptors to
the current descriptor list.
N.B. The first descriptor that is added must be general usable
memory as the addition allocates heap.
Arguments:
Type - The type of memory to add
Start - The starting address in the memory range
Must be page aligned
NumberOfPages - The number of pages in the range
Attribute - Attributes of the memory to add
Returns:
None. The range is added to the memory map
--*/
{
EFI_PHYSICAL_ADDRESS End;
EFI_STATUS Status;
UINTN Index;
UINTN FreeIndex;
if ((Start & EFI_PAGE_MASK) != 0) {
return;
}
if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {
return;
}
CoreAcquireMemoryLock ();
End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
CoreAddRange (Type, Start, End, Attribute);
CoreFreeMemoryMapStack ();
CoreReleaseMemoryLock ();
//
// Check to see if the statistics for the different memory types have already been established
//
if (mMemoryTypeInformationInitialized) {
return;
}
//
// Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
//
for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
//
// Make sure the memory type in the gMemoryTypeInformation[] array is valid
//
Type = gMemoryTypeInformation[Index].Type;
if (Type < 0 || Type > EfiMaxMemoryType) {
continue;
}
if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
//
// Allocate pages for the current memory type from the top of available memory
//
Status = CoreAllocatePages (
AllocateAnyPages,
Type,
gMemoryTypeInformation[Index].NumberOfPages,
&mMemoryTypeStatistics[Type].BaseAddress
);
if (EFI_ERROR (Status)) {
//
// If an error occurs allocating the pages for the current memory type, then
// free all the pages allocates for the previous memory types and return. This
// operation with be retied when/if more memory is added to the system
//
for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
//
// Make sure the memory type in the gMemoryTypeInformation[] array is valid
//
Type = gMemoryTypeInformation[FreeIndex].Type;
if (Type < 0 || Type > EfiMaxMemoryType) {
continue;
}
if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
CoreFreePages (
mMemoryTypeStatistics[Type].BaseAddress,
gMemoryTypeInformation[FreeIndex].NumberOfPages
);
mMemoryTypeStatistics[Type].BaseAddress = 0;
mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS;
}
}
return;
}
//
// Compute the address at the top of the current statistics
//
mMemoryTypeStatistics[Type].MaximumAddress =
mMemoryTypeStatistics[Type].BaseAddress +
LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
//
// If the current base address is the lowest address so far, then update the default
// maximum address
//
if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
}
}
}
//
// There was enough system memory for all the the memory types were allocated. So,
// those memory areas can be freed for future allocations, and all future memory
// allocations can occur within their respective bins
//
for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
//
// Make sure the memory type in the gMemoryTypeInformation[] array is valid
//
Type = gMemoryTypeInformation[Index].Type;
if (Type < 0 || Type > EfiMaxMemoryType) {
continue;
}
if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
CoreFreePages (
mMemoryTypeStatistics[Type].BaseAddress,
gMemoryTypeInformation[Index].NumberOfPages
);
gMemoryTypeInformation[Index].NumberOfPages = 0;
}
}
//
// If the number of pages reserved for a memory type is 0, then all allocations for that type
// should be in the default range.
//
for (Type = 0; Type < EfiMaxMemoryType; Type++) {
for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
mMemoryTypeStatistics[Type].InformationIndex = Index;
}
}
mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) {
mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
}
}
mMemoryTypeInformationInitialized = TRUE;
}
STATIC
VOID
CoreAddRange (
IN EFI_MEMORY_TYPE Type,
IN EFI_PHYSICAL_ADDRESS Start,
IN EFI_PHYSICAL_ADDRESS End,
IN UINT64 Attribute
)
/*++
Routine Description:
Internal function. Adds a ranges to the memory map.
The range must not already exist in the map.
Arguments:
Type - The type of memory range to add
Start - The starting address in the memory range
Must be paged aligned
End - The last address in the range
Must be the last byte of a page
Attribute - The attributes of the memory range to add
Returns:
None. The range is added to the memory map
--*/
{
EFI_LIST_ENTRY *Link;
MEMORY_MAP *Entry;
ASSERT ((Start & EFI_PAGE_MASK) == 0);
ASSERT (End > Start) ;
ASSERT_LOCKED (&gMemoryLock);
DEBUG ((EFI_D_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, (UINTN)Type));
//
// Memory map being altered
//
mMemoryMapKey += 1;
//
// Look for adjoining memory descriptor
//
// Two memory descriptors can only be merged if they have the same Type
// and the same Attribute
//
Link = gMemoryMap.ForwardLink;
while (Link != &gMemoryMap) {
Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
Link = Link->ForwardLink;
if (Entry->Type != Type) {
continue;
}
if (Entry->Attribute != Attribute) {
continue;
}
if (Entry->End + 1 == Start) {
Start = Entry->Start;
RemoveMemoryMapEntry (Entry);
} else if (Entry->Start == End + 1) {
End = Entry->End;
RemoveMemoryMapEntry (Entry);
}
}
//
// Add descriptor
//
mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
mMapStack[mMapDepth].FromPool = FALSE;
mMapStack[mMapDepth].Type = Type;
mMapStack[mMapDepth].Start = Start;
mMapStack[mMapDepth].End = End;
mMapStack[mMapDepth].VirtualStart = 0;
mMapStack[mMapDepth].Attribute = Attribute;
InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
mMapDepth += 1;
ASSERT (mMapDepth < MAX_MAP_DEPTH);
return ;
}
STATIC
VOID
CoreFreeMemoryMapStack (
VOID
)
/*++
Routine Description:
Internal function. Moves any memory descriptors that are on the
temporary descriptor stack to heap.
Arguments:
None
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?