/** @file\r
UEFI Memory page management functions.\r
\r
-Copyright (c) 2007 - 2008, Intel Corporation. <BR>\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
http://opensource.org/licenses/bsd-license.php\r
**/\r
\r
#include "DxeMain.h"\r
+#include "Imem.h"\r
\r
#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)\r
\r
//\r
UINTN mMemoryMapKey = 0;\r
\r
-//\r
-// mMapStack - space to use as temp storage to build new map descriptors\r
-// mMapDepth - depth of new descriptor stack\r
-//\r
-\r
#define MAX_MAP_DEPTH 6\r
+\r
+///\r
+/// mMapDepth - depth of new descriptor stack\r
+///\r
UINTN mMapDepth = 0;\r
+///\r
+/// mMapStack - space to use as temp storage to build new map descriptors\r
+///\r
MEMORY_MAP mMapStack[MAX_MAP_DEPTH];\r
UINTN mFreeMapStack = 0;\r
-//\r
-// This list maintain the free memory map list\r
-//\r
+///\r
+/// This list maintain the free memory map list\r
+///\r
LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
BOOLEAN mMemoryTypeInformationInitialized = FALSE;\r
\r
EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode\r
- { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode\r
+ { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType\r
};\r
\r
-EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS;\r
+EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ADDRESS;\r
\r
EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {\r
{ EfiReservedMemoryType, 0 },\r
{ EfiPalCode, 0 },\r
{ EfiMaxMemoryType, 0 }\r
};\r
-\r
//\r
-// Internal prototypes\r
+// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated\r
+// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a \r
+// address assigned by DXE core.\r
//\r
-/**\r
- Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.\r
-\r
-**/\r
-VOID\r
-PromoteMemoryResource (\r
- VOID\r
- );\r
-\r
-/**\r
- Internal function. Adds a ranges to the memory map.\r
- The range must not already exist in the map.\r
-\r
- @param Type The type of memory range to add\r
- @param Start The starting address in the memory range Must be\r
- paged aligned\r
- @param End The last address in the range Must be the last\r
- byte of a page\r
- @param Attribute The attributes of the memory range to add\r
-\r
-**/\r
-VOID\r
-CoreAddRange (\r
- IN EFI_MEMORY_TYPE Type,\r
- IN EFI_PHYSICAL_ADDRESS Start,\r
- IN EFI_PHYSICAL_ADDRESS End,\r
- IN UINT64 Attribute\r
- );\r
-\r
-/**\r
- Internal function. Moves any memory descriptors that are on the\r
- temporary descriptor stack to heap.\r
-\r
-**/\r
-VOID\r
-CoreFreeMemoryMapStack (\r
- VOID\r
- );\r
-\r
-/**\r
- Internal function. Converts a memory range to the specified type.\r
- The range must exist in the memory map.\r
-\r
- @param Start The first address of the range Must be page\r
- aligned\r
- @param NumberOfPages The number of pages to convert\r
- @param NewType The new type for the memory range\r
-\r
- @retval EFI_INVALID_PARAMETER Invalid parameter\r
- @retval EFI_NOT_FOUND Could not find a descriptor cover the specified\r
- range or convertion not allowed.\r
- @retval EFI_SUCCESS Successfully converts the memory range to the\r
- specified type.\r
-\r
-**/\r
-EFI_STATUS\r
-CoreConvertPages (\r
- IN UINT64 Start,\r
- IN UINT64 NumberOfPages,\r
- IN EFI_MEMORY_TYPE NewType\r
- );\r
-\r
-/**\r
- Internal function. Removes a descriptor entry.\r
-\r
- @param Entry The entry to remove\r
-\r
-**/\r
-VOID\r
-RemoveMemoryMapEntry (\r
- IN OUT MEMORY_MAP *Entry\r
- );\r
-\r
-/**\r
- Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.\r
- If the list is emtry, then allocate a new page to refuel the list.\r
- Please Note this algorithm to allocate the memory map descriptor has a property\r
- that the memory allocated for memory entries always grows, and will never really be freed\r
- For example, if the current boot uses 2000 memory map entries at the maximum point, but\r
- ends up with only 50 at the time the OS is booted, then the memory associated with the 1950\r
- memory map entries is still allocated from EfiBootServicesMemory.\r
-\r
-\r
- @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
-\r
-**/\r
-MEMORY_MAP *\r
-AllocateMemoryMapEntry (\r
- VOID\r
- );\r
-\r
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;\r
\r
/**\r
Enter critical section by gaining lock on gMemoryLock.\r
}\r
\r
\r
-/**\r
- Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.\r
-\r
-**/\r
-VOID\r
-PromoteMemoryResource (\r
- VOID\r
- )\r
-{\r
- LIST_ENTRY *Link;\r
- EFI_GCD_MAP_ENTRY *Entry;\r
-\r
- DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));\r
-\r
- CoreAcquireGcdMemoryLock ();\r
-\r
- Link = mGcdMemorySpaceMap.ForwardLink;\r
- while (Link != &mGcdMemorySpaceMap) {\r
-\r
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
-\r
- if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
- Entry->EndAddress < EFI_MAX_ADDRESS &&\r
- (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
- (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {\r
- //\r
- // Update the GCD map\r
- //\r
- Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;\r
- Entry->Capabilities |= EFI_MEMORY_TESTED;\r
- Entry->ImageHandle = gDxeCoreImageHandle;\r
- Entry->DeviceHandle = NULL;\r
-\r
- //\r
- // Add to allocable system memory resource\r
- //\r
-\r
- CoreAddRange (\r
- EfiConventionalMemory,\r
- Entry->BaseAddress,\r
- Entry->EndAddress,\r
- Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
- );\r
- CoreFreeMemoryMapStack ();\r
-\r
- }\r
-\r
- Link = Link->ForwardLink;\r
- }\r
-\r
- CoreReleaseGcdMemoryLock ();\r
-\r
- return;\r
-}\r
\r
\r
/**\r
- Called to initialize the memory map and add descriptors to\r
- the current descriptor list.\r
- The first descriptor that is added must be general usable\r
- memory as the addition allocates heap.\r
-\r
- @param Type The type of memory to add\r
- @param Start The starting address in the memory range Must be\r
- page aligned\r
- @param NumberOfPages The number of pages in the range\r
- @param Attribute Attributes of the memory to add\r
+ Internal function. Removes a descriptor entry.\r
\r
- @return None. The range is added to the memory map\r
+ @param Entry The entry to remove\r
\r
**/\r
VOID\r
-CoreAddMemoryDescriptor (\r
- IN EFI_MEMORY_TYPE Type,\r
- IN EFI_PHYSICAL_ADDRESS Start,\r
- IN UINT64 NumberOfPages,\r
- IN UINT64 Attribute\r
+RemoveMemoryMapEntry (\r
+ IN OUT MEMORY_MAP *Entry\r
)\r
{\r
- EFI_PHYSICAL_ADDRESS End;\r
- EFI_STATUS Status;\r
- UINTN Index;\r
- UINTN FreeIndex;\r
-\r
- if ((Start & EFI_PAGE_MASK) != 0) {\r
- return;\r
- }\r
-\r
- if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {\r
- return;\r
- }\r
-\r
- CoreAcquireMemoryLock ();\r
- End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
- CoreAddRange (Type, Start, End, Attribute);\r
- CoreFreeMemoryMapStack ();\r
- CoreReleaseMemoryLock ();\r
-\r
- //\r
- // Check to see if the statistics for the different memory types have already been established\r
- //\r
- if (mMemoryTypeInformationInitialized) {\r
- return;\r
- }\r
-\r
- //\r
- // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array\r
- //\r
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
- //\r
- // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
- //\r
- Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
- if (Type < 0 || Type > EfiMaxMemoryType) {\r
- continue;\r
- }\r
-\r
- if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
- //\r
- // Allocate pages for the current memory type from the top of available memory\r
- //\r
- Status = CoreAllocatePages (\r
- AllocateAnyPages,\r
- Type,\r
- gMemoryTypeInformation[Index].NumberOfPages,\r
- &mMemoryTypeStatistics[Type].BaseAddress\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // If an error occurs allocating the pages for the current memory type, then\r
- // free all the pages allocates for the previous memory types and return. This\r
- // operation with be retied when/if more memory is added to the system\r
- //\r
- for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {\r
- //\r
- // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
- //\r
- Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);\r
- if (Type < 0 || Type > EfiMaxMemoryType) {\r
- continue;\r
- }\r
-\r
- if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {\r
- CoreFreePages (\r
- mMemoryTypeStatistics[Type].BaseAddress,\r
- gMemoryTypeInformation[FreeIndex].NumberOfPages\r
- );\r
- mMemoryTypeStatistics[Type].BaseAddress = 0;\r
- mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS;\r
- }\r
- }\r
- return;\r
- }\r
-\r
- //\r
- // Compute the address at the top of the current statistics\r
- //\r
- mMemoryTypeStatistics[Type].MaximumAddress =\r
- mMemoryTypeStatistics[Type].BaseAddress +\r
- LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
-\r
- //\r
- // If the current base address is the lowest address so far, then update the default\r
- // maximum address\r
- //\r
- if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {\r
- mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;\r
- }\r
- }\r
- }\r
+ RemoveEntryList (&Entry->Link);\r
+ Entry->Link.ForwardLink = NULL;\r
\r
- //\r
- // There was enough system memory for all the the memory types were allocated. So,\r
- // those memory areas can be freed for future allocations, and all future memory\r
- // allocations can occur within their respective bins\r
- //\r
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
+ if (Entry->FromPages) {\r
//\r
- // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
+ // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList\r
//\r
- Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
- if (Type < 0 || Type > EfiMaxMemoryType) {\r
- continue;\r
- }\r
-\r
- if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
- CoreFreePages (\r
- mMemoryTypeStatistics[Type].BaseAddress,\r
- gMemoryTypeInformation[Index].NumberOfPages\r
- );\r
- mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;\r
- gMemoryTypeInformation[Index].NumberOfPages = 0;\r
- }\r
- }\r
-\r
- //\r
- // If the number of pages reserved for a memory type is 0, then all allocations for that type\r
- // should be in the default range.\r
- //\r
- for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {\r
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
- if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {\r
- mMemoryTypeStatistics[Type].InformationIndex = Index;\r
- }\r
- }\r
- mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;\r
- if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) {\r
- mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;\r
- }\r
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
}\r
-\r
- mMemoryTypeInformationInitialized = TRUE;\r
}\r
\r
-\r
-\r
/**\r
Internal function. Adds a ranges to the memory map.\r
The range must not already exist in the map.\r
mMapDepth += 1;\r
ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
\r
- return ;\r
+ return ;\r
+}\r
+\r
+/**\r
+ Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.\r
+ If the list is emtry, then allocate a new page to refuel the list.\r
+ Please Note this algorithm to allocate the memory map descriptor has a property\r
+ that the memory allocated for memory entries always grows, and will never really be freed\r
+ For example, if the current boot uses 2000 memory map entries at the maximum point, but\r
+ ends up with only 50 at the time the OS is booted, then the memory associated with the 1950\r
+ memory map entries is still allocated from EfiBootServicesMemory.\r
+\r
+\r
+ @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
+\r
+**/\r
+MEMORY_MAP *\r
+AllocateMemoryMapEntry (\r
+ VOID\r
+ )\r
+{\r
+ MEMORY_MAP* FreeDescriptorEntries;\r
+ MEMORY_MAP* Entry;\r
+ UINTN Index;\r
+\r
+ if (IsListEmpty (&mFreeMemoryMapEntryList)) {\r
+ //\r
+ // The list is empty, to allocate one page to refuel the list\r
+ //\r
+ FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
+ if(FreeDescriptorEntries != NULL) {\r
+ //\r
+ // Enque the free memmory map entries into the list\r
+ //\r
+ for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) {\r
+ FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;\r
+ InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);\r
+ }\r
+ } else {\r
+ return NULL;\r
+ }\r
+ }\r
+ //\r
+ // dequeue the first descriptor from the list\r
+ //\r
+ Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ RemoveEntryList (&Entry->Link);\r
+\r
+ return Entry;\r
}\r
\r
\r
mFreeMapStack -= 1;\r
}\r
\r
-\r
/**\r
- Internal function. Removes a descriptor entry.\r
-\r
- @param Entry The entry to remove\r
+ Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.\r
\r
**/\r
VOID\r
-RemoveMemoryMapEntry (\r
- IN OUT MEMORY_MAP *Entry\r
+PromoteMemoryResource (\r
+ VOID\r
)\r
{\r
- RemoveEntryList (&Entry->Link);\r
- Entry->Link.ForwardLink = NULL;\r
+ LIST_ENTRY *Link;\r
+ EFI_GCD_MAP_ENTRY *Entry;\r
\r
- if (Entry->FromPages) {\r
- //\r
- // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList\r
- //\r
- InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
+ DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));\r
+\r
+ CoreAcquireGcdMemoryLock ();\r
+\r
+ Link = mGcdMemorySpaceMap.ForwardLink;\r
+ while (Link != &mGcdMemorySpaceMap) {\r
+\r
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
+\r
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
+ Entry->EndAddress < MAX_ADDRESS &&\r
+ (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {\r
+ //\r
+ // Update the GCD map\r
+ //\r
+ Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;\r
+ Entry->Capabilities |= EFI_MEMORY_TESTED;\r
+ Entry->ImageHandle = gDxeCoreImageHandle;\r
+ Entry->DeviceHandle = NULL;\r
+\r
+ //\r
+ // Add to allocable system memory resource\r
+ //\r
+\r
+ CoreAddRange (\r
+ EfiConventionalMemory,\r
+ Entry->BaseAddress,\r
+ Entry->EndAddress,\r
+ Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
+ );\r
+ CoreFreeMemoryMapStack ();\r
+\r
+ }\r
+\r
+ Link = Link->ForwardLink;\r
}\r
+\r
+ CoreReleaseGcdMemoryLock ();\r
+\r
+ return;\r
}\r
+/**\r
+ This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD \r
+ PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the \r
+ size of boot time and runtime code.\r
\r
+**/\r
+VOID\r
+CoreLoadingFixedAddressHook (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RuntimeCodePageNumber;\r
+ UINT32 BootTimeCodePageNumber;\r
+ EFI_PHYSICAL_ADDRESS RuntimeCodeBase;\r
+ EFI_PHYSICAL_ADDRESS BootTimeCodeBase;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Make sure these 2 areas are not initialzied.\r
+ //\r
+ if (!gLoadFixedAddressCodeMemoryReady) { \r
+ RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
+ BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
+ RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));\r
+ BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));\r
+ //\r
+ // Try to allocate runtime memory.\r
+ //\r
+ Status = CoreAllocatePages (\r
+ AllocateAddress,\r
+ EfiRuntimeServicesCode,\r
+ RuntimeCodePageNumber,\r
+ &RuntimeCodeBase\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Runtime memory allocation failed \r
+ //\r
+ return;\r
+ }\r
+ //\r
+ // Try to allocate boot memory.\r
+ //\r
+ Status = CoreAllocatePages (\r
+ AllocateAddress,\r
+ EfiBootServicesCode,\r
+ BootTimeCodePageNumber,\r
+ &BootTimeCodeBase\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // boot memory allocation failed. Free Runtime code range and will try the allocation again when \r
+ // new memory range is installed.\r
+ //\r
+ CoreFreePages (\r
+ RuntimeCodeBase,\r
+ RuntimeCodePageNumber\r
+ );\r
+ return;\r
+ }\r
+ gLoadFixedAddressCodeMemoryReady = TRUE;\r
+ } \r
+ return;\r
+} \r
\r
/**\r
- Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.\r
- If the list is emtry, then allocate a new page to refuel the list.\r
- Please Note this algorithm to allocate the memory map descriptor has a property\r
- that the memory allocated for memory entries always grows, and will never really be freed\r
- For example, if the current boot uses 2000 memory map entries at the maximum point, but\r
- ends up with only 50 at the time the OS is booted, then the memory associated with the 1950\r
- memory map entries is still allocated from EfiBootServicesMemory.\r
+ Called to initialize the memory map and add descriptors to\r
+ the current descriptor list.\r
+ The first descriptor that is added must be general usable\r
+ memory as the addition allocates heap.\r
\r
+ @param Type The type of memory to add\r
+ @param Start The starting address in the memory range Must be\r
+ page aligned\r
+ @param NumberOfPages The number of pages in the range\r
+ @param Attribute Attributes of the memory to add\r
\r
- @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
+ @return None. The range is added to the memory map\r
\r
**/\r
-MEMORY_MAP *\r
-AllocateMemoryMapEntry (\r
- VOID\r
+VOID\r
+CoreAddMemoryDescriptor (\r
+ IN EFI_MEMORY_TYPE Type,\r
+ IN EFI_PHYSICAL_ADDRESS Start,\r
+ IN UINT64 NumberOfPages,\r
+ IN UINT64 Attribute\r
)\r
{\r
- MEMORY_MAP* FreeDescriptorEntries;\r
- MEMORY_MAP* Entry;\r
- UINTN Index;\r
+ EFI_PHYSICAL_ADDRESS End;\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN FreeIndex;\r
+ \r
+ if ((Start & EFI_PAGE_MASK) != 0) {\r
+ return;\r
+ }\r
\r
- if (IsListEmpty (&mFreeMemoryMapEntryList)) {\r
+ if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {\r
+ return;\r
+ }\r
+ CoreAcquireMemoryLock ();\r
+ End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
+ CoreAddRange (Type, Start, End, Attribute);\r
+ CoreFreeMemoryMapStack ();\r
+ CoreReleaseMemoryLock ();\r
+\r
+ //\r
+ // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type\r
+ //\r
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ CoreLoadingFixedAddressHook();\r
+ }\r
+ \r
+ //\r
+ // Check to see if the statistics for the different memory types have already been established\r
+ //\r
+ if (mMemoryTypeInformationInitialized) {\r
+ return;\r
+ }\r
+\r
+ \r
+ //\r
+ // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array\r
+ //\r
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
//\r
- // The list is empty, to allocate one page to refuel the list\r
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
//\r
- FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
- if(FreeDescriptorEntries != NULL) {\r
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
+ if (Type < 0 || Type > EfiMaxMemoryType) {\r
+ continue;\r
+ }\r
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
//\r
- // Enque the free memmory map entries into the list\r
+ // Allocate pages for the current memory type from the top of available memory\r
//\r
- for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) {\r
- FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;\r
- InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);\r
+ Status = CoreAllocatePages (\r
+ AllocateAnyPages,\r
+ Type,\r
+ gMemoryTypeInformation[Index].NumberOfPages,\r
+ &mMemoryTypeStatistics[Type].BaseAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // If an error occurs allocating the pages for the current memory type, then\r
+ // free all the pages allocates for the previous memory types and return. This\r
+ // operation with be retied when/if more memory is added to the system\r
+ //\r
+ for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {\r
+ //\r
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
+ //\r
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);\r
+ if (Type < 0 || Type > EfiMaxMemoryType) {\r
+ continue;\r
+ }\r
+\r
+ if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {\r
+ CoreFreePages (\r
+ mMemoryTypeStatistics[Type].BaseAddress,\r
+ gMemoryTypeInformation[FreeIndex].NumberOfPages\r
+ );\r
+ mMemoryTypeStatistics[Type].BaseAddress = 0;\r
+ mMemoryTypeStatistics[Type].MaximumAddress = MAX_ADDRESS;\r
+ }\r
+ }\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Compute the address at the top of the current statistics\r
+ //\r
+ mMemoryTypeStatistics[Type].MaximumAddress =\r
+ mMemoryTypeStatistics[Type].BaseAddress +\r
+ LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
+\r
+ //\r
+ // If the current base address is the lowest address so far, then update the default\r
+ // maximum address\r
+ //\r
+ if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {\r
+ mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;\r
}\r
- } else {\r
- return NULL;\r
}\r
}\r
+\r
//\r
- // dequeue the first descriptor from the list\r
+ // There was enough system memory for all the the memory types were allocated. So,\r
+ // those memory areas can be freed for future allocations, and all future memory\r
+ // allocations can occur within their respective bins\r
//\r
- Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
- RemoveEntryList (&Entry->Link);\r
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
+ //\r
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
+ //\r
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
+ if (Type < 0 || Type > EfiMaxMemoryType) {\r
+ continue;\r
+ }\r
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
+ CoreFreePages (\r
+ mMemoryTypeStatistics[Type].BaseAddress,\r
+ gMemoryTypeInformation[Index].NumberOfPages\r
+ );\r
+ mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;\r
+ gMemoryTypeInformation[Index].NumberOfPages = 0;\r
+ }\r
+ }\r
\r
- return Entry;\r
+ //\r
+ // If the number of pages reserved for a memory type is 0, then all allocations for that type\r
+ // should be in the default range.\r
+ //\r
+ for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {\r
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
+ if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {\r
+ mMemoryTypeStatistics[Type].InformationIndex = Index;\r
+ }\r
+ }\r
+ mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;\r
+ if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ADDRESS) {\r
+ mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;\r
+ }\r
+ }\r
+\r
+ mMemoryTypeInformationInitialized = TRUE;\r
}\r
\r
\r
// if that's all we've got\r
//\r
RangeEnd = End;\r
+\r
+ ASSERT (Entry != NULL);\r
if (Entry->End < End) {\r
RangeEnd = Entry->End;\r
}\r
// Add our new range in\r
//\r
CoreAddRange (NewType, Start, RangeEnd, Attribute);\r
+ if (NewType == EfiConventionalMemory) {\r
+ DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));\r
+ }\r
\r
//\r
// Move any map descriptor stack to general pool\r
//\r
// The max address is the max natively addressable address for the processor\r
//\r
- MaxAddress = EFI_MAX_ADDRESS;\r
+ MaxAddress = MAX_ADDRESS;\r
\r
if (Type == AllocateMaxAddress) {\r
MaxAddress = Start;\r
}\r
}\r
if (Link == &gMemoryMap) {\r
- CoreReleaseMemoryLock ();\r
- return EFI_NOT_FOUND;\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
}\r
\r
Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;\r
\r
+ ASSERT (Entry != NULL);\r
if (Entry->Type == EfiACPIReclaimMemory ||\r
Entry->Type == EfiACPIMemoryNVS ||\r
Entry->Type == EfiRuntimeServicesCode ||\r
}\r
\r
if ((Memory & (Alignment - 1)) != 0) {\r
- CoreReleaseMemoryLock ();\r
- return EFI_INVALID_PARAMETER;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
}\r
\r
NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;\r
\r
Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
\r
- CoreReleaseMemoryLock ();\r
-\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Destroy the contents\r
- //\r
- if (Memory < EFI_MAX_ADDRESS) {\r
- DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);\r
+ goto Done;\r
}\r
\r
+Done:\r
+ CoreReleaseMemoryLock ();\r
return Status;\r
}\r
\r
MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;\r
}\r
\r
- MemoryMap = NextMemoryDescriptor (MemoryMap, Size);\r
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
}\r
\r
for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
(GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {\r
if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {\r
-\r
+ // \r
+ // Create EFI_MEMORY_DESCRIPTOR for every Reserved and MMIO GCD entries\r
+ // that are marked for runtime use\r
+ //\r
MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;\r
MemoryMap->VirtualStart = 0;\r
MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);\r
}\r
}\r
\r
- MemoryMap = NextMemoryDescriptor (MemoryMap, Size);\r
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
}\r
}\r
}\r
//\r
// Find the pages to convert\r
//\r
- Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment);\r
+ Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);\r
\r
//\r
// Convert it to boot services data\r
//\r
if (Start == 0) {\r
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages));\r
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));\r
} else {\r
CoreConvertPages (Start, NumberOfPages, PoolType);\r
}\r
\r
for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
- if (Entry->Attribute & EFI_MEMORY_RUNTIME) {\r
+ if ((Entry->Attribute & EFI_MEMORY_RUNTIME) != 0) {\r
if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {\r
DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\r
}\r
- if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
+ if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {\r
DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\r
}\r
- if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
+ if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {\r
DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\r