]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Mem/Page.c
MdeModulePkg/DxeCore: Filter out all paging capabilities
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
index b09f2f1304e1d562e2bbe490b2726aec2820db00..962ae90d3dd68e48708761bff4610750a20ee9bd 100644 (file)
@@ -1,8 +1,8 @@
 /** @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 - 2017, 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
@@ -13,11 +13,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 **/\r
 \r
 #include "DxeMain.h"\r
-\r
-#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT  (EFI_PAGE_SIZE)\r
+#include "Imem.h"\r
+#include "HeapGuard.h"\r
 \r
 //\r
-// Entry for tracking the memory regions for each memory type to help cooalese like memory types\r
+// Entry for tracking the memory regions for each memory type to coalesce similar memory types\r
 //\r
 typedef struct {\r
   EFI_PHYSICAL_ADDRESS  BaseAddress;\r
@@ -27,47 +27,51 @@ typedef struct {
   UINTN                 InformationIndex;\r
   BOOLEAN               Special;\r
   BOOLEAN               Runtime;\r
-} EFI_MEMORY_TYPE_STAISTICS;\r
+} EFI_MEMORY_TYPE_STATISTICS;\r
 \r
 //\r
 // MemoryMap - The current memory map\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
+EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {\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 },  // EfiPersistentMemory\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
+EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ADDRESS;\r
 \r
 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {\r
   { EfiReservedMemoryType,      0 },\r
@@ -84,103 +88,15 @@ EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
   { EfiMemoryMappedIO,          0 },\r
   { EfiMemoryMappedIOPortSpace, 0 },\r
   { EfiPalCode,                 0 },\r
+  { EfiPersistentMemory,        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
@@ -209,222 +125,30 @@ CoreReleaseMemoryLock (
 }\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_ERROR | 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
@@ -454,7 +178,22 @@ CoreAddRange (
   ASSERT_LOCKED (&gMemoryLock);\r
 \r
   DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));\r
-\r
+  \r
+  //\r
+  // If memory of type EfiConventionalMemory is being added that includes the page \r
+  // starting at address 0, then zero the page starting at address 0.  This has \r
+  // two benifits.  It helps find NULL pointer bugs and it also maximizes \r
+  // compatibility with operating systems that may evaluate memory in this page \r
+  // for legacy data structures.  If memory of any other type is added starting \r
+  // at address 0, then do not zero the page at address 0 because the page is being \r
+  // used for other purposes.\r
+  //  \r
+  if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 1)) {\r
+    if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {\r
+      SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);\r
+    }\r
+  }\r
+  \r
   //\r
   // Memory map being altered so updated key\r
   //\r
@@ -466,7 +205,7 @@ CoreAddRange (
   // If we are in EFI 1.10 compatability mode no event groups will be\r
   // found and nothing will happen we we call this function. These events\r
   // will get signaled but since a lock is held around the call to this\r
-  // function the notificaiton events will only be called after this funciton\r
+  // function the notificaiton events will only be called after this function\r
   // returns and the lock is released.\r
   //\r
   CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);\r
