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