/** @file\r
SMM Memory page management functions.\r
\r
- Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials are licensed and made available \r
- under the terms and conditions of the BSD License which accompanies this \r
- distribution. The full text of the license may be found at \r
- http://opensource.org/licenses/bsd-license.php \r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "PiSmmCore.h"\r
+#include <Library/SmmServicesTableLib.h>\r
\r
#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)\r
\r
LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);\r
\r
+//\r
+// For GetMemoryMap()\r
+//\r
+\r
+#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')\r
+typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY Link;\r
+\r
+ BOOLEAN FromStack;\r
+ EFI_MEMORY_TYPE Type;\r
+ UINT64 Start;\r
+ UINT64 End;\r
+\r
+} MEMORY_MAP;\r
+\r
+LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);\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
+LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
+\r
+/**\r
+ Allocates pages from the memory map.\r
+\r
+ @param[in] Type The type of allocation to perform.\r
+ @param[in] MemoryType The type of memory to turn the allocated pages\r
+ into.\r
+ @param[in] NumberOfPages The number of pages to allocate.\r
+ @param[out] Memory A pointer to receive the base allocated memory\r
+ address.\r
+ @param[in] AddRegion If this memory is new added region.\r
+ @param[in] NeedGuard Flag to indicate Guard page is needed\r
+ or not\r
+\r
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
+ @retval EFI_SUCCESS Pages successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmInternalAllocatePagesEx (\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN NumberOfPages,\r
+ OUT EFI_PHYSICAL_ADDRESS *Memory,\r
+ IN BOOLEAN AddRegion,\r
+ IN BOOLEAN NeedGuard\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
+\r
+ @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
+\r
+**/\r
+MEMORY_MAP *\r
+AllocateMemoryMapEntry (\r
+ VOID\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS Mem;\r
+ EFI_STATUS Status;\r
+ MEMORY_MAP* FreeDescriptorEntries;\r
+ MEMORY_MAP* Entry;\r
+ UINTN Index;\r
+\r
+ //DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));\r
+\r
+ if (IsListEmpty (&mFreeMemoryMapEntryList)) {\r
+ //DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));\r
+ //\r
+ // The list is empty, to allocate one page to refuel the list\r
+ //\r
+ Status = SmmInternalAllocatePagesEx (\r
+ AllocateAnyPages,\r
+ EfiRuntimeServicesData,\r
+ EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY),\r
+ &Mem,\r
+ TRUE,\r
+ FALSE\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if(!EFI_ERROR (Status)) {\r
+ FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem;\r
+ //DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));\r
+ //\r
+ // Enque the free memmory map entries into the list\r
+ //\r
+ for (Index = 0; Index< RUNTIME_PAGE_ALLOCATION_GRANULARITY / 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
+/**\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
+ MEMORY_MAP *Entry;\r
+\r
+ //\r
+ // If already freeing the map stack, then return\r
+ //\r
+ if (mFreeMapStack != 0) {\r
+ ASSERT (FALSE);\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Move the temporary memory descriptor stack into pool\r
+ //\r
+ mFreeMapStack += 1;\r
+\r
+ while (mMapDepth != 0) {\r
+ //\r
+ // Deque an memory map entry from mFreeMemoryMapEntryList\r
+ //\r
+ Entry = AllocateMemoryMapEntry ();\r
+ ASSERT (Entry);\r
+\r
+ //\r
+ // Update to proper entry\r
+ //\r
+ mMapDepth -= 1;\r
+\r
+ if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
+\r
+ CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
+ Entry->FromStack = FALSE;\r
+\r
+ //\r
+ // Move this entry to general memory\r
+ //\r
+ InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link);\r
+ RemoveEntryList (&mMapStack[mMapDepth].Link);\r
+ mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
+ }\r
+ }\r
+\r
+ mFreeMapStack -= 1;\r
+}\r
+\r
+/**\r
+ Insert new entry from memory map.\r
+\r
+ @param[in] Link The old memory map entry to be linked.\r
+ @param[in] Start The start address of new memory map entry.\r
+ @param[in] End The end address of new memory map entry.\r
+ @param[in] Type The type of new memory map entry.\r
+ @param[in] Next If new entry is inserted to the next of old entry.\r
+ @param[in] AddRegion If this memory is new added region.\r
+**/\r
+VOID\r
+InsertNewEntry (\r
+ IN LIST_ENTRY *Link,\r
+ IN UINT64 Start,\r
+ IN UINT64 End,\r
+ IN EFI_MEMORY_TYPE Type,\r
+ IN BOOLEAN Next,\r
+ IN BOOLEAN AddRegion\r
+ )\r
+{\r
+ MEMORY_MAP *Entry;\r
+\r
+ Entry = &mMapStack[mMapDepth];\r
+ mMapDepth += 1;\r
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
+ Entry->FromStack = TRUE;\r
+\r
+ Entry->Signature = MEMORY_MAP_SIGNATURE;\r
+ Entry->Type = Type;\r
+ Entry->Start = Start;\r
+ Entry->End = End;\r
+ if (Next) {\r
+ InsertHeadList (Link, &Entry->Link);\r
+ } else {\r
+ InsertTailList (Link, &Entry->Link);\r
+ }\r
+}\r
+\r
+/**\r
+ Remove old entry from memory map.\r
+\r
+ @param[in] Entry Memory map entry to be removed.\r
+**/\r
+VOID\r
+RemoveOldEntry (\r
+ IN MEMORY_MAP *Entry\r
+ )\r
+{\r
+ RemoveEntryList (&Entry->Link);\r
+ Entry->Link.ForwardLink = NULL;\r
+\r
+ if (!Entry->FromStack) {\r
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
+ }\r
+}\r
+\r
+/**\r
+ Update SMM memory map entry.\r
+\r
+ @param[in] Type The type of allocation to perform.\r
+ @param[in] Memory The base of memory address.\r
+ @param[in] NumberOfPages The number of pages to allocate.\r
+ @param[in] AddRegion If this memory is new added region.\r
+**/\r
+VOID\r
+ConvertSmmMemoryMapEntry (\r
+ IN EFI_MEMORY_TYPE Type,\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NumberOfPages,\r
+ IN BOOLEAN AddRegion\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ MEMORY_MAP *NextEntry;\r
+ LIST_ENTRY *NextLink;\r
+ MEMORY_MAP *PreviousEntry;\r
+ LIST_ENTRY *PreviousLink;\r
+ EFI_PHYSICAL_ADDRESS Start;\r
+ EFI_PHYSICAL_ADDRESS End;\r
+\r
+ Start = Memory;\r
+ End = Memory + EFI_PAGES_TO_SIZE(NumberOfPages) - 1;\r
+\r
+ //\r
+ // Exclude memory region\r
+ //\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ Link = Link->ForwardLink;\r
+\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---\r
+ // +----------+ ^ +------+ +------+ +------+\r
+ // |\r
+ // +------+\r
+ // |EntryX|\r
+ // +------+\r
+ //\r
+ if (Entry->Start > End) {\r
+ if ((Entry->Start == End + 1) && (Entry->Type == Type)) {\r
+ Entry->Start = Start;\r
+ return ;\r
+ }\r
+ InsertNewEntry (\r
+ &Entry->Link,\r
+ Start,\r
+ End,\r
+ Type,\r
+ FALSE,\r
+ AddRegion\r
+ );\r
+ return ;\r
+ }\r
+\r
+ if ((Entry->Start <= Start) && (Entry->End >= End)) {\r
+ if (Entry->Type != Type) {\r
+ if (Entry->Start < Start) {\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---\r
+ // +----------+ +------+ ^ +------+ +------+\r
+ // |\r
+ // +------+\r
+ // |EntryA|\r
+ // +------+\r
+ //\r
+ InsertNewEntry (\r
+ &Entry->Link,\r
+ Entry->Start,\r
+ Start - 1,\r
+ Entry->Type,\r
+ FALSE,\r
+ AddRegion\r
+ );\r
+ }\r
+ if (Entry->End > End) {\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---\r
+ // +----------+ +------+ +------+ ^ +------+\r
+ // |\r
+ // +------+\r
+ // |EntryZ|\r
+ // +------+\r
+ //\r
+ InsertNewEntry (\r
+ &Entry->Link,\r
+ End + 1,\r
+ Entry->End,\r
+ Entry->Type,\r
+ TRUE,\r
+ AddRegion\r
+ );\r
+ }\r
+ //\r
+ // Update this node\r
+ //\r
+ Entry->Start = Start;\r
+ Entry->End = End;\r
+ Entry->Type = Type;\r
+\r
+ //\r
+ // Check adjacent\r
+ //\r
+ NextLink = Entry->Link.ForwardLink;\r
+ if (NextLink != &gMemoryMap) {\r
+ NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +-----------------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|---\r
+ // +----------+ +------+ +-----------------+\r
+ //\r
+ if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) {\r
+ Entry->End = NextEntry->End;\r
+ RemoveOldEntry (NextEntry);\r
+ }\r
+ }\r
+ PreviousLink = Entry->Link.BackLink;\r
+ if (PreviousLink != &gMemoryMap) {\r
+ PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +-----------------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|---\r
+ // +----------+ +-----------------+ +------+\r
+ //\r
+ if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) {\r
+ PreviousEntry->End = Entry->End;\r
+ RemoveOldEntry (Entry);\r
+ }\r
+ }\r
+ }\r
+ return ;\r
+ }\r
+ }\r
+\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---\r
+ // +----------+ +------+ +------+ +------+ ^\r
+ // |\r
+ // +------+\r
+ // |EntryX|\r
+ // +------+\r
+ //\r
+ Link = gMemoryMap.BackLink;\r
+ if (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ if ((Entry->End + 1 == Start) && (Entry->Type == Type)) {\r
+ Entry->End = End;\r
+ return ;\r
+ }\r
+ }\r
+ InsertNewEntry (\r
+ &gMemoryMap,\r
+ Start,\r
+ End,\r
+ Type,\r
+ FALSE,\r
+ AddRegion\r
+ );\r
+ return ;\r
+}\r
+\r
+/**\r
+ Return the count of Smm memory map entry.\r
+\r
+ @return The count of Smm memory map entry.\r
+**/\r
+UINTN\r
+GetSmmMemoryMapEntryCount (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ UINTN Count;\r
+\r
+ Count = 0;\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Link = Link->ForwardLink;\r
+ Count++;\r
+ }\r
+ return Count;\r
+}\r
+\r
+\r
+\r
/**\r
Internal Function. Allocate n pages from given free page node.\r
\r
/**\r
Allocates pages from the memory map.\r
\r
- @param Type The type of allocation to perform.\r
- @param MemoryType The type of memory to turn the allocated pages\r
- into.\r
- @param NumberOfPages The number of pages to allocate.\r
- @param Memory A pointer to receive the base allocated memory\r
- address.\r
+ @param[in] Type The type of allocation to perform.\r
+ @param[in] MemoryType The type of memory to turn the allocated pages\r
+ into.\r
+ @param[in] NumberOfPages The number of pages to allocate.\r
+ @param[out] Memory A pointer to receive the base allocated memory\r
+ address.\r
+ @param[in] AddRegion If this memory is new added region.\r
+ @param[in] NeedGuard Flag to indicate Guard page is needed\r
+ or not\r
\r
@retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
@retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-SmmInternalAllocatePages (\r
+SmmInternalAllocatePagesEx (\r
IN EFI_ALLOCATE_TYPE Type,\r
IN EFI_MEMORY_TYPE MemoryType,\r
IN UINTN NumberOfPages,\r
- OUT EFI_PHYSICAL_ADDRESS *Memory\r
+ OUT EFI_PHYSICAL_ADDRESS *Memory,\r
+ IN BOOLEAN AddRegion,\r
+ IN BOOLEAN NeedGuard\r
)\r
{\r
UINTN RequestedAddress;\r
case AllocateAnyPages:\r
RequestedAddress = (UINTN)(-1);\r
case AllocateMaxAddress:\r
+ if (NeedGuard) {\r
+ *Memory = InternalAllocMaxAddressWithGuard (\r
+ &mSmmMemoryMap,\r
+ NumberOfPages,\r
+ RequestedAddress,\r
+ MemoryType\r
+ );\r
+ if (*Memory == (UINTN)-1) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
*Memory = InternalAllocMaxAddress (\r
&mSmmMemoryMap,\r
NumberOfPages,\r
);\r
if (*Memory == (UINTN)-1) {\r
return EFI_OUT_OF_RESOURCES;\r
- } \r
+ }\r
break;\r
case AllocateAddress:\r
*Memory = InternalAllocAddress (\r
default:\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
+ //\r
+ // Update SmmMemoryMap here.\r
+ //\r
+ ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);\r
+ if (!AddRegion) {\r
+ CoreFreeMemoryMapStack();\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Allocates pages from the memory map.\r
+\r
+ @param[in] Type The type of allocation to perform.\r
+ @param[in] MemoryType The type of memory to turn the allocated pages\r
+ into.\r
+ @param[in] NumberOfPages The number of pages to allocate.\r
+ @param[out] Memory A pointer to receive the base allocated memory\r
+ address.\r
+ @param[in] NeedGuard Flag to indicate Guard page is needed\r
+ or not\r
+\r
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
+ @retval EFI_SUCCESS Pages successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInternalAllocatePages (\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN NumberOfPages,\r
+ OUT EFI_PHYSICAL_ADDRESS *Memory,\r
+ IN BOOLEAN NeedGuard\r
+ )\r
+{\r
+ return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory,\r
+ FALSE, NeedGuard);\r
+}\r
+\r
/**\r
Allocates pages from the memory map.\r
\r
)\r
{\r
EFI_STATUS Status;\r
+ BOOLEAN NeedGuard;\r
\r
- Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);\r
+ NeedGuard = IsPageTypeToGuard (MemoryType, Type);\r
+ Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,\r
+ NeedGuard);\r
if (!EFI_ERROR (Status)) {\r
SmmCoreUpdateProfile (\r
(EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
/**\r
Frees previous allocated pages.\r
\r
- @param Memory Base address of memory being freed.\r
- @param NumberOfPages The number of pages to free.\r
+ @param[in] Memory Base address of memory being freed.\r
+ @param[in] NumberOfPages The number of pages to free.\r
+ @param[in] AddRegion If this memory is new added region.\r
\r
@retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
- @retval EFI_INVALID_PARAMETER Address not aligned.\r
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
@return EFI_SUCCESS Pages successfully freed.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-SmmInternalFreePages (\r
+SmmInternalFreePagesEx (\r
IN EFI_PHYSICAL_ADDRESS Memory,\r
- IN UINTN NumberOfPages\r
+ IN UINTN NumberOfPages,\r
+ IN BOOLEAN AddRegion\r
)\r
{\r
LIST_ENTRY *Node;\r
FREE_PAGE_LIST *Pages;\r
\r
- if ((Memory & EFI_PAGE_MASK) != 0) {\r
+ if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
InternalMergeNodes (Pages);\r
}\r
\r
+ //\r
+ // Update SmmMemoryMap here.\r
+ //\r
+ ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);\r
+ if (!AddRegion) {\r
+ CoreFreeMemoryMapStack();\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Frees previous allocated pages.\r
+\r
+ @param[in] Memory Base address of memory being freed.\r
+ @param[in] NumberOfPages The number of pages to free.\r
+ @param[in] IsGuarded Is the memory to free guarded or not.\r
+\r
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
+ @return EFI_SUCCESS Pages successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInternalFreePages (\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NumberOfPages,\r
+ IN BOOLEAN IsGuarded\r
+ )\r
+{\r
+ if (IsGuarded) {\r
+ return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);\r
+ }\r
+ return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);\r
+}\r
+\r
+/**\r
+ Check whether the input range is in memory map.\r
+\r
+ @param Memory Base address of memory being inputed.\r
+ @param NumberOfPages The number of pages.\r
+\r
+ @retval TRUE In memory map.\r
+ @retval FALSE Not in memory map.\r
+\r
+**/\r
+BOOLEAN\r
+InMemMap (\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NumberOfPages\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ EFI_PHYSICAL_ADDRESS Last;\r
+\r
+ Last = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1;\r
+\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ Link = Link->ForwardLink;\r
+\r
+ if ((Entry->Start <= Memory) && (Entry->End >= Last)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
/**\r
Frees previous allocated pages.\r
\r
@param NumberOfPages The number of pages to free.\r
\r
@retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
- @retval EFI_INVALID_PARAMETER Address not aligned.\r
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
@return EFI_SUCCESS Pages successfully freed.\r
\r
**/\r
)\r
{\r
EFI_STATUS Status;\r
+ BOOLEAN IsGuarded;\r
+\r
+ if (!InMemMap(Memory, NumberOfPages)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
\r
- Status = SmmInternalFreePages (Memory, NumberOfPages);\r
+ IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);\r
+ Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);\r
if (!EFI_ERROR (Status)) {\r
SmmCoreUpdateProfile (\r
(EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
UINTN AlignedMemBase;\r
\r
//\r
- // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization\r
+ // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization\r
//\r
if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
- return;\r
+ Type = EfiRuntimeServicesData;\r
+ } else {\r
+ Type = EfiConventionalMemory;\r
}\r
- \r
+\r
+ DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));\r
+ DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));\r
+ DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));\r
+ DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));\r
+ DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));\r
+\r
//\r
// Align range on an EFI_PAGE_SIZE boundary\r
- // \r
+ //\r
AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;\r
MemLength -= AlignedMemBase - MemBase;\r
- SmmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength));\r
+ if (Type == EfiConventionalMemory) {\r
+ SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
+ } else {\r
+ ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
+ }\r
+\r
+ CoreFreeMemoryMapStack ();\r
+}\r
+\r
+/**\r
+ This function returns a copy of the current memory map. The map is an array of\r
+ memory descriptors, each of which describes a contiguous block of memory.\r
+\r
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
+ MemoryMap buffer. On input, this is the size of\r
+ the buffer allocated by the caller. On output,\r
+ it is the size of the buffer returned by the\r
+ firmware if the buffer was large enough, or the\r
+ size of the buffer needed to contain the map if\r
+ the buffer was too small.\r
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param[out] MapKey A pointer to the location in which firmware\r
+ returns the key for the current memory map.\r
+ @param[out] DescriptorSize A pointer to the location in which firmware\r
+ returns the size, in bytes, of an individual\r
+ EFI_MEMORY_DESCRIPTOR.\r
+ @param[out] DescriptorVersion A pointer to the location in which firmware\r
+ returns the version number associated with the\r
+ EFI_MEMORY_DESCRIPTOR.\r
+\r
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
+ buffer.\r
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
+ buffer size needed to hold the memory map is\r
+ returned in MemoryMapSize.\r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCoreGetMemoryMap (\r
+ IN OUT UINTN *MemoryMapSize,\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ OUT UINTN *MapKey,\r
+ OUT UINTN *DescriptorSize,\r
+ OUT UINT32 *DescriptorVersion\r
+ )\r
+{\r
+ UINTN Count;\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ UINTN Size;\r
+ UINTN BufferSize;\r
+\r
+ Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
+\r
+ //\r
+ // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
+ // prevent people from having pointer math bugs in their code.\r
+ // now you have to use *DescriptorSize to make things work.\r
+ //\r
+ Size += sizeof(UINT64) - (Size % sizeof (UINT64));\r
+\r
+ if (DescriptorSize != NULL) {\r
+ *DescriptorSize = Size;\r
+ }\r
+\r
+ if (DescriptorVersion != NULL) {\r
+ *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
+ }\r
+\r
+ Count = GetSmmMemoryMapEntryCount ();\r
+ BufferSize = Size * Count;\r
+ if (*MemoryMapSize < BufferSize) {\r
+ *MemoryMapSize = BufferSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *MemoryMapSize = BufferSize;\r
+ if (MemoryMap == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (MemoryMap, BufferSize);\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ Link = Link->ForwardLink;\r
+\r
+ MemoryMap->Type = Entry->Type;\r
+ MemoryMap->PhysicalStart = Entry->Start;\r
+ MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
+\r
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
}\r