@@ -523,6 +262,59 @@ CoreAddRange (
   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 (\r
+                              EfiBootServicesData,\r
+                              EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),\r
+                              DEFAULT_PAGE_ALLOCATION_GRANULARITY,\r
+                              FALSE\r
+                              );\r
+    if (FreeDescriptorEntries != NULL) {\r
+      //\r
+      // Enque the free memmory map entries into the list\r
+      //\r
+      for (Index = 0; Index < DEFAULT_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
@@ -561,126 +353,350 @@ CoreFreeMemoryMapStack (
     ASSERT (Entry);\r
 \r
     //\r
-    // Update to proper entry\r
+    // Update to proper entry\r
+    //\r
+    mMapDepth -= 1;\r
+\r
+    if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
+\r
+      //\r
+      // Move this entry to general memory\r
+      //\r
+      RemoveEntryList (&mMapStack[mMapDepth].Link);\r
+      mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
+\r
+      CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
+      Entry->FromPages = TRUE;\r
+\r
+      //\r
+      // Find insertion location\r
+      //\r
+      for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {\r
+        Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+        if (Entry2->FromPages && Entry2->Start > Entry->Start) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      InsertTailList (Link2, &Entry->Link);\r
+\r
+    } else {\r
+      //\r
+      // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,\r
+      // so here no need to move it to memory.\r
+      //\r
+      InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
+    }\r
+  }\r
+\r
+  mFreeMapStack -= 1;\r
+}\r
+\r
+/**\r
+  Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.\r
+\r
+**/\r
+BOOLEAN\r
+PromoteMemoryResource (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY         *Link;\r
+  EFI_GCD_MAP_ENTRY  *Entry;\r
+  BOOLEAN            Promoted;\r
+\r
+  DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));\r
+\r
+  CoreAcquireGcdMemoryLock ();\r
+\r
+  Promoted = FALSE;\r
+  Link = mGcdMemorySpaceMap.ForwardLink;\r
+  while (Link != &mGcdMemorySpaceMap) {\r
+\r
+    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
+      if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {\r
+        Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;\r
+      } else {\r
+        Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;\r
+      }\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
+      Promoted = TRUE;\r
+    }\r
+\r
+    Link = Link->ForwardLink;\r
+  }\r
+\r
+  CoreReleaseGcdMemoryLock ();\r
+\r
+  return Promoted;\r
+}\r
+/**\r
+  This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD \r
+  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
+  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 None.  The range is added to the memory map\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
+  )\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 < MEMORY_TYPE_OEM_RESERVED_MIN) {\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
+  ApplyMemoryProtectionPolicy (EfiMaxMemoryType, Type, Start,\r
+    LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT));\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
+    // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
     //\r
-    mMapDepth -= 1;\r
-\r
-    if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
-\r
+    Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
+    if ((UINT32)Type > EfiMaxMemoryType) {\r
+      continue;\r
+    }\r
+    if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
       //\r
-      // Move this entry to general memory\r
+      // Allocate pages for the current memory type from the top of available memory\r
       //\r
-      RemoveEntryList (&mMapStack[mMapDepth].Link);\r
-      mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
-\r
-      CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
-      Entry->FromPages = TRUE;\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 ((UINT32)Type > EfiMaxMemoryType) {\r
+            continue;\r
+          }\r
 \r
-      //\r
-      // Find insertion location\r
-      //\r
-      for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {\r
-        Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
-        if (Entry2->FromPages && Entry2->Start > Entry->Start) {\r
-          break;\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
-      InsertTailList (Link2, &Entry->Link);\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
-    } else {\r
       //\r
-      // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,\r
-      // so here no need to move it to memory.\r
+      // If the current base address is the lowest address so far, then update the default\r
+      // maximum address\r
       //\r
-      InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
+      if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {\r
+        mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;\r
+      }\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
-\r
-**/\r
-VOID\r
-RemoveMemoryMapEntry (\r
-  IN OUT MEMORY_MAP      *Entry\r
-  )\r
-{\r
-  RemoveEntryList (&Entry->Link);\r
-  Entry->Link.ForwardLink = NULL;\r
-\r
-  if (Entry->FromPages) {\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
     //\r
-    // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList\r
+    // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
     //\r
-    InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
+    Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
+    if ((UINT32)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
-\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
+  // 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
-    } else {\r
-      return NULL;\r
+    }\r
+    mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;\r
+    if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ADDRESS) {\r
+      mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;\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
+  mMemoryTypeInformationInitialized = TRUE;\r
 }\r
 \r
 \r
 /**\r
-  Internal function.  Converts a memory range to the specified type.\r
-  The range must exist in the memory map.\r
+  Internal function.  Converts a memory range to the specified type or attributes.\r
+  The range must exist in the memory map.  Either ChangingType or\r
+  ChangingAttributes must be set, but not both.\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  ChangingType           Boolean indicating that type value should be changed\r
   @param  NewType                The new type for the memory range\r
+  @param  ChangingAttributes     Boolean indicating that attributes value should be changed\r
+  @param  NewAttributes          The new attributes 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
@@ -690,10 +706,13 @@ AllocateMemoryMapEntry (
 \r
 **/\r
 EFI_STATUS\r
-CoreConvertPages (\r
+CoreConvertPagesEx (\r
   IN UINT64           Start,\r
   IN UINT64           NumberOfPages,\r
-  IN EFI_MEMORY_TYPE  NewType\r
+  IN BOOLEAN          ChangingType,\r
+  IN EFI_MEMORY_TYPE  NewType,\r
+  IN BOOLEAN          ChangingAttributes,\r
+  IN UINT64           NewAttributes\r
   )\r
 {\r
 \r
@@ -701,6 +720,7 @@ CoreConvertPages (
   UINT64          End;\r
   UINT64          RangeEnd;\r
   UINT64          Attribute;\r
+  EFI_MEMORY_TYPE MemType;\r
   LIST_ENTRY      *Link;\r
   MEMORY_MAP      *Entry;\r
 \r
@@ -712,8 +732,9 @@ CoreConvertPages (
   ASSERT ((Start & EFI_PAGE_MASK) == 0);\r
   ASSERT (End > Start) ;\r
   ASSERT_LOCKED (&gMemoryLock);\r
+  ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) );\r
 \r
-  if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start > (Start + NumberOfBytes))) {\r
+  if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -739,45 +760,70 @@ CoreConvertPages (
       return EFI_NOT_FOUND;\r
     }\r
 \r
+    //\r
+    // If we are converting the type of the range from EfiConventionalMemory to\r
+    // another type, we have to ensure that the entire range is covered by a\r
+    // single entry.\r
+    //\r
+    if (ChangingType && (NewType != EfiConventionalMemory)) {\r
+      if (Entry->End < End) {\r
+        DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));\r
+        return EFI_NOT_FOUND;\r
+      }\r
+    }\r
     //\r
     // Convert range to the end, or to the end of the descriptor\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
 \r
-    DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType));\r
-\r
-    //\r
-    // Debug code - verify conversion is allowed\r
-    //\r
-    if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {\r
-      DEBUG ((DEBUG_ERROR , "ConvertPages: Incompatible memory types\n"));\r
-      return EFI_NOT_FOUND;\r
+    if (ChangingType) {\r
+      DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));\r
+    }\r
+    if (ChangingAttributes) {\r
+      DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));\r
     }\r
 \r
-    //\r
-    // Update counters for the number of pages allocated to each memory type\r
-    //\r
-    if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {\r
-      if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress &&\r
-          Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) {\r
-        if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {\r
-          mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;\r
+    if (ChangingType) {\r
+      //\r
+      // Debug code - verify conversion is allowed\r
+      //\r
+      if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {\r
+        DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));\r
+        if (Entry->Type == EfiConventionalMemory) {\r
+          DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));\r
         } else {\r
-          mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;\r
+          DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));\r
         }\r
+        return EFI_NOT_FOUND;\r
       }\r
-    }\r
 \r
-    if (NewType >= 0 && NewType < EfiMaxMemoryType) {\r
-      if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) {\r
-        mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;\r
-        if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages >\r
-            gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {\r
-          gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;\r
+      //\r
+      // Update counters for the number of pages allocated to each memory type\r
+      //\r
+      if ((UINT32)Entry->Type < EfiMaxMemoryType) {\r
+        if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||\r
+            (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress)                                                          ) {\r
+          if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {\r
+            mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;\r
+          } else {\r
+            mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;\r
+          }\r
+        }\r
+      }\r
+\r
+      if ((UINT32)NewType < EfiMaxMemoryType) {\r
+        if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||\r
+            (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress)                                                  ) {\r
+          mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;\r
+          if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {\r
+            gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;\r
+          }\r
         }\r
       }\r
     }\r
@@ -831,52 +877,151 @@ CoreConvertPages (
 \r
     //\r
     // The new range inherits the same Attribute as the Entry\r
-    //it is being cut out of\r
+    // it is being cut out of unless attributes are being changed\r
     //\r
-    Attribute = Entry->Attribute;\r
+    if (ChangingType) {\r
+      Attribute = Entry->Attribute;\r
+      MemType = NewType;\r
+    } else {\r
+      Attribute = NewAttributes;\r
+      MemType = Entry->Type;\r
+    }\r
+\r
+    //\r
+    // If the descriptor is empty, then remove it from the map\r
+    //\r
+    if (Entry->Start == Entry->End + 1) {\r
+      RemoveMemoryMapEntry (Entry);\r
+      Entry = NULL;\r
+    }\r
+\r
+    //\r
+    // Add our new range in\r
+    //\r
+    CoreAddRange (MemType, Start, RangeEnd, Attribute);\r
+    if (ChangingType && (MemType == EfiConventionalMemory)) {\r
+      if (Start == 0) {\r
+        //\r
+        // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this\r
+        // macro will ASSERT() if address is 0.  Instead, CoreAddRange()\r
+        // guarantees that the page starting at address 0 is always filled\r
+        // with zeros.\r
+        //\r
+        if (RangeEnd > EFI_PAGE_SIZE) {\r
+          DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));\r
+        }\r
+      } else {\r
+        //\r
+        // If Heap Guard is enabled, the page at the top and/or bottom of\r
+        // this memory block to free might be inaccessible. Skipping them\r
+        // to avoid page fault exception.\r
+        //\r
+        UINT64  StartToClear;\r
+        UINT64  EndToClear;\r
+\r
+        StartToClear = Start;\r
+        EndToClear   = RangeEnd;\r
+        if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) {\r
+          if (IsGuardPage(StartToClear)) {\r
+            StartToClear += EFI_PAGE_SIZE;\r
+          }\r
+          if (IsGuardPage (EndToClear)) {\r
+            EndToClear -= EFI_PAGE_SIZE;\r
+          }\r
+          ASSERT (EndToClear > StartToClear);\r
+        }\r
+\r
+        DEBUG_CLEAR_MEMORY(\r
+          (VOID *)(UINTN)StartToClear,\r
+          (UINTN)(EndToClear - StartToClear + 1)\r
+          );\r
+      }\r
+    }\r
+\r
+    //\r
+    // Move any map descriptor stack to general pool\r
+    //\r
+    CoreFreeMemoryMapStack ();\r
+\r
+    //\r
+    // Bump the starting address, and convert the next range\r
+    //\r
+    Start = RangeEnd + 1;\r
+  }\r
+\r
+  //\r
+  // Converted the whole range, done\r
+  //\r
+\r
+  return EFI_SUCCESS;\r
+}\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
+  return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);\r
+}\r
 \r
-    //\r
-    // If the descriptor is empty, then remove it from the map\r
-    //\r
-    if (Entry->Start == Entry->End + 1) {\r
-      RemoveMemoryMapEntry (Entry);\r
-      Entry = NULL;\r
-    }\r
 \r
-    //\r
-    // Add our new range in\r
-    //\r
-    CoreAddRange (NewType, Start, RangeEnd, Attribute);\r
+/**\r
+  Internal function.  Converts a memory range to use new attributes.\r
 \r
-    //\r
-    // Move any map descriptor stack to general pool\r
-    //\r
-    CoreFreeMemoryMapStack ();\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  NewAttributes          The new attributes value for the range.\r
 \r
-    //\r
-    // Bump the starting address, and convert the next range\r
-    //\r
-    Start = RangeEnd + 1;\r
-  }\r
+**/\r
+VOID\r
+CoreUpdateMemoryAttributes (\r
+  IN EFI_PHYSICAL_ADDRESS  Start,\r
+  IN UINT64                NumberOfPages,\r
+  IN UINT64                NewAttributes\r
+  )\r
+{\r
+  CoreAcquireMemoryLock ();\r
 \r
   //\r
-  // Converted the whole range, done\r
+  // Update the attributes to the new value\r
   //\r
+  CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);\r
 \r
-  return EFI_SUCCESS;\r
+  CoreReleaseMemoryLock ();\r
 }\r
 \r
 \r
