]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/PiSmmCore/Page.c
MdeModulePkg PiSmmCore: Set ForwardLink to NULL in RemoveOldEntry()
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Page.c
index 5c04e8c8bf4d46e07d51a81041da86b5504d1a7b..3699af7424584c33afd383b82c72c56610a7c5ab 100644 (file)
 /** @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
+  Copyright (c) 2009 - 2018, 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
+  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
 \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
+  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
+\r
 /**\r
   Internal Function. Allocate n pages from given free page node.\r
 \r
@@ -131,12 +687,15 @@ InternalAllocAddress (
 /**\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
@@ -145,12 +704,13 @@ InternalAllocAddress (
 \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
@@ -172,6 +732,21 @@ SmmInternalAllocatePages (
     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
@@ -179,7 +754,7 @@ SmmInternalAllocatePages (
                   );\r
       if (*Memory == (UINTN)-1) {\r
         return EFI_OUT_OF_RESOURCES;\r
-      } \r
+      }\r
       break;\r
     case AllocateAddress:\r
       *Memory = InternalAllocAddress (\r
@@ -194,9 +769,50 @@ SmmInternalAllocatePages (
     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
@@ -223,8 +839,11 @@ SmmAllocatePages (
   )\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
@@ -268,25 +887,26 @@ InternalMergeNodes (
 /**\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
@@ -326,9 +946,43 @@ SmmInternalFreePages (
     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
   Frees previous allocated pages.\r
 \r
@@ -336,7 +990,7 @@ SmmInternalFreePages (
   @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
@@ -348,8 +1002,10 @@ SmmFreePages (
   )\r
 {\r
   EFI_STATUS  Status;\r
+  BOOLEAN     IsGuarded;\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
@@ -383,16 +1039,121 @@ SmmAddMemoryRegion (
   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