+ 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
+ Dump Smm memory map entry.\r
+**/\r
+VOID\r
+DumpSmmMemoryMapEntry (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ EFI_PHYSICAL_ADDRESS Last;\r
+\r
+ Last = 0;\r
+ DEBUG ((DEBUG_INFO, "DumpSmmMemoryMapEntry:\n"));\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 ((Last != 0) && (Last != (UINT64)-1)) {\r
+ if (Last + 1 != Entry->Start) {\r
+ Last = (UINT64)-1;\r
+ } else {\r
+ Last = Entry->End;\r
+ }\r
+ } else if (Last == 0) {\r
+ Last = Entry->End;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "Entry (Link - 0x%x)\n", &Entry->Link));\r
+ DEBUG ((DEBUG_INFO, " Signature - 0x%x\n", Entry->Signature));\r
+ DEBUG ((DEBUG_INFO, " Link.ForwardLink - 0x%x\n", Entry->Link.ForwardLink));\r
+ DEBUG ((DEBUG_INFO, " Link.BackLink - 0x%x\n", Entry->Link.BackLink));\r
+ DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Entry->Type));\r
+ DEBUG ((DEBUG_INFO, " Start - 0x%016lx\n", Entry->Start));\r
+ DEBUG ((DEBUG_INFO, " End - 0x%016lx\n", Entry->End));\r
+ }\r
+\r
+ ASSERT (Last != (UINT64)-1);\r
+}\r
+\r
+/**\r
+ Dump Smm memory map.\r
+**/\r
+VOID\r
+DumpSmmMemoryMap (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+\r
+ DEBUG ((DEBUG_INFO, "DumpSmmMemoryMap\n"));\r
+\r
+ Pages = NULL;\r
+ Node = mSmmMemoryMap.ForwardLink;\r
+ while (Node != &mSmmMemoryMap) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ DEBUG ((DEBUG_INFO, "Pages - 0x%x\n", Pages));\r
+ DEBUG ((DEBUG_INFO, "Pages->NumberOfPages - 0x%x\n", Pages->NumberOfPages));\r
+ Node = Node->ForwardLink;\r
+ }\r
+}\r
+\r
+/**\r
+ Check if a Smm base~length is in Smm memory map.\r
+\r
+ @param[in] Base The base address of Smm memory to be checked.\r
+ @param[in] Length THe length of Smm memory to be checked.\r
+\r
+ @retval TRUE Smm base~length is in smm memory map.\r
+ @retval FALSE Smm base~length is in smm memory map.\r
+**/\r
+BOOLEAN\r
+SmmMemoryMapConsistencyCheckRange (\r
+ IN EFI_PHYSICAL_ADDRESS Base,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ BOOLEAN Result;\r
+\r
+ Result = FALSE;\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->Type != EfiConventionalMemory) {\r
+ continue;\r
+ }\r
+ if (Entry->Start == Base && Entry->End == Base + Length - 1) {\r
+ Result = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Result;\r
+}\r
+\r
+/**\r
+ Check the consistency of Smm memory map.\r
+**/\r
+VOID\r
+SmmMemoryMapConsistencyCheck (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+ BOOLEAN Result;\r
+\r
+ Pages = NULL;\r
+ Node = mSmmMemoryMap.ForwardLink;\r
+ while (Node != &mSmmMemoryMap) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ Result = SmmMemoryMapConsistencyCheckRange ((EFI_PHYSICAL_ADDRESS)(UINTN)Pages, (UINTN)EFI_PAGES_TO_SIZE(Pages->NumberOfPages));\r
+ ASSERT (Result);\r
+ Node = Node->ForwardLink;\r
+ }\r
+}\r