]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Mem/Page.c
MdeModulePkg: fix mixed dos and linux EOL format issue
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
index b0cf1ece1e6545c50fcda28b67baead29c4164c7..fa84e2612526ed0e15f73557f82b002cbb3b2839 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 - 2014, 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
@@ -28,7 +28,7 @@ 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
@@ -52,7 +52,7 @@ UINTN         mFreeMapStack = 0;
 LIST_ENTRY   mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
 BOOLEAN      mMemoryTypeInformationInitialized = FALSE;\r
 \r
-EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {\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
@@ -71,6 +71,7 @@ EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
 };\r
 \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
@@ -176,7 +177,20 @@ 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
+    SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);\r
+  }\r
+  \r
   //\r
   // Memory map being altered so updated key\r
   //\r
@@ -374,18 +388,20 @@ CoreFreeMemoryMapStack (
   Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.\r
 \r
 **/\r
-VOID\r
+BOOLEAN\r
 PromoteMemoryResource (\r
   VOID\r
   )\r
 {\r
-  LIST_ENTRY                       *Link;\r
-  EFI_GCD_MAP_ENTRY                *Entry;\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
@@ -415,6 +431,7 @@ PromoteMemoryResource (
         );\r
       CoreFreeMemoryMapStack ();\r
 \r
+      Promoted = TRUE;\r
     }\r
 \r
     Link = Link->ForwardLink;\r
@@ -422,7 +439,7 @@ PromoteMemoryResource (
 \r
   CoreReleaseGcdMemoryLock ();\r
 \r
-  return;\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
@@ -553,7 +570,7 @@ CoreAddMemoryDescriptor (
     // 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
+    if ((UINT32)Type > EfiMaxMemoryType) {\r
       continue;\r
     }\r
     if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
@@ -577,7 +594,7 @@ CoreAddMemoryDescriptor (
           // 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
+          if ((UINT32)Type > EfiMaxMemoryType) {\r
             continue;\r
           }\r
 \r
@@ -620,7 +637,7 @@ CoreAddMemoryDescriptor (
     // 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
+    if ((UINT32)Type > EfiMaxMemoryType) {\r
       continue;\r
     }\r
     if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
@@ -654,13 +671,17 @@ CoreAddMemoryDescriptor (
 \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
@@ -670,10 +691,13 @@ CoreAddMemoryDescriptor (
 \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
@@ -681,6 +705,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
@@ -692,6 +717,7 @@ 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
     return EFI_INVALID_PARAMETER;\r
@@ -730,36 +756,43 @@ CoreConvertPages (
       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 | DEBUG_PAGE, "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
-        } else {\r
-          mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;\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\n"));\r
+        return EFI_NOT_FOUND;\r
+      }\r
+\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
 \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
+      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
@@ -813,9 +846,15 @@ 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
@@ -828,7 +867,21 @@ CoreConvertPages (
     //\r
     // Add our new range in\r
     //\r
-    CoreAddRange (NewType, Start, RangeEnd, Attribute);\r
+    CoreAddRange (MemType, Start, RangeEnd, Attribute);\r
+    if (ChangingType && (MemType == EfiConventionalMemory)) {\r
+      //\r
+      // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this\r
+      // macro will ASSERT() if address is 0.  Instead, CoreAddRange() guarantees\r
+      // that the page starting at address 0 is always filled with zeros.\r
+      //\r
+      if (Start == 0) {\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
+        DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));\r
+      }\r
+    }\r
 \r
     //\r
     // Move any map descriptor stack to general pool\r
@@ -849,12 +902,66 @@ CoreConvertPages (
 }\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
+/**\r
+  Internal function.  Converts a memory range to use new attributes.\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  NewAttributes          The new attributes value for the range.\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
+  // Update the attributes to the new value\r
+  //\r
+  CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);\r
+\r
+  CoreReleaseMemoryLock ();\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
@@ -866,6 +973,7 @@ 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
@@ -897,7 +1005,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
@@ -922,9 +1030,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
@@ -944,6 +1052,12 @@ 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
@@ -991,41 +1105,62 @@ FindFreePages (
     IN UINTN            Alignment\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
+              );\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, Alignment);\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
+  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);\r
 }\r
 \r
 \r
-\r
 /**\r
   Allocates pages from the memory map.\r
 \r
@@ -1046,7 +1181,7 @@ 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
@@ -1058,7 +1193,7 @@ CoreAllocatePages (
   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
@@ -1067,6 +1202,10 @@ CoreAllocatePages (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if (Memory == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;\r
 \r
   if  (MemoryType == EfiACPIReclaimMemory   ||\r
@@ -1128,6 +1267,41 @@ Done:
   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
+\r
+  Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);\r
+  if (!EFI_ERROR (Status)) {\r
+    CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages, MemoryType, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) *Memory);\r
+  }\r
+  return Status;\r
+}\r
 \r
 /**\r
   Frees previous allocated pages.\r
@@ -1142,7 +1316,7 @@ Done:
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-CoreFreePages (\r
+CoreInternalFreePages (\r
   IN EFI_PHYSICAL_ADDRESS   Memory,\r
   IN UINTN                  NumberOfPages\r
   )\r
@@ -1198,18 +1372,118 @@ CoreFreePages (
     goto Done;\r
   }\r
 \r
-  //\r
-  // Destroy the contents\r
-  //\r
-  if (Memory < MAX_ADDRESS) {\r
-    DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);\r
-  }\r
-\r
 Done:\r
   CoreReleaseMemoryLock ();\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
+\r
+  Status = CoreInternalFreePages (Memory, NumberOfPages);\r
+  if (!EFI_ERROR (Status)) {\r
+    CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePages, (EFI_MEMORY_TYPE) 0, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) Memory);\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
+  // Traverse the array of descriptors in MemoryMap\r
+  //\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
+  //\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
   This function returns a copy of the current memory map. The map is an array of\r
@@ -1259,6 +1533,7 @@ CoreGetMemoryMap (
   MEMORY_MAP                        *Entry;\r
   EFI_GCD_MAP_ENTRY                 *GcdMapEntry;\r
   EFI_MEMORY_TYPE                   Type;\r
+  EFI_MEMORY_DESCRIPTOR             *MemoryMapStart;\r
 \r
   //\r
   // Make sure the parameters are valid\r
@@ -1324,6 +1599,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
@@ -1353,11 +1629,17 @@ 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 = NEXT_MEMORY_DESCRIPTOR (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
@@ -1384,19 +1666,23 @@ CoreGetMemoryMap (
           }\r
         }\r
 \r
-        MemoryMap = NEXT_MEMORY_DESCRIPTOR (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
   }\r
 \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
   Status = EFI_SUCCESS;\r
 \r
 Done:\r
-\r
-  CoreReleaseMemoryLock ();\r
-\r
-  CoreReleaseGcdMemoryLock ();\r
-\r
   //\r
   // Update the map key finally\r
   //\r
@@ -1404,6 +1690,10 @@ Done:
     *MapKey = mMemoryMapKey;\r
   }\r
 \r
+  CoreReleaseMemoryLock ();\r
+\r
+  CoreReleaseGcdMemoryLock ();\r
+\r
   *MemoryMapSize = BufferSize;\r
 \r
   return Status;\r