-\r
 /**\r
   Internal function. Finds a consecutive free page range below\r
   the requested address.\r
 \r
   @param  MaxAddress             The address that the range must be below\r
+  @param  MinAddress             The address that the range must be above\r
   @param  NumberOfPages          Number of pages needed\r
   @param  NewType                The type of memory the range is going to be\r
                                  turned into\r
   @param  Alignment              Bits to align with\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not\r
 \r
   @return The base address of the range, or 0 if the range was not found\r
 \r
@@ -884,9 +1029,11 @@ CoreConvertPages (
 UINT64\r
 CoreFindFreePagesI (\r
   IN UINT64           MaxAddress,\r
+  IN UINT64           MinAddress,\r
   IN UINT64           NumberOfPages,\r
   IN EFI_MEMORY_TYPE  NewType,\r
-  IN UINTN            Alignment\r
+  IN UINTN            Alignment,\r
+  IN BOOLEAN          NeedGuard\r
   )\r
 {\r
   UINT64          NumberOfBytes;\r
@@ -915,7 +1062,7 @@ CoreFindFreePagesI (
     //\r
     // Set MaxAddress to a page boundary\r
     //\r
-    MaxAddress &= ~EFI_PAGE_MASK;\r
+    MaxAddress &= ~(UINT64)EFI_PAGE_MASK;\r
 \r
     //\r
     // Set MaxAddress to end of the page\r
@@ -940,9 +1087,9 @@ CoreFindFreePagesI (
     DescEnd = Entry->End;\r
 \r
     //\r
-    // If desc is past max allowed address, skip it\r
+    // If desc is past max allowed address or below min allowed address, skip it\r
     //\r
-    if (DescStart >= MaxAddress) {\r
+    if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {\r
       continue;\r
     }\r
 \r
@@ -955,6 +1102,11 @@ CoreFindFreePagesI (
 \r
     DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;\r
 \r
+    // Skip if DescEnd is less than DescStart after alignment clipping\r
+    if (DescEnd < DescStart) {\r
+      continue;\r
+    }\r
+\r
     //\r
     // Compute the number of bytes we can used from this\r
     // descriptor, and see it's enough to satisfy the request\r
@@ -962,11 +1114,28 @@ CoreFindFreePagesI (
     DescNumberOfBytes = DescEnd - DescStart + 1;\r
 \r
     if (DescNumberOfBytes >= NumberOfBytes) {\r
+      //\r
+      // If the start of the allocated range is below the min address allowed, skip it\r
+      //\r
+      if ((DescEnd - NumberOfBytes + 1) < MinAddress) {\r
+        continue;\r
+      }\r
 \r
       //\r
       // If this is the best match so far remember it\r
       //\r
       if (DescEnd > Target) {\r
+        if (NeedGuard) {\r
+          DescEnd = AdjustMemoryS (\r
+                      DescEnd + 1 - DescNumberOfBytes,\r
+                      DescNumberOfBytes,\r
+                      NumberOfBytes\r
+                      );\r
+          if (DescEnd == 0) {\r
+            continue;\r
+          }\r
+        }\r
+\r
         Target = DescEnd;\r
       }\r
     }\r
@@ -997,6 +1166,7 @@ CoreFindFreePagesI (
   @param  NewType                The type of memory the range is going to be\r
                                  turned into\r
   @param  Alignment              Bits to align with\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not\r
 \r
   @return The base address of the range, or 0 if the range was not found.\r
 \r
@@ -1006,44 +1176,69 @@ FindFreePages (
     IN UINT64           MaxAddress,\r
     IN UINT64           NoPages,\r
     IN EFI_MEMORY_TYPE  NewType,\r
-    IN UINTN            Alignment\r
+    IN UINTN            Alignment,\r
+    IN BOOLEAN          NeedGuard\r
     )\r
 {\r
-  UINT64  NewMaxAddress;\r
-  UINT64  Start;\r
+  UINT64   Start;\r
 \r
-  NewMaxAddress = MaxAddress;\r
+  //\r
+  // Attempt to find free pages in the preferred bin based on the requested memory type\r
+  //\r
+  if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {\r
+    Start = CoreFindFreePagesI (\r
+              mMemoryTypeStatistics[NewType].MaximumAddress, \r
+              mMemoryTypeStatistics[NewType].BaseAddress, \r
+              NoPages, \r
+              NewType, \r
+              Alignment,\r
+              NeedGuard\r
+              );\r
+    if (Start != 0) {\r
+      return Start;\r
+    }\r
+  }\r
 \r
-  if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {\r
-    NewMaxAddress  = mMemoryTypeStatistics[NewType].MaximumAddress;\r
-  } else {\r
-    if (NewMaxAddress > mDefaultMaximumAddress) {\r
-      NewMaxAddress  = mDefaultMaximumAddress;\r
+  //\r
+  // Attempt to find free pages in the default allocation bin\r
+  //\r
+  if (MaxAddress >= mDefaultMaximumAddress) {\r
+    Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType,\r
+                                Alignment, NeedGuard);\r
+    if (Start != 0) {\r
+      if (Start < mDefaultBaseAddress) {\r
+        mDefaultBaseAddress = Start;\r
+      }\r
+      return Start;\r
     }\r
   }\r
 \r
-  Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);\r
-  if (Start == 0) {\r
-    Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);\r
-    if (Start == 0) {\r
-      //\r
-      // Here means there may be no enough memory to use, so try to go through\r
-      // all the memory descript to promote the untested memory directly\r
-      //\r
-      PromoteMemoryResource ();\r
+  //\r
+  // The allocation did not succeed in any of the prefered bins even after \r
+  // promoting resources. Attempt to find free pages anywhere is the requested \r
+  // address range.  If this allocation fails, then there are not enough \r
+  // resources anywhere to satisfy the request.\r
+  //\r
+  Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment,\r
+                              NeedGuard);\r
+  if (Start != 0) {\r
+    return Start;\r
+  }\r
 \r
-      //\r
-      // Allocate memory again after the memory resource re-arranged\r
-      //\r
-      Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);\r
-    }\r
+  //\r
+  // If allocations from the preferred bins fail, then attempt to promote memory resources.\r
+  //\r
+  if (!PromoteMemoryResource ()) {\r
+    return 0;\r
   }\r
 \r
-  return Start;\r
+  //\r
+  // If any memory resources were promoted, then re-attempt the allocation\r
+  //\r
+  return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);\r
 }\r
 \r
 \r
-\r
 /**\r
   Allocates pages from the memory map.\r
 \r
@@ -1053,6 +1248,7 @@ FindFreePages (
   @param  NumberOfPages          The number of pages to allocate\r
   @param  Memory                 A pointer to receive the base allocated memory\r
                                  address\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not\r
 \r
   @return Status. On success, Memory is filled in with the base address allocated\r
   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in\r
@@ -1064,35 +1260,42 @@ FindFreePages (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-CoreAllocatePages (\r
+CoreInternalAllocatePages (\r
   IN EFI_ALLOCATE_TYPE      Type,\r
   IN EFI_MEMORY_TYPE        MemoryType,\r
   IN UINTN                  NumberOfPages,\r
-  IN OUT EFI_PHYSICAL_ADDRESS  *Memory\r
+  IN OUT EFI_PHYSICAL_ADDRESS  *Memory,\r
+  IN BOOLEAN                NeedGuard\r
   )\r
 {\r
   EFI_STATUS      Status;\r
   UINT64          Start;\r
+  UINT64          NumberOfBytes;\r
+  UINT64          End;\r
   UINT64          MaxAddress;\r
   UINTN           Alignment;\r
 \r
-  if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) {\r
+  if ((UINT32)Type >= MaxAllocateType) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||\r
+       (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) ||\r
-       MemoryType == EfiConventionalMemory) {\r
+  if (Memory == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;\r
+  Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
 \r
   if  (MemoryType == EfiACPIReclaimMemory   ||\r
        MemoryType == EfiACPIMemoryNVS       ||\r
        MemoryType == EfiRuntimeServicesCode ||\r
        MemoryType == EfiRuntimeServicesData) {\r
 \r
-    Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
+    Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
   }\r
 \r
   if (Type == AllocateAddress) {\r
@@ -1112,7 +1315,31 @@ CoreAllocatePages (
   //\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
+  //\r
+  // Check for Type AllocateAddress,\r
+  // if NumberOfPages is 0 or\r
+  // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ADDRESS or\r
+  // if (Start + NumberOfBytes) rolls over 0 or\r
+  // if Start is above MAX_ADDRESS or\r
+  // if End is above MAX_ADDRESS,\r
+  // return EFI_NOT_FOUND.\r
+  //\r
+  if (Type == AllocateAddress) {\r
+    if ((NumberOfPages == 0) ||\r
+        (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+    NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);\r
+    End = Start + NumberOfBytes - 1;\r
+\r
+    if ((Start >= End) ||\r
+        (Start > MaxAddress) || \r
+        (End > MaxAddress)) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
 \r
   if (Type == AllocateMaxAddress) {\r
     MaxAddress = Start;\r
@@ -1124,7 +1351,8 @@ CoreAllocatePages (
   // If not a specific address, then find an address to allocate\r
   //\r
   if (Type != AllocateAddress) {\r
-    Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);\r
+    Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,\r
+                           NeedGuard);\r
     if (Start == 0) {\r
       Status = EFI_OUT_OF_RESOURCES;\r
       goto Done;\r
@@ -1134,24 +1362,80 @@ CoreAllocatePages (
   //\r
   // Convert pages from FreeMemory to the requested type\r
   //\r
-  Status = CoreConvertPages (Start, NumberOfPages, MemoryType);\r
+  if (NeedGuard) {\r
+    Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);\r
+  } else {\r
+    Status = CoreConvertPages(Start, NumberOfPages, MemoryType);\r
+  }\r
 \r
 Done:\r
   CoreReleaseMemoryLock ();\r
 \r
   if (!EFI_ERROR (Status)) {\r
+    if (NeedGuard) {\r
+      SetGuardForMemory (Start, NumberOfPages);\r
+    }\r
     *Memory = Start;\r
   }\r
 \r
   return Status;\r
 }\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
+\r
+  @return Status. On success, Memory is filled in with the base address allocated\r
+  @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in\r
+                                 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
+CoreAllocatePages (\r
+  IN  EFI_ALLOCATE_TYPE     Type,\r
+  IN  EFI_MEMORY_TYPE       MemoryType,\r
+  IN  UINTN                 NumberOfPages,\r
+  OUT EFI_PHYSICAL_ADDRESS  *Memory\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  BOOLEAN     NeedGuard;\r
+\r
+  NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;\r
+  Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,\r
+                                      NeedGuard);\r
+  if (!EFI_ERROR (Status)) {\r
+    CoreUpdateProfile (\r
+      (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
+      MemoryProfileActionAllocatePages,\r
+      MemoryType,\r
+      EFI_PAGES_TO_SIZE (NumberOfPages),\r
+      (VOID *) (UINTN) *Memory,\r
+      NULL\r
+      );\r
+    InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);\r
+    ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,\r
+      EFI_PAGES_TO_SIZE (NumberOfPages));\r
+  }\r
+  return Status;\r
+}\r
 \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  MemoryType             Pointer to memory type\r
 \r
   @retval EFI_NOT_FOUND          Could not find the entry that covers the range\r
   @retval EFI_INVALID_PARAMETER  Address not aligned\r
@@ -1160,15 +1444,17 @@ Done:
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-CoreFreePages (\r
+CoreInternalFreePages (\r
   IN EFI_PHYSICAL_ADDRESS   Memory,\r
-  IN UINTN                  NumberOfPages\r
+  IN UINTN                  NumberOfPages,\r
+  OUT EFI_MEMORY_TYPE       *MemoryType OPTIONAL\r
   )\r
 {\r
   EFI_STATUS      Status;\r
   LIST_ENTRY      *Link;\r
   MEMORY_MAP      *Entry;\r
   UINTN           Alignment;\r
+  BOOLEAN         IsGuarded;\r
 \r
   //\r
   // Free the range\r
@@ -1178,6 +1464,7 @@ CoreFreePages (
   //\r
   // Find the entry that the covers the range\r
   //\r
+  IsGuarded = FALSE;\r
   Entry = NULL;\r
   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
     Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
@@ -1186,48 +1473,170 @@ CoreFreePages (
     }\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
+  Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
 \r
+  ASSERT (Entry != NULL);\r
   if  (Entry->Type == EfiACPIReclaimMemory   ||\r
        Entry->Type == EfiACPIMemoryNVS       ||\r
        Entry->Type == EfiRuntimeServicesCode ||\r
        Entry->Type == EfiRuntimeServicesData) {\r
 \r
-    Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
+    Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
 \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
   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);\r
 \r
-  Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
+  if (MemoryType != NULL) {\r
+    *MemoryType = Entry->Type;\r
+  }\r
+\r
+  IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&\r
+              IsMemoryGuarded (Memory);\r
+  if (IsGuarded) {\r
+    Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,\r
+                                        EfiConventionalMemory);\r
+  } else {\r
+    Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
+  }\r
 \r
+Done:\r
   CoreReleaseMemoryLock ();\r
+  if (IsGuarded) {\r
+    UnsetGuardForMemory(Memory, NumberOfPages);\r
+  }\r
+  return Status;\r
+}\r
+\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
+\r
+  @retval EFI_NOT_FOUND          Could not find the entry that covers the range\r
+  @retval EFI_INVALID_PARAMETER  Address not aligned\r
+  @return EFI_SUCCESS         -Pages successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreFreePages (\r
+  IN EFI_PHYSICAL_ADDRESS  Memory,\r
+  IN UINTN                 NumberOfPages\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  EFI_MEMORY_TYPE   MemoryType;\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);\r
+  if (!EFI_ERROR (Status)) {\r
+    CoreUpdateProfile (\r
+      (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
+      MemoryProfileActionFreePages,\r
+      MemoryType,\r
+      EFI_PAGES_TO_SIZE (NumberOfPages),\r
+      (VOID *) (UINTN) Memory,\r
+      NULL\r
+      );\r
+    InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);\r
+    ApplyMemoryProtectionPolicy (MemoryType, EfiConventionalMemory, Memory,\r
+      EFI_PAGES_TO_SIZE (NumberOfPages));\r
   }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function checks to see if the last memory map descriptor in a memory map\r
+  can be merged with any of the other memory map descriptors in a memorymap.\r
+  Memory descriptors may be merged if they are adjacent and have the same type\r
+  and attributes.\r
+\r
+  @param  MemoryMap              A pointer to the start of the memory map.\r
+  @param  MemoryMapDescriptor    A pointer to the last descriptor in MemoryMap.\r
+  @param  DescriptorSize         The size, in bytes, of an individual\r
+                                 EFI_MEMORY_DESCRIPTOR.\r
 \r
+  @return  A pointer to the next available descriptor in MemoryMap\r
+\r
+**/\r
+EFI_MEMORY_DESCRIPTOR *\r
+MergeMemoryMapDescriptor (\r
+  IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN EFI_MEMORY_DESCRIPTOR  *MemoryMapDescriptor,\r
+  IN UINTN                  DescriptorSize\r
+  )\r
+{\r
   //\r
-  // Destroy the contents\r
+  // Traverse the array of descriptors in MemoryMap\r
   //\r
-  if (Memory < EFI_MAX_ADDRESS) {\r
-    DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);\r
+  for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {\r
+    //\r
+    // Check to see if the Type fields are identical.\r
+    //\r
+    if (MemoryMap->Type != MemoryMapDescriptor->Type) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Check to see if the Attribute fields are identical.\r
+    //\r
+    if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Check to see if MemoryMapDescriptor is immediately above MemoryMap\r
+    //\r
+    if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) { \r
+      //\r
+      // Merge MemoryMapDescriptor into MemoryMap\r
+      //\r
+      MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;\r
+\r
+      //\r
+      // Return MemoryMapDescriptor as the next available slot int he MemoryMap array\r
+      //\r
+      return MemoryMapDescriptor;\r
+    }\r
+\r
+    //\r
+    // Check to see if MemoryMapDescriptor is immediately below MemoryMap\r
+    //\r
+    if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {\r
+      //\r
+      // Merge MemoryMapDescriptor into MemoryMap\r
+      //\r
+      MemoryMap->PhysicalStart  = MemoryMapDescriptor->PhysicalStart;\r
+      MemoryMap->VirtualStart   = MemoryMapDescriptor->VirtualStart;\r
+      MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;\r
+\r
+      //\r
+      // Return MemoryMapDescriptor as the next available slot int he MemoryMap array\r
+      //\r
+      return MemoryMapDescriptor;\r
+    }\r
   }\r
 \r
-  return Status;\r
+  //\r
+  // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.\r
+  //\r
+  // Return the slot immediately after MemoryMapDescriptor as the next available \r
+  // slot in the MemoryMap array\r
+  //\r
+  return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);\r
 }\r
 \r
-\r
 /**\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
@@ -1271,11 +1680,14 @@ CoreGetMemoryMap (
   EFI_STATUS                        Status;\r
   UINTN                             Size;\r
   UINTN                             BufferSize;\r
-  UINTN                             NumberOfRuntimeEntries;\r
+  UINTN                             NumberOfEntries;\r
   LIST_ENTRY                        *Link;\r
   MEMORY_MAP                        *Entry;\r
   EFI_GCD_MAP_ENTRY                 *GcdMapEntry;\r
+  EFI_GCD_MAP_ENTRY                 MergeGcdMapEntry;\r
   EFI_MEMORY_TYPE                   Type;\r
+  EFI_MEMORY_DESCRIPTOR             *MemoryMapStart;\r
+  EFI_MEMORY_DESCRIPTOR             *MemoryMapEnd;\r
 \r
   //\r
   // Make sure the parameters are valid\r
@@ -1287,16 +1699,17 @@ CoreGetMemoryMap (
   CoreAcquireGcdMemoryLock ();\r
 \r
   //\r
-  // Count the number of Reserved and MMIO entries that are marked for runtime use\r
+  // Count the number of Reserved and runtime MMIO entries\r
+  // And, count the number of Persistent entries.\r
   //\r
-  NumberOfRuntimeEntries = 0;\r
+  NumberOfEntries = 0;\r
   for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
     GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
-    if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
-        (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {\r
-      if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {\r
-        NumberOfRuntimeEntries++;\r
-      }\r
+    if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) || \r
+        (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
+        ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
+        ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {\r
+      NumberOfEntries ++;\r
     }\r
   }\r
 \r
@@ -1322,7 +1735,7 @@ CoreGetMemoryMap (
   //\r
   // Compute the buffer size needed to fit the entire map\r
   //\r
-  BufferSize = Size * NumberOfRuntimeEntries;\r
+  BufferSize = Size * NumberOfEntries;\r
   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
     BufferSize += Size;\r
   }\r
@@ -1341,6 +1754,7 @@ CoreGetMemoryMap (
   // Build the map\r
   //\r
   ZeroMem (MemoryMap, BufferSize);\r
+  MemoryMapStart = MemoryMap;\r
   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
     ASSERT (Entry->VirtualStart == 0);\r
@@ -1370,47 +1784,141 @@ CoreGetMemoryMap (
       }\r
     }\r
     MemoryMap->Attribute = Entry->Attribute;\r
-    if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {\r
-      MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;\r
+    if (MemoryMap->Type < EfiMaxMemoryType) {\r
+      if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {\r
+        MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;\r
+      }\r
     }\r
 \r
-    MemoryMap = NextMemoryDescriptor (MemoryMap, Size);\r
+    //\r
+    // Check to see if the new Memory Map Descriptor can be merged with an \r
+    // existing descriptor if they are adjacent and have the same attributes\r
+    //\r
+    MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
   }\r
 \r
-  for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
-    GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
-    if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
-        (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {\r
-      if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {\r
-\r
-        MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;\r
-        MemoryMap->VirtualStart  = 0;\r
-        MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);\r
-        MemoryMap->Attribute     = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;\r
-\r
-        if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {\r
-          MemoryMap->Type = EfiReservedMemoryType;\r
-        } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
-          if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {\r
-            MemoryMap->Type = EfiMemoryMappedIOPortSpace;\r
-          } else {\r
-            MemoryMap->Type = EfiMemoryMappedIO;\r
-          }\r
-        }\r
\r
+  ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));\r
+  GcdMapEntry = NULL;\r
+  for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {\r
+    if (Link != &mGcdMemorySpaceMap) {\r
+      //\r
+      // Merge adjacent same type and attribute GCD memory range\r
+      //\r
+      GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
+  \r
+      if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) && \r
+          (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&\r
+          (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&\r
+          (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {\r
+        MergeGcdMapEntry.EndAddress  = GcdMapEntry->EndAddress;\r
+        continue;\r
+      }\r
+    }\r
 \r
-        MemoryMap = NextMemoryDescriptor (MemoryMap, Size);\r
+    if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
+        ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
+        ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {\r
+      //\r
+      // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR, \r
+      // it will be recorded as page PhysicalStart and NumberOfPages. \r
+      //\r
+      ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);\r
+      ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);\r
+      \r
+      // \r
+      // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries\r
+      //\r
+      MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;\r
+      MemoryMap->VirtualStart  = 0;\r
+      MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);\r
+      MemoryMap->Attribute     = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) | \r
+                                (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |\r
+                                EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));\r
+\r
+      if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {\r
+        MemoryMap->Type = EfiReservedMemoryType;\r
+      } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
+        if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {\r
+          MemoryMap->Type = EfiMemoryMappedIOPortSpace;\r
+        } else {\r
+          MemoryMap->Type = EfiMemoryMappedIO;\r
+        }\r
       }\r
+\r
+      //\r
+      // Check to see if the new Memory Map Descriptor can be merged with an \r
+      // existing descriptor if they are adjacent and have the same attributes\r
+      //\r
+      MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
     }\r
-  }\r
+    \r
+    if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {\r
+      //\r
+      // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR, \r
+      // it will be recorded as page PhysicalStart and NumberOfPages. \r
+      //\r
+      ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);\r
+      ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);\r
 \r
-  Status = EFI_SUCCESS;\r
+      // \r
+      // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries\r
+      //\r
+      MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;\r
+      MemoryMap->VirtualStart  = 0;\r
+      MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);\r
+      MemoryMap->Attribute     = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV | \r
+                                (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |\r
+                                EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));\r
+      MemoryMap->Type          = EfiPersistentMemory;\r
+      \r
+      //\r
+      // Check to see if the new Memory Map Descriptor can be merged with an \r
+      // existing descriptor if they are adjacent and have the same attributes\r
+      //\r
+      MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
+    }\r
+    if (Link == &mGcdMemorySpaceMap) {\r
+      //\r
+      // break loop when arrive at head.\r
+      //\r
+      break;\r
+    }\r
+    if (GcdMapEntry != NULL) {\r
+      //\r
+      // Copy new GCD map entry for the following GCD range merge\r
+      //\r
+      CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));\r
+    }\r
+  }\r
 \r
-Done:\r
+  //\r
+  // Compute the size of the buffer actually used after all memory map descriptor merge operations\r
+  //\r
+  BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);\r
 \r
-  CoreReleaseMemoryLock ();\r
+  //\r
+  // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really\r
+  //       set attributes and change memory paging attribute accordingly.\r
+  //       But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by\r
+  //       value from Capabilities in GCD memory map. This might cause\r
+  //       boot problems. Clearing all paging related capabilities can\r
+  //       workaround it. Following code is supposed to be removed once\r
+  //       the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in\r
+  //       UEFI spec and adopted by both EDK-II Core and all supported\r
+  //       OSs.\r
+  //\r
+  MemoryMapEnd = MemoryMap;\r
+  MemoryMap = MemoryMapStart;\r
+  while (MemoryMap < MemoryMapEnd) {\r
+    MemoryMap->Attribute &= ~(UINT64)(EFI_MEMORY_RP | EFI_MEMORY_RO |\r
+                                      EFI_MEMORY_XP);\r
+    MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
+  }\r
 \r
-  CoreReleaseGcdMemoryLock ();\r
+  Status = EFI_SUCCESS;\r
 \r
+Done:\r
   //\r
   // Update the map key finally\r
   //\r
@@ -1418,8 +1926,18 @@ Done:
     *MapKey = mMemoryMapKey;\r
   }\r
 \r
+  CoreReleaseMemoryLock ();\r
+\r
+  CoreReleaseGcdMemoryLock ();\r
+\r
   *MemoryMapSize = BufferSize;\r
 \r
+  DEBUG_CODE (\r
+    if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) {\r
+      DumpGuardedMemoryBitmap ();\r
+    }\r
+  );\r
+\r
   return Status;\r
 }\r
 \r
@@ -1431,6 +1949,7 @@ Done:
   @param  PoolType               The type of memory for the new pool pages\r
   @param  NumberOfPages          No of pages to allocate\r
   @param  Alignment              Bits to align.\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not\r
 \r
   @return The allocated memory, or NULL\r
 \r
@@ -1439,7 +1958,8 @@ VOID *
 CoreAllocatePoolPages (\r
   IN EFI_MEMORY_TYPE    PoolType,\r
   IN UINTN              NumberOfPages,\r
-  IN UINTN              Alignment\r
+  IN UINTN              Alignment,\r
+  IN BOOLEAN            NeedGuard\r
   )\r
 {\r
   UINT64            Start;\r
@@ -1447,15 +1967,20 @@ CoreAllocatePoolPages (
   //\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
+                         NeedGuard);\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
+    if (NeedGuard) {\r
+      CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);\r
+    } else {\r
+      CoreConvertPages (Start, NumberOfPages, PoolType);\r
+    }\r
   }\r
 \r
   return (VOID *)(UINTN) Start;\r
@@ -1514,21 +2039,20 @@ CoreTerminateMemoryMap (
 \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->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {\r
-          DEBUG((DEBUG_ERROR, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));\r
-          CoreReleaseMemoryLock ();\r
-          return EFI_INVALID_PARAMETER;\r
-        }\r
-        if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
-          DEBUG((DEBUG_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
-          CoreReleaseMemoryLock ();\r
-          return EFI_INVALID_PARAMETER;\r
-        }\r
-        if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
-          DEBUG((DEBUG_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
-          CoreReleaseMemoryLock ();\r
-          return EFI_INVALID_PARAMETER;\r
+      if (Entry->Type < EfiMaxMemoryType) {\r
+        if (mMemoryTypeStatistics[Entry->Type].Runtime) {\r
+          ASSERT (Entry->Type != EfiACPIReclaimMemory);\r
+          ASSERT (Entry->Type != EfiACPIMemoryNVS);\r
+          if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 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) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 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
         }\r
       }\r
     }\r
@@ -1544,6 +2068,7 @@ CoreTerminateMemoryMap (
     Status = EFI_INVALID_PARAMETER;\r
   }\r
 \r
+Done:\r
   CoreReleaseMemoryLock ();\r
 \r
   return Status;\r