1) Improve how memory usage is tracked in DXE Core

2) Update GetMemoryMap() to merge adjacent memory descriptors with identical types and attributes.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10579 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
mdkinney 2010-06-14 23:21:26 +00:00
parent 2a2e33b20f
commit 2345e7d4a4
1 changed files with 165 additions and 38 deletions

View File

@ -71,6 +71,7 @@ EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
}; };
EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ADDRESS; EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ADDRESS;
EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ADDRESS;
EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = { EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
{ EfiReservedMemoryType, 0 }, { EfiReservedMemoryType, 0 },
@ -374,18 +375,20 @@ CoreFreeMemoryMapStack (
Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable. Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
**/ **/
VOID BOOLEAN
PromoteMemoryResource ( PromoteMemoryResource (
VOID VOID
) )
{ {
LIST_ENTRY *Link; LIST_ENTRY *Link;
EFI_GCD_MAP_ENTRY *Entry; EFI_GCD_MAP_ENTRY *Entry;
BOOLEAN Promoted;
DEBUG ((DEBUG_PAGE, "Promote the memory resource\n")); DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
CoreAcquireGcdMemoryLock (); CoreAcquireGcdMemoryLock ();
Promoted = FALSE;
Link = mGcdMemorySpaceMap.ForwardLink; Link = mGcdMemorySpaceMap.ForwardLink;
while (Link != &mGcdMemorySpaceMap) { while (Link != &mGcdMemorySpaceMap) {
@ -415,6 +418,7 @@ PromoteMemoryResource (
); );
CoreFreeMemoryMapStack (); CoreFreeMemoryMapStack ();
Promoted = TRUE;
} }
Link = Link->ForwardLink; Link = Link->ForwardLink;
@ -422,7 +426,7 @@ PromoteMemoryResource (
CoreReleaseGcdMemoryLock (); CoreReleaseGcdMemoryLock ();
return; return Promoted;
} }
/** /**
This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
@ -744,8 +748,8 @@ CoreConvertPages (
// Update counters for the number of pages allocated to each memory type // Update counters for the number of pages allocated to each memory type
// //
if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) { if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {
if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||
Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) { (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) { if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0; mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
} else { } else {
@ -755,10 +759,10 @@ CoreConvertPages (
} }
if (NewType >= 0 && NewType < EfiMaxMemoryType) { if (NewType >= 0 && NewType < EfiMaxMemoryType) {
if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) { if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||
(Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages; mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages; gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
} }
} }
@ -869,6 +873,7 @@ CoreConvertPages (
UINT64 UINT64
CoreFindFreePagesI ( CoreFindFreePagesI (
IN UINT64 MaxAddress, IN UINT64 MaxAddress,
IN UINT64 MinAddress,
IN UINT64 NumberOfPages, IN UINT64 NumberOfPages,
IN EFI_MEMORY_TYPE NewType, IN EFI_MEMORY_TYPE NewType,
IN UINTN Alignment IN UINTN Alignment
@ -925,9 +930,9 @@ CoreFindFreePagesI (
DescEnd = Entry->End; DescEnd = Entry->End;
// //
// If desc is past max allowed address, skip it // If desc is past max allowed address or below min allowed address, skip it
// //
if (DescStart >= MaxAddress) { if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
continue; continue;
} }
@ -947,6 +952,12 @@ CoreFindFreePagesI (
DescNumberOfBytes = DescEnd - DescStart + 1; DescNumberOfBytes = DescEnd - DescStart + 1;
if (DescNumberOfBytes >= NumberOfBytes) { if (DescNumberOfBytes >= NumberOfBytes) {
//
// If the start of the allocated range is below the min address allowed, skip it
//
if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
continue;
}
// //
// If this is the best match so far remember it // If this is the best match so far remember it
@ -994,41 +1005,62 @@ FindFreePages (
IN UINTN Alignment IN UINTN Alignment
) )
{ {
UINT64 NewMaxAddress; UINT64 Start;
UINT64 Start;
NewMaxAddress = MaxAddress; //
// Attempt to find free pages in the preferred bin based on the requested memory type
if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) { //
NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress; if (NewType >= 0 && NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
} else { Start = CoreFindFreePagesI (
if (NewMaxAddress > mDefaultMaximumAddress) { mMemoryTypeStatistics[NewType].MaximumAddress,
NewMaxAddress = mDefaultMaximumAddress; mMemoryTypeStatistics[NewType].BaseAddress,
NoPages,
NewType,
Alignment
);
if (Start != 0) {
return Start;
} }
} }
Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment); //
if (Start == 0) { // Attempt to find free pages in the default allocation bin
Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment); //
if (Start == 0) { if (MaxAddress >= mDefaultMaximumAddress) {
// Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType, Alignment);
// Here means there may be no enough memory to use, so try to go through if (Start != 0) {
// all the memory descript to promote the untested memory directly if (Start < mDefaultBaseAddress) {
// mDefaultBaseAddress = Start;
PromoteMemoryResource (); }
return Start;
//
// Allocate memory again after the memory resource re-arranged
//
Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
} }
} }
return Start; //
// The allocation did not succeed in any of the prefered bins even after
// promoting resources. Attempt to find free pages anywhere is the requested
// address range. If this allocation fails, then there are not enough
// resources anywhere to satisfy the request.
//
Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment);
if (Start != 0) {
return Start;
}
//
// If allocations from the preferred bins fail, then attempt to promote memory resources.
//
if (!PromoteMemoryResource ()) {
return 0;
}
//
// If any memory resources were promoted, then re-attempt the allocation
//
return FindFreePages (MaxAddress, NoPages, NewType, Alignment);
} }
/** /**
Allocates pages from the memory map. Allocates pages from the memory map.
@ -1206,6 +1238,86 @@ Done:
return Status; return Status;
} }
/**
This function checks to see if the last memory map descriptor in a memory map
can be merged with any of the other memory map descriptors in a memorymap.
Memory descriptors may be merged if they are adjacent and have the same type
and attributes.
@param MemoryMap A pointer to the start of the memory map.
@param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
@param DescriptorSize The size, in bytes, of an individual
EFI_MEMORY_DESCRIPTOR.
@return A pointer to the next available descriptor in MemoryMap
**/
EFI_MEMORY_DESCRIPTOR *
MergeMemoryMapDescriptor (
IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
IN UINTN DescriptorSize
)
{
//
// Traverse the array of descriptors in MemoryMap
//
for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
//
// Check to see if the Type fields are identical.
//
if (MemoryMap->Type != MemoryMapDescriptor->Type) {
continue;
}
//
// Check to see if the Attribute fields are identical.
//
if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
continue;
}
//
// Check to see if MemoryMapDescriptor is immediately above MemoryMap
//
if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
//
// Merge MemoryMapDescriptor into MemoryMap
//
MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
//
// Return MemoryMapDescriptor as the next available slot int he MemoryMap array
//
return MemoryMapDescriptor;
}
//
// Check to see if MemoryMapDescriptor is immediately below MemoryMap
//
if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
//
// Merge MemoryMapDescriptor into MemoryMap
//
MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
//
// Return MemoryMapDescriptor as the next available slot int he MemoryMap array
//
return MemoryMapDescriptor;
}
}
//
// MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
//
// Return the slot immediately after MemoryMapDescriptor as the next available
// slot in the MemoryMap array
//
return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
}
/** /**
This function returns a copy of the current memory map. The map is an array of This function returns a copy of the current memory map. The map is an array of
@ -1255,6 +1367,7 @@ CoreGetMemoryMap (
MEMORY_MAP *Entry; MEMORY_MAP *Entry;
EFI_GCD_MAP_ENTRY *GcdMapEntry; EFI_GCD_MAP_ENTRY *GcdMapEntry;
EFI_MEMORY_TYPE Type; EFI_MEMORY_TYPE Type;
EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
// //
// Make sure the parameters are valid // Make sure the parameters are valid
@ -1320,6 +1433,7 @@ CoreGetMemoryMap (
// Build the map // Build the map
// //
ZeroMem (MemoryMap, BufferSize); ZeroMem (MemoryMap, BufferSize);
MemoryMapStart = MemoryMap;
for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
ASSERT (Entry->VirtualStart == 0); ASSERT (Entry->VirtualStart == 0);
@ -1353,7 +1467,11 @@ CoreGetMemoryMap (
MemoryMap->Attribute |= EFI_MEMORY_RUNTIME; MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
} }
MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size); //
// Check to see if the new Memory Map Descriptor can be merged with an
// existing descriptor if they are adjacent and have the same attributes
//
MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
} }
for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) { for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
@ -1380,11 +1498,20 @@ CoreGetMemoryMap (
} }
} }
MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size); //
// Check to see if the new Memory Map Descriptor can be merged with an
// existing descriptor if they are adjacent and have the same attributes
//
MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
} }
} }
} }
//
// Compute the size of the buffer actually used after all memory map descriptor merge operations
//
BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
Done: Done: