📄 page.c
字号:
/*++
Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
Module Name:
Abstract:
Revision History
--*/
#include "imem.h"
#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
#ifdef EFI64
#define EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE * 2)
#else
#define EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
#endif
//
// MemoryMap - the curernt memory map
//
UINTN MemoryMapKey = 0;
//
// MapStack - space to use as temp storage to build new map descriptors
// MapDepth - depth of new descriptor stack
//
#define MAX_MAP_DEPTH 6
UINTN MapDepth = 0;
MEMORY_MAP MapStack[MAX_MAP_DEPTH];
UINTN FreeMapStack = 0;
//
// Watermarks to cooalese like memory types (IA-32 values)
//
#define EFI_RUNTIME_SERVICES_CODE_RESERVE (0x010000 * sizeof(UINTN))
#define EFI_RUNTIME_SERVICES_DATA_RESERVE (0x030000 * sizeof(UINTN))
#define EFI_BOOT_SERVICES_CODE_RESERVE (0x080000 * sizeof(UINTN))
#define EFI_BOOT_SERVICES_DATA_RESERVE (0x140000 * sizeof(UINTN))
UINT64 EfiWatermarkRuntimeServicesCode = MAX_ADDRESS;
UINT64 EfiWatermarkRuntimeServicesData = MAX_ADDRESS;
UINT64 EfiWatermarkBootServicesCode = MAX_ADDRESS;
UINT64 EfiWatermarkBootServicesData = MAX_ADDRESS;
UINT64 EfiWatermarkDefault = MAX_ADDRESS;
//
// Internal prototypes
//
STATIC
VOID
AddRange (
IN EFI_MEMORY_TYPE Type,
IN EFI_PHYSICAL_ADDRESS Start,
IN EFI_PHYSICAL_ADDRESS End,
IN UINT64 Attribute
);
STATIC
VOID
FreeMemoryMapStack (
VOID
);
STATIC
EFI_STATUS
ConvertPages (
IN BOOLEAN LoadConvert,
IN UINT64 Start,
IN UINT64 NoPages,
IN EFI_MEMORY_TYPE NewType
);
STATIC
UINT64
FindFreePages (
IN UINT64 MaxAddress,
IN UINT64 NoPages,
IN EFI_MEMORY_TYPE NewType,
IN UINTN Alignment
);
STATIC
VOID
RemoveMemoryMapEntry (
MEMORY_MAP *Entry
);
//
//
//
VOID
InitializeMemoryMap (
VOID
)
/*++
Routine Description:
Initialize memory subsystem
Arguments:
None
Returns:
None
--*/
{
InitializeLock (&MemoryLock, TPL_NOTIFY);
InitializeListHead (&MemoryMap);
InitializePool ();
MemoryMapKey = 0;
MapDepth = 0;
FreeMapStack = 0;
}
VOID
InitializeMemoryMapWatermarks (
VOID
)
{
EFI_STATUS BootServicesCodeStatus;
EFI_STATUS BootServicesDataStatus;
EFI_STATUS RuntimeServicesCodeStatus;
EFI_STATUS RuntimeServicesDataStatus;
UINTN Count;
RuntimeServicesDataStatus = AllocatePages (
AllocateMaxAddress,
EfiRuntimeServicesData,
EFI_RUNTIME_SERVICES_DATA_RESERVE >> EFI_PAGE_SHIFT,
&EfiWatermarkRuntimeServicesData
);
RuntimeServicesCodeStatus = AllocatePages (
AllocateMaxAddress,
EfiRuntimeServicesCode,
EFI_RUNTIME_SERVICES_CODE_RESERVE >> EFI_PAGE_SHIFT,
&EfiWatermarkRuntimeServicesCode
);
BootServicesCodeStatus = AllocatePages (
AllocateMaxAddress,
EfiBootServicesCode,
EFI_BOOT_SERVICES_CODE_RESERVE >> EFI_PAGE_SHIFT,
&EfiWatermarkBootServicesCode
);
BootServicesDataStatus = AllocatePages (
AllocateMaxAddress,
EfiBootServicesData,
EFI_BOOT_SERVICES_DATA_RESERVE >> EFI_PAGE_SHIFT,
&EfiWatermarkBootServicesData
);
Count = 0;
if (!EFI_ERROR (RuntimeServicesCodeStatus)) {
FreePages (EfiWatermarkRuntimeServicesCode, EFI_RUNTIME_SERVICES_CODE_RESERVE >> EFI_PAGE_SHIFT);
EfiWatermarkRuntimeServicesCode += (EFI_RUNTIME_SERVICES_CODE_RESERVE - 1);
Count++;
}
if (!EFI_ERROR (RuntimeServicesDataStatus)) {
FreePages (EfiWatermarkRuntimeServicesData, EFI_RUNTIME_SERVICES_DATA_RESERVE >> EFI_PAGE_SHIFT);
EfiWatermarkRuntimeServicesData += (EFI_RUNTIME_SERVICES_DATA_RESERVE - 1);
Count++;
}
if (!EFI_ERROR (BootServicesCodeStatus)) {
FreePages (EfiWatermarkBootServicesCode, EFI_BOOT_SERVICES_CODE_RESERVE >> EFI_PAGE_SHIFT);
EfiWatermarkBootServicesCode += (EFI_BOOT_SERVICES_CODE_RESERVE - 1);
Count++;
}
if (!EFI_ERROR (BootServicesDataStatus)) {
FreePages (EfiWatermarkBootServicesData, EFI_BOOT_SERVICES_DATA_RESERVE >> EFI_PAGE_SHIFT);
EfiWatermarkDefault = EfiWatermarkBootServicesData - 1;
EfiWatermarkBootServicesData += (EFI_BOOT_SERVICES_DATA_RESERVE - 1);
Count++;
}
if (Count != 4) {
EfiWatermarkRuntimeServicesCode = MAX_ADDRESS;
EfiWatermarkRuntimeServicesData = MAX_ADDRESS;
EfiWatermarkBootServicesCode = MAX_ADDRESS;
EfiWatermarkBootServicesData = MAX_ADDRESS;
EfiWatermarkDefault = MAX_ADDRESS;
}
}
VOID
FwAddMemoryDescriptor (
IN EFI_MEMORY_TYPE Type,
IN EFI_PHYSICAL_ADDRESS Start,
IN UINT64 NoPages,
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.
NoPages - The number of pages in the range
Attribute - Attributes of the memory to add
Returns:
None. The range is added to the memroy map.
--*/
{
EFI_PHYSICAL_ADDRESS End;
AcquireLock (&MemoryLock);
End = Start + LShiftU64(NoPages, EFI_PAGE_SHIFT) - 1;
AddRange (Type, Start, End, Attribute);
FreeMemoryMapStack ();
ReleaseLock (&MemoryLock);
}
STATIC
VOID
AddRange (
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 memroy map.
--*/
{
LIST_ENTRY *Link;
MEMORY_MAP *Entry;
MEMORY_MAP *Entry1;
BOOLEAN Merge;
ASSERT ((Start & EFI_PAGE_MASK) == 0);
ASSERT (End > Start) ;
ASSERT_LOCKED (&MemoryLock);
DEBUG((D_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
//
// Memory map being altered
//
MemoryMapKey += 1;
//
// Look for adjoining memory descriptor
//
// Two memory descriptors can only be merged if they have the same Type
// and the same Attribute.
//
Merge = FALSE;
Link = MemoryMap.Flink;
while (Link != &MemoryMap) {
Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
Link = Link->Flink;
if (Entry->Type != Type) {
continue;
}
if (Entry->Attribute != Attribute) {
continue;
}
if (Entry->End + 1 == Start) {
Entry->End = End;
Merge = TRUE;
}
else if (Entry->Start == End + 1) {
Entry->Start = Start;
Merge = TRUE;
}
if (Merge) {
Link = MemoryMap.Flink;
while (Link != &MemoryMap) {
Entry1 = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
Link = Link->Flink;
if (Entry->Type != Entry1->Type) {
continue;
}
if (Entry->Attribute != Entry1->Attribute) {
continue;
}
if (Entry->End + 1 == Entry1->Start) {
Entry1->Start = Entry->Start;
RemoveMemoryMapEntry (Entry);
return;
} else if (Entry->Start == Entry1->End + 1) {
Entry1->End = Entry->End;
RemoveMemoryMapEntry (Entry);
return;
}
}
return;
}
}
//
// Add descriptor
//
MapStack[MapDepth].Signature = MEMORY_MAP_SIGNATURE;
MapStack[MapDepth].FromPool = FALSE;
MapStack[MapDepth].Type = Type;
MapStack[MapDepth].Start = Start;
MapStack[MapDepth].End = End;
MapStack[MapDepth].VirtualStart = 0;
MapStack[MapDepth].Attribute = Attribute;
InsertTailList (&MemoryMap, &MapStack[MapDepth].Link);
MapDepth += 1;
ASSERT (MapDepth < MAX_MAP_DEPTH);
return;
}
STATIC
VOID
FreeMemoryMapStack (
VOID
)
/*++
Routine Description:
Internal function. Moves any memory descriptors that are on the
temporary descriptor stack to heap.
Arguments:
None.
Returns:
None.
--*/
{
MEMORY_MAP *Entry, *Entry2;
LIST_ENTRY *Link2;
ASSERT_LOCKED (&MemoryLock);
//
// If already freeing the map stack, then return
//
if (FreeMapStack) {
return ;
}
//
// Move the temporary memory descriptor stack into pool
//
FreeMapStack += 1;
while (MapDepth) {
//
// Allocate memory for a entry
//
Entry = AllocatePoolI (EfiRuntimeServicesData, sizeof(MEMORY_MAP));
//
// Update to proper entry
//
MapDepth -= 1;
if (MapStack[MapDepth].Link.Flink) {
//
// Move this entry to general pool
//
RemoveEntryList (&MapStack[MapDepth].Link);
MapStack[MapDepth].Link.Flink = NULL;
*Entry = MapStack[MapDepth];
Entry->FromPool = TRUE;
//
// Find insertion location
//
for (Link2 = MemoryMap.Flink; Link2 != &MemoryMap; Link2 = Link2->Flink) {
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
//
FreePoolI (Entry);
}
}
FreeMapStack -= 1;
}
STATIC
VOID
RemoveMemoryMapEntry (
MEMORY_MAP *Entry
)
/*++
Routine Description:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -