Pull EdkModulePkg/Core/Dxe/Mem/Page.c into sparse tree

>From edk2 rev 2398

Signed-off-by: Alex Williamson <alex.williamson@xxxxxx>
---

diff -r 7988fb818c3b edk2-sparse/EdkModulePkg/Core/Dxe/Mem/Page.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/edk2-sparse/EdkModulePkg/Core/Dxe/Mem/Page.c	Wed Oct 10 11:57:54 2007 -0600
@@ -0,0 +1,1656 @@
+/*++
+
+Copyright (c) 2007, Intel Corporation                                                         
+All rights reserved. This program and the accompanying materials                          
+are licensed and made available under the terms and conditions of the BSD License         
+which accompanies this distribution.  The full text of the license may be found at        
+http://opensource.org/licenses/bsd-license.php                                            
+                                                                                          
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+
+Module Name:
+
+  page.c
+
+Abstract:
+
+  EFI Memory page management
+
+
+Revision History
+
+--*/
+
+#include <DxeMain.h>
+
+#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT  (EFI_PAGE_SIZE)
+
+//
+// Entry for tracking the memory regions for each memory type to help cooalese like memory types
+//
+typedef struct {
+  EFI_PHYSICAL_ADDRESS  BaseAddress;
+  EFI_PHYSICAL_ADDRESS  MaximumAddress;
+  UINT64                CurrentNumberOfPages;
+  UINTN                 InformationIndex;
+} EFI_MEMORY_TYPE_STAISTICS;
+
+//
+// MemoryMap - The current memory map
+//
+UINTN     mMemoryMapKey = 0;
+
+//
+// mMapStack - space to use as temp storage to build new map descriptors
+// mMapDepth - depth of new descriptor stack
+//
+
+#define MAX_MAP_DEPTH 6
+UINTN         mMapDepth = 0;
+MEMORY_MAP    mMapStack[MAX_MAP_DEPTH];
+UINTN         mFreeMapStack = 0;
+//
+// This list maintain the free memory map list
+//
+LIST_ENTRY   mFreeMemoryMapEntryList  = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
+BOOLEAN mMemoryTypeInformationInitialized = FALSE;
+
+EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiReservedMemoryType
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiLoaderCode
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiLoaderData
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiBootServicesCode
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiBootServicesData
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiRuntimeServicesCode
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiRuntimeServicesData
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiConventionalMemory
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiUnusableMemory
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiACPIReclaimMemory
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiACPIMemoryNVS
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiMemoryMappedIO
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiMemoryMappedIOPortSpace
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiPalCode
+  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }   // EfiMaxMemoryType
+};
+
+EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS;
+
+EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
+  { EfiReservedMemoryType,      0 },
+  { EfiLoaderCode,              0 },
+  { EfiLoaderData,              0 },
+  { EfiBootServicesCode,        0 },
+  { EfiBootServicesData,        0 },
+  { EfiRuntimeServicesCode,     0 },
+  { EfiRuntimeServicesData,     0 },
+  { EfiConventionalMemory,      0 },
+  { EfiUnusableMemory,          0 },
+  { EfiACPIReclaimMemory,       0 },
+  { EfiACPIMemoryNVS,           0 },
+  { EfiMemoryMappedIO,          0 },
+  { EfiMemoryMappedIOPortSpace, 0 },
+  { EfiPalCode,                 0 },
+  { EfiMaxMemoryType,           0 }
+};
+
+//
+// Internal prototypes
+//
+STATIC
+VOID 
+PromoteMemoryResource (
+  VOID
+);
+
+STATIC
+VOID
+CoreAddRange (
+  IN EFI_MEMORY_TYPE          Type,
+  IN EFI_PHYSICAL_ADDRESS     Start,
+  IN EFI_PHYSICAL_ADDRESS     End,
+  IN UINT64                   Attribute
+  );
+
+STATIC
+VOID
+CoreFreeMemoryMapStack (
+  VOID
+  );
+
+STATIC
+EFI_STATUS
+CoreConvertPages (
+  IN UINT64           Start,
+  IN UINT64           NumberOfPages,
+  IN EFI_MEMORY_TYPE  NewType
+  );
+
+STATIC
+VOID
+RemoveMemoryMapEntry (
+  MEMORY_MAP      *Entry
+  );
+  
+STATIC
+MEMORY_MAP *
+AllocateMemoryMapEntry (
+  VOID
+  );
+ 
+VOID
+CoreAcquireMemoryLock (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Enter critical section by gaining lock on gMemoryLock
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  CoreAcquireLock (&gMemoryLock);
+}
+
+
+VOID
+CoreReleaseMemoryLock (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Exit critical section by releasing lock on gMemoryLock
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  CoreReleaseLock (&gMemoryLock);
+}
+
+STATIC
+VOID
+PromoteMemoryResource (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  LIST_ENTRY                       *Link;
+  EFI_GCD_MAP_ENTRY                *Entry;
+
+  DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "Promote the memory resource\n"));
+  
+  CoreAcquireGcdMemoryLock ();
+  
+  Link = mGcdMemorySpaceMap.ForwardLink;
+  while (Link != &mGcdMemorySpaceMap) {
+
+    Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+    if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
+        Entry->EndAddress < EFI_MAX_ADDRESS &&
+        (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+          (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
+      //
+      // Update the GCD map
+      //
+      Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
+      Entry->Capabilities |= EFI_MEMORY_TESTED;
+      Entry->ImageHandle  = gDxeCoreImageHandle;
+      Entry->DeviceHandle = NULL;
+
+      //
+      // Add to allocable system memory resource
+      //      
+
+      CoreAddRange (
+        EfiConventionalMemory, 
+        Entry->BaseAddress, 
+        Entry->EndAddress, 
+        Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+        );
+      CoreFreeMemoryMapStack ();
+      
+    }
+
+    Link = Link->ForwardLink;
+  }
+  
+  CoreReleaseGcdMemoryLock ();
+  
+  return;
+}
+
+VOID
+CoreAddMemoryDescriptor (
+  IN EFI_MEMORY_TYPE       Type,
+  IN EFI_PHYSICAL_ADDRESS  Start,
+  IN UINT64                NumberOfPages,
+  IN UINT64                Attribute
+  )
+/*++
+
+Routine Description:
+
+  Called to initialize the memory map and add descriptors to
+  the current descriptor list.
+
+  The first descriptor that is added must be general usable
+  memory as the addition allocates heap.
+
+Arguments:
+
+  Type          - The type of memory to add
+
+  Start         - The starting address in the memory range
+                  Must be page aligned
+
+  NumberOfPages - The number of pages in the range
+
+  Attribute     - Attributes of the memory to add
+
+Returns:
+
+  None.  The range is added to the memory map
+
+--*/
+{
+  EFI_PHYSICAL_ADDRESS        End;
+  EFI_STATUS                  Status;
+  UINTN                       Index;
+  UINTN                       FreeIndex;
+
+  if ((Start & EFI_PAGE_MASK) != 0) {
+    return;
+  }
+
+  if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {
+    return;
+  }
+  
+  CoreAcquireMemoryLock ();
+  End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
+  CoreAddRange (Type, Start, End, Attribute);
+  CoreFreeMemoryMapStack ();
+  CoreReleaseMemoryLock ();
+
+  //
+  // Check to see if the statistics for the different memory types have already been established
+  //
+  if (mMemoryTypeInformationInitialized) {
+    return;
+  }
+
+  //
+  // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
+  //
+  for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+    //
+    // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+    //
+    Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
+    if (Type < 0 || Type > EfiMaxMemoryType) {
+      continue;
+    }
+
+    if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+      //
+      // Allocate pages for the current memory type from the top of available memory
+      //
+      Status = CoreAllocatePages (
+                 AllocateAnyPages,
+                 Type,
+                 gMemoryTypeInformation[Index].NumberOfPages,
+                 &mMemoryTypeStatistics[Type].BaseAddress
+                 );
+      if (EFI_ERROR (Status)) {
+        //
+        // If an error occurs allocating the pages for the current memory type, then 
+        // free all the pages allocates for the previous memory types and return.  This
+        // operation with be retied when/if more memory is added to the system
+        //
+        for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
+          //
+          // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+          //
+          Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
+          if (Type < 0 || Type > EfiMaxMemoryType) {
+            continue;
+          }
+
+          if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
+            CoreFreePages (
+              mMemoryTypeStatistics[Type].BaseAddress, 
+              gMemoryTypeInformation[FreeIndex].NumberOfPages
+              );
+            mMemoryTypeStatistics[Type].BaseAddress    = 0;
+            mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS;
+          }
+        }
+        return;
+      }
+
+      //
+      // Compute the address at the top of the current statistics
+      //
+      mMemoryTypeStatistics[Type].MaximumAddress = 
+        mMemoryTypeStatistics[Type].BaseAddress + 
+        LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
+
+      //
+      // If the current base address is the lowest address so far, then update the default 
+      // maximum address
+      //
+      if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
+        mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
+      }
+    }
+  }
+
+  //
+  // There was enough system memory for all the the memory types were allocated.  So,
+  // those memory areas can be freed for future allocations, and all future memory
+  // allocations can occur within their respective bins
+  //
+  for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+    //
+    // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+    //
+    Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
+    if (Type < 0 || Type > EfiMaxMemoryType) {
+      continue;
+    }
+
+    if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+      CoreFreePages (
+        mMemoryTypeStatistics[Type].BaseAddress, 
+        gMemoryTypeInformation[Index].NumberOfPages
+        );
+      gMemoryTypeInformation[Index].NumberOfPages = 0;
+    }
+  }
+
+  //
+  // If the number of pages reserved for a memory type is 0, then all allocations for that type
+  // should be in the default range.
+  //
+  for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
+    for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+      if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
+        mMemoryTypeStatistics[Type].InformationIndex = Index;
+      }
+    }
+    mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
+    if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) {
+      mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
+    }
+  }
+
+  mMemoryTypeInformationInitialized = TRUE;
+}
+
+
+STATIC
+VOID
+CoreAddRange (
+  IN EFI_MEMORY_TYPE          Type,
+  IN EFI_PHYSICAL_ADDRESS     Start,
+  IN EFI_PHYSICAL_ADDRESS     End,
+  IN UINT64                   Attribute
+  )
+/*++
+
+Routine Description:
+
+  Internal function.  Adds a ranges to the memory map.
+  The range must not already exist in the map.
+
+Arguments:
+
+  Type    - The type of memory range to add
+
+  Start   - The starting address in the memory range
+            Must be paged aligned
+
+  End     - The last address in the range
+          Must be the last byte of a page
+
+  Attribute - The attributes of the memory range to add
+
+Returns:
+
+  None.  The range is added to the memory map
+
+--*/
+{
+  LIST_ENTRY        *Link;
+  MEMORY_MAP        *Entry;
+
+  ASSERT ((Start & EFI_PAGE_MASK) == 0);
+  ASSERT (End > Start) ;
+
+  ASSERT_LOCKED (&gMemoryLock);
+  
+  DEBUG ((EFI_D_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
+
+  //
+  // Memory map being altered so updated key
+  //
+  mMemoryMapKey += 1;
+
+  //
+  // UEFI 2.0 added an event group for notificaiton on memory map changes.
+  // So we need to signal this Event Group every time the memory map changes.
+  // If we are in EFI 1.10 compatability mode no event groups will be 
+  // found and nothing will happen we we call this function. These events
+  // will get signaled but since a lock is held around the call to this 
+  // function the notificaiton events will only be called after this funciton
+  // returns and the lock is released.
+  //
+  CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
+
+  //
+  // Look for adjoining memory descriptor
+  //
+  
+  // Two memory descriptors can only be merged if they have the same Type
+  // and the same Attribute
+  //
+
+  Link = gMemoryMap.ForwardLink;
+  while (Link != &gMemoryMap) {
+    Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+    Link  = Link->ForwardLink;
+
+    if (Entry->Type != Type) {
+      continue;
+    }
+
+    if (Entry->Attribute != Attribute) {
+      continue;
+    }
+
+    if (Entry->End + 1 == Start) {
+      
+      Start = Entry->Start;
+      RemoveMemoryMapEntry (Entry);
+
+    } else if (Entry->Start == End + 1) {
+      
+      End = Entry->End;
+      RemoveMemoryMapEntry (Entry);
+    }
+  }
+
+  //
+  // Add descriptor 
+  //
+
+  mMapStack[mMapDepth].Signature     = MEMORY_MAP_SIGNATURE;
+  mMapStack[mMapDepth].FromPages      = FALSE;
+  mMapStack[mMapDepth].Type          = Type;
+  mMapStack[mMapDepth].Start         = Start;
+  mMapStack[mMapDepth].End           = End;
+  mMapStack[mMapDepth].VirtualStart  = 0;
+  mMapStack[mMapDepth].Attribute     = Attribute;
+  InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
+
+  mMapDepth += 1;
+  ASSERT (mMapDepth < MAX_MAP_DEPTH);
+
+  return ;
+}
+
+STATIC
+VOID
+CoreFreeMemoryMapStack (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Internal function.  Moves any memory descriptors that are on the
+  temporary descriptor stack to heap.
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  MEMORY_MAP      *Entry;
+  MEMORY_MAP      *Entry2;
+  LIST_ENTRY      *Link2;
+
+  ASSERT_LOCKED (&gMemoryLock);
+
+  //
+  // If already freeing the map stack, then return
+  //
+  if (mFreeMapStack) {
+    return ;
+  }
+
+  //
+  // Move the temporary memory descriptor stack into pool
+  //
+  mFreeMapStack += 1;
+
+  while (mMapDepth) {
+    //
+    // Deque an memory map entry from mFreeMemoryMapEntryList 
+    //
+    Entry = AllocateMemoryMapEntry ();
+    
+    ASSERT (Entry);
+
+    //
+    // Update to proper entry
+    //
+    mMapDepth -= 1;
+
+    if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
+
+      //
+      // Move this entry to general memory
+      //
+      RemoveEntryList (&mMapStack[mMapDepth].Link);
+      mMapStack[mMapDepth].Link.ForwardLink = NULL;
+
+      CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
+      Entry->FromPages = TRUE;
+
+      //
+      // Find insertion location
+      //
+      for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
+        Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+        if (Entry2->FromPages && Entry2->Start > Entry->Start) {
+          break;
+        }
+      }
+
+      InsertTailList (Link2, &Entry->Link);
+
+    } else {
+      // 
+      // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
+      // so here no need to move it to memory.
+      //
+      InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+    }
+  }
+
+  mFreeMapStack -= 1;
+}
+
+STATIC
+VOID
+RemoveMemoryMapEntry (
+  MEMORY_MAP      *Entry
+  )
+/*++
+
+Routine Description:
+
+  Internal function.  Removes a descriptor entry.
+
+Arguments:
+
+  Entry   - The entry to remove
+
+Returns:
+
+  None
+
+--*/
+{
+  RemoveEntryList (&Entry->Link);
+  Entry->Link.ForwardLink = NULL;
+
+  if (Entry->FromPages) {
+  	//
+  	// Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
+  	//
+    InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+  }
+}
+
+STATIC
+MEMORY_MAP *
+AllocateMemoryMapEntry (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Internal function.  Deque a descriptor entry from the mFreeMemoryMapEntryList.
+  If the list is emtry, then allocate a new page to refuel the list. 
+  Please Note this algorithm to allocate the memory map descriptor has a property
+  that the memory allocated for memory entries always grows, and will never really be freed 
+  For example, if the current boot uses 2000 memory map entries at the maximum point, but
+  ends up with only 50 at the time the OS is booted, then the memory associated with the 1950 
+  memory map entries is still allocated from EfiBootServicesMemory.  
+
+Arguments:
+
+  NONE
+
+Returns:
+
+  The Memory map descriptor dequed from the mFreeMemoryMapEntryList
+
+--*/ 
+{
+  MEMORY_MAP*            FreeDescriptorEntries;
+  MEMORY_MAP*            Entry;
+  UINTN                  Index;
+  
+  if (IsListEmpty (&mFreeMemoryMapEntryList)) {
+    // 
+    // The list is empty, to allocate one page to refuel the list
+    //
+    FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);
+    if(FreeDescriptorEntries != NULL) {
+      //
+      // Enque the free memmory map entries into the list
+      //
+      for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) {
+        FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
+        InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
+      }     
+    } else {
+      return NULL;
+    }
+  }
+  //
+  // dequeue the first descriptor from the list
+  //
+  Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+  RemoveEntryList (&Entry->Link);
+  
+  return Entry;
+}    
+
+STATIC
+EFI_STATUS
+CoreConvertPages (
+  IN UINT64           Start,
+  IN UINT64           NumberOfPages,
+  IN EFI_MEMORY_TYPE  NewType
+  )
+/*++
+
+Routine Description:
+
+  Internal function.  Converts a memory range to the specified type.
+  The range must exist in the memory map.
+
+Arguments:
+
+  Start         - The first address of the range
+                  Must be page aligned
+
+  NumberOfPages - The number of pages to convert
+
+  NewType       - The new type for the memory range
+
+Returns:
+
+  EFI_INVALID_PARAMETER   - Invalid parameter
+  
+  EFI_NOT_FOUND           - Could not find a descriptor cover the specified range 
+                            or convertion not allowed.
+  
+  EFI_SUCCESS             - Successfully converts the memory range to the specified type.
+
+--*/
+{
+
+  UINT64          NumberOfBytes;
+  UINT64          End;
+  UINT64          RangeEnd;
+  UINT64          Attribute;
+  LIST_ENTRY      *Link;
+  MEMORY_MAP      *Entry;
+
+  Entry = NULL;
+  NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+  End = Start + NumberOfBytes - 1;
+
+  ASSERT (NumberOfPages);
+  ASSERT ((Start & EFI_PAGE_MASK) == 0);
+  ASSERT (End > Start) ;
+  ASSERT_LOCKED (&gMemoryLock);
+
+  if (NumberOfPages == 0 || (Start & EFI_PAGE_MASK ) || (Start > (Start + NumberOfBytes))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Convert the entire range
+  //
+
+  while (Start < End) {
+
+    //
+    // Find the entry that the covers the range
+    //
+    for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+      Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+
+      if (Entry->Start <= Start && Entry->End > Start) {
+        break;
+      }
+    }
+
+    if (Link == &gMemoryMap) {
+      DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
+      return EFI_NOT_FOUND;
+    }
+
+    //
+    // Convert range to the end, or to the end of the descriptor
+    // if that's all we've got
+    //
+    RangeEnd = End;
+    if (Entry->End < End) {
+      RangeEnd = Entry->End;
+    }
+
+    DEBUG ((EFI_D_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType));
+
+    //
+    // Debug code - verify conversion is allowed
+    //
+    if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
+      DEBUG ((EFI_D_ERROR , "ConvertPages: Incompatible memory types\n"));
+      return EFI_NOT_FOUND;
+    }  
+
+    //
+    // Update counters for the number of pages allocated to each memory type
+    //
+    if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {
+      if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && 
+          Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) {
+        if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
+          mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
+        } else {
+          mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
+        }
+      }
+    }
+
+    if (NewType >= 0 && NewType < EfiMaxMemoryType) {
+      if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) {
+        mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
+        if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > 
+            gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
+          gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
+        }
+      }
+    }
+
+    //
+    // Pull range out of descriptor
+    //
+    if (Entry->Start == Start) {
+      
+      //
+      // Clip start
+      //
+      Entry->Start = RangeEnd + 1;
+
+    } else if (Entry->End == RangeEnd) {
+      
+      //
+      // Clip end
+      //
+      Entry->End = Start - 1;
+
+    } else {
+
+      //
+      // Pull it out of the center, clip current
+      //
+      
+      //
+      // Add a new one
+      //
+      mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
+      mMapStack[mMapDepth].FromPages  = FALSE;
+      mMapStack[mMapDepth].Type      = Entry->Type;
+      mMapStack[mMapDepth].Start     = RangeEnd+1;
+      mMapStack[mMapDepth].End       = Entry->End;
+
+      //
+      // Inherit Attribute from the Memory Descriptor that is being clipped
+      //
+      mMapStack[mMapDepth].Attribute = Entry->Attribute;
+
+      Entry->End = Start - 1;
+      ASSERT (Entry->Start < Entry->End);
+
+      Entry = &mMapStack[mMapDepth];
+      InsertTailList (&gMemoryMap, &Entry->Link);
+
+      mMapDepth += 1;
+      ASSERT (mMapDepth < MAX_MAP_DEPTH);
+    }
+
+    //
+    // The new range inherits the same Attribute as the Entry 
+    //it is being cut out of
+    //
+    Attribute = Entry->Attribute;
+
+    //
+    // If the descriptor is empty, then remove it from the map
+    //
+    if (Entry->Start == Entry->End + 1) {
+      RemoveMemoryMapEntry (Entry);
+      Entry = NULL;
+    }
+    
+    //
+    // Add our new range in
+    //
+    CoreAddRange (NewType, Start, RangeEnd, Attribute);
+
+    //
+    // Move any map descriptor stack to general pool
+    //
+    CoreFreeMemoryMapStack ();
+
+    //
+    // Bump the starting address, and convert the next range
+    //
+    Start = RangeEnd + 1;
+  }
+
+  //
+  // Converted the whole range, done
+  //
+
+  return EFI_SUCCESS;
+}
+
+
+STATIC
+UINT64
+CoreFindFreePagesI (
+  IN UINT64           MaxAddress,
+  IN UINT64           NumberOfPages,
+  IN EFI_MEMORY_TYPE  NewType,
+  IN UINTN            Alignment
+  )
+/*++
+
+Routine Description:
+
+  Internal function. Finds a consecutive free page range below
+  the requested address.
+
+Arguments:
+
+  MaxAddress    - The address that the range must be below
+
+  NumberOfPages - Number of pages needed
+
+  NewType       - The type of memory the range is going to be turned into
+
+  Alignment     - Bits to align with
+
+Returns:
+
+  The base address of the range, or 0 if the range was not found
+
+--*/
+{
+  UINT64          NumberOfBytes;
+  UINT64          Target;
+  UINT64          DescStart;
+  UINT64          DescEnd;
+  UINT64          DescNumberOfBytes;
+  LIST_ENTRY      *Link;
+  MEMORY_MAP      *Entry;
+
+  if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
+    return 0;
+  }
+
+  if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
+    
+    //
+    // If MaxAddress is not aligned to the end of a page
+    //
+    
+    //
+    // Change MaxAddress to be 1 page lower
+    //
+    MaxAddress -= (EFI_PAGE_MASK + 1);
+    
+    //
+    // Set MaxAddress to a page boundary
+    //
+    MaxAddress &= ~EFI_PAGE_MASK;
+    
+    //
+    // Set MaxAddress to end of the page
+    //
+    MaxAddress |= EFI_PAGE_MASK;
+  }
+
+  NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+  Target = 0;
+
+  for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+    Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+  
+    //
+    // If it's not a free entry, don't bother with it
+    //
+    if (Entry->Type != EfiConventionalMemory) {
+      continue;
+    }
+
+    DescStart = Entry->Start;
+    DescEnd = Entry->End;
+
+    //
+    // If desc is past max allowed address, skip it
+    //
+    if (DescStart >= MaxAddress) {
+      continue;
+    }
+
+    //
+    // If desc ends past max allowed address, clip the end
+    //
+    if (DescEnd >= MaxAddress) {
+      DescEnd = MaxAddress;
+    }
+
+    DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
+
+    //
+    // Compute the number of bytes we can used from this 
+    // descriptor, and see it's enough to satisfy the request
+    //
+    DescNumberOfBytes = DescEnd - DescStart + 1;
+
+    if (DescNumberOfBytes >= NumberOfBytes) {
+
+      //
+      // If this is the best match so far remember it
+      //
+      if (DescEnd > Target) {
+        Target = DescEnd;
+      }
+    }
+  }          
+
+  //
+  // If this is a grow down, adjust target to be the allocation base
+  //
+  Target -= NumberOfBytes - 1;
+
+  //
+  // If we didn't find a match, return 0
+  //
+  if ((Target & EFI_PAGE_MASK) != 0) {
+    return 0;
+  }
+
+  return Target;
+}
+
+STATIC
+UINT64
+FindFreePages (
+    IN UINT64           MaxAddress,
+    IN UINT64           NoPages,
+    IN EFI_MEMORY_TYPE  NewType,
+    IN UINTN            Alignment
+    )
+/*++
+
+Routine Description:
+
+    Internal function.  Finds a consecutive free page range below
+    the requested address
+
+Arguments:
+
+    MaxAddress          - The address that the range must be below
+
+    NoPages             - Number of pages needed
+
+    NewType             - The type of memory the range is going to be turned into
+
+    Alignment           - Bits to align with
+
+Returns:
+
+    The base address of the range, or 0 if the range was not found.
+
+--*/
+{
+  UINT64  NewMaxAddress;
+  UINT64  Start;
+
+  NewMaxAddress = MaxAddress;
+
+  if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
+    NewMaxAddress  = mMemoryTypeStatistics[NewType].MaximumAddress;
+  } else {
+    if (NewMaxAddress > mDefaultMaximumAddress) {
+      NewMaxAddress  = mDefaultMaximumAddress;
+    }
+  }
+
+  Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);
+  if (!Start) {
+    Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
+    if (!Start) {
+      //
+      // Here means there may be no enough memory to use, so try to go through
+      // all the memory descript to promote the untested memory directly
+      //
+      PromoteMemoryResource ();
+
+      //
+      // Allocate memory again after the memory resource re-arranged
+      //
+      Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
+    }
+  }
+
+  return Start;
+}
+
+
+EFI_STATUS
+EFIAPI
+CoreAllocatePages (
+  IN EFI_ALLOCATE_TYPE      Type,
+  IN EFI_MEMORY_TYPE        MemoryType,
+  IN UINTN                  NumberOfPages,
+  IN OUT EFI_PHYSICAL_ADDRESS  *Memory
+  )
+/*++
+
+Routine Description:
+
+  Allocates pages from the memory map.
+
+Arguments:
+
+  Type          - The type of allocation to perform
+
+  MemoryType    - The type of memory to turn the allocated pages into
+
+  NumberOfPages - The number of pages to allocate
+
+  Memory        - A pointer to receive the base allocated memory address
+
+Returns:
+
+  Status. On success, Memory is filled in with the base address allocated
+
+  EFI_INVALID_PARAMETER     - Parameters violate checking rules defined in spec.
+  
+  EFI_NOT_FOUND             - Could not allocate pages match the requirement.
+  
+  EFI_OUT_OF_RESOURCES      - No enough pages to allocate.
+  
+  EFI_SUCCESS               - Pages successfully allocated.
+
+--*/
+{
+  EFI_STATUS      Status;
+  UINT64          Start;
+  UINT64          MaxAddress;
+  UINTN           Alignment;
+
+  if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) ||
+       MemoryType == EfiConventionalMemory) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
+
+  if  (MemoryType == EfiACPIReclaimMemory   ||
+       MemoryType == EfiACPIMemoryNVS       ||
+       MemoryType == EfiRuntimeServicesCode ||
+       MemoryType == EfiRuntimeServicesData) {
+
+    Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
+  }
+
+  if (Type == AllocateAddress) {
+    if ((*Memory & (Alignment - 1)) != 0) {
+      return EFI_NOT_FOUND;
+    }
+  }
+
+  NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
+  NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
+
+  //
+  // If this is for below a particular address, then 
+  //
+  Start = *Memory;
+  
+  //
+  // The max address is the max natively addressable address for the processor
+  //
+  MaxAddress = EFI_MAX_ADDRESS;
+  
+  if (Type == AllocateMaxAddress) {
+    MaxAddress = Start;
+  }
+
+  CoreAcquireMemoryLock ();
+  
+  //
+  // If not a specific address, then find an address to allocate
+  //
+  if (Type != AllocateAddress) {
+    Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
+    if (Start == 0) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Done;
+    }
+  }
+
+  //
+  // Convert pages from FreeMemory to the requested type
+  //
+  Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
+
+Done:
+  CoreReleaseMemoryLock ();
+
+  if (!EFI_ERROR (Status)) {
+    *Memory = Start;
+  }
+
+  return Status;
+}
+
+
+
+
+EFI_STATUS 
+EFIAPI
+CoreFreePages (
+  IN EFI_PHYSICAL_ADDRESS   Memory,
+  IN UINTN                  NumberOfPages
+  )
+/*++
+
+Routine Description:
+
+  Frees previous allocated pages.
+
+Arguments:
+
+  Memory        - Base address of memory being freed
+
+  NumberOfPages - The number of pages to free
+
+Returns:
+
+  EFI_NOT_FOUND       - Could not find the entry that covers the range
+  
+  EFI_INVALID_PARAMETER   - Address not aligned
+  
+  EFI_SUCCESS         -Pages successfully freed.
+
+--*/
+{
+  EFI_STATUS      Status;
+  LIST_ENTRY      *Link;
+  MEMORY_MAP      *Entry;
+  UINTN           Alignment;
+
+  //
+  // Free the range
+  //
+  CoreAcquireMemoryLock ();
+
+  //
+  // Find the entry that the covers the range
+  //
+  Entry = NULL;
+  for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+    Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+    if (Entry->Start <= Memory && Entry->End > Memory) {
+        break;
+    }
+  }
+  if (Link == &gMemoryMap) {
+    CoreReleaseMemoryLock ();
+    return EFI_NOT_FOUND;
+  }
+
+  Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
+
+  if  (Entry->Type == EfiACPIReclaimMemory   ||
+       Entry->Type == EfiACPIMemoryNVS       ||
+       Entry->Type == EfiRuntimeServicesCode ||
+       Entry->Type == EfiRuntimeServicesData) {
+
+    Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
+
+  }
+
+  if ((Memory & (Alignment - 1)) != 0) {
+    CoreReleaseMemoryLock ();
+    return EFI_INVALID_PARAMETER;
+  }
+
+  NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
+  NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
+
+  Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
+
+  CoreReleaseMemoryLock ();
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Destroy the contents
+  //
+  if (Memory < EFI_MAX_ADDRESS) {
+    DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);
+  }
+  
+  return Status;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMap (
+  IN OUT UINTN                  *MemoryMapSize,
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
+  OUT UINTN                     *MapKey,
+  OUT UINTN                     *DescriptorSize,
+  OUT UINT32                    *DescriptorVersion
+  )
+/*++
+
+Routine Description:
+
+  This function returns a copy of the current memory map. The map is an array of 
+  memory descriptors, each of which describes a contiguous block of memory.
+
+Arguments:
+
+  MemoryMapSize     - A pointer to the size, in bytes, of the MemoryMap buffer. On
+                      input, this is the size of the buffer allocated by the caller. 
+                      On output, it is the size of the buffer returned by the firmware 
+                      if the buffer was large enough, or the size of the buffer needed 
+                      to contain the map if the buffer was too small.
+  MemoryMap         - A pointer to the buffer in which firmware places the current memory map.
+  MapKey            - A pointer to the location in which firmware returns the key for the
+                      current memory map.
+  DescriptorSize    - A pointer to the location in which firmware returns the size, in
+                      bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+  DescriptorVersion - A pointer to the location in which firmware returns the version
+                      number associated with the EFI_MEMORY_DESCRIPTOR.
+
+Returns:
+
+  EFI_SUCCESS           - The memory map was returned in the MemoryMap buffer.       
+  EFI_BUFFER_TOO_SMALL  - The MemoryMap buffer was too small. The current buffer size
+                          needed to hold the memory map is returned in MemoryMapSize.
+  EFI_INVALID_PARAMETER - One of the parameters has an invalid value.                
+
+--*/
+{
+  EFI_STATUS                        Status;
+  UINTN                             Size;  
+  UINTN                             BufferSize;  
+  UINTN                             NumberOfRuntimeEntries;
+  LIST_ENTRY                        *Link;
+  MEMORY_MAP                        *Entry;  
+  EFI_GCD_MAP_ENTRY                 *GcdMapEntry;  
+
+  //
+  // Make sure the parameters are valid
+  //
+  if (MemoryMapSize == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  
+  CoreAcquireGcdMemoryLock ();
+  
+  //
+  // Count the number of Reserved and MMIO entries that are marked for runtime use
+  //
+  NumberOfRuntimeEntries = 0;
+  for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
+    GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+    if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
+        (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {
+      if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
+        NumberOfRuntimeEntries++;
+      }
+    }
+  }
+
+  Size = sizeof (EFI_MEMORY_DESCRIPTOR);
+
+  //
+  // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
+  // prevent people from having pointer math bugs in their code.
+  // now you have to use *DescriptorSize to make things work.
+  //
+  Size += sizeof(UINT64) - (Size % sizeof (UINT64));
+
+  if (DescriptorSize != NULL) {
+    *DescriptorSize = Size;
+  }
+  
+  if (DescriptorVersion != NULL) {
+    *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
+  }
+
+  CoreAcquireMemoryLock ();
+
+  //
+  // Compute the buffer size needed to fit the entire map
+  //
+  BufferSize = Size * NumberOfRuntimeEntries;
+  for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+    BufferSize += Size;
+  }
+
+  if (*MemoryMapSize < BufferSize) {
+    Status = EFI_BUFFER_TOO_SMALL;
+    goto Done;
+  }
+
+  if (MemoryMap == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Done;
+  }
+
+  //
+  // Build the map
+  //
+  ZeroMem (MemoryMap, Size);
+  for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+    Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+    ASSERT (Entry->VirtualStart == 0);
+
+    MemoryMap->Type           = Entry->Type;
+    MemoryMap->PhysicalStart  = Entry->Start;
+    MemoryMap->VirtualStart   = Entry->VirtualStart;
+    MemoryMap->NumberOfPages  = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
+  
+    switch (Entry->Type) {
+    case EfiRuntimeServicesCode:
+    case EfiRuntimeServicesData:
+    case EfiPalCode:
+      MemoryMap->Attribute = Entry->Attribute | EFI_MEMORY_RUNTIME;
+      break;
+
+    default:
+      MemoryMap->Attribute = Entry->Attribute;
+      break;
+    }
+    
+    MemoryMap = NextMemoryDescriptor (MemoryMap, Size);
+  }
+
+  for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
+    GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+    if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
+        (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {
+      if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
+        
+        MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;
+        MemoryMap->VirtualStart  = 0;
+        MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);
+        MemoryMap->Attribute     = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;
+
+        if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {
+          MemoryMap->Type = EfiReservedMemoryType;
+        } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+          if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
+            MemoryMap->Type = EfiMemoryMappedIOPortSpace;
+          } else {
+            MemoryMap->Type = EfiMemoryMappedIO;
+          }
+        }
+
+        MemoryMap = NextMemoryDescriptor (MemoryMap, Size);
+      }
+    }
+  }
+  
+  Status = EFI_SUCCESS;
+
+Done:
+
+  CoreReleaseMemoryLock ();
+  
+  CoreReleaseGcdMemoryLock ();
+  
+  // 
+  // Update the map key finally 
+  // 
+  if (MapKey != NULL) {
+    *MapKey = mMemoryMapKey;
+  }
+  
+  *MemoryMapSize = BufferSize;
+  
+  return Status;
+}
+
+VOID *
+CoreAllocatePoolPages (
+  IN EFI_MEMORY_TYPE    PoolType,
+  IN UINTN              NumberOfPages,
+  IN UINTN              Alignment
+  )
+/*++
+
+Routine Description:
+
+  Internal function.  Used by the pool functions to allocate pages
+  to back pool allocation requests.
+
+Arguments:
+
+  PoolType      - The type of memory for the new pool pages
+
+  NumberOfPages - No of pages to allocate
+
+  Alignment     - Bits to align.
+
+Returns:
+
+  The allocated memory, or NULL
+
+--*/
+{
+  UINT64            Start;
+
+  //
+  // Find the pages to convert
+  //
+  Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
+
+  //
+  // Convert it to boot services data
+  //
+  if (Start == 0) {
+    DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages));
+  } else {
+    CoreConvertPages (Start, NumberOfPages, PoolType);
+  }
+
+  return (VOID *)(UINTN)Start;
+}
+
+VOID
+CoreFreePoolPages (
+  IN EFI_PHYSICAL_ADDRESS   Memory,
+  IN UINTN                  NumberOfPages
+  )
+/*++
+
+Routine Description:
+
+  Internal function.  Frees pool pages allocated via AllocatePoolPages ()
+
+Arguments:
+
+  Memory        - The base address to free
+
+  NumberOfPages - The number of pages to free
+
+Returns:
+
+  None
+
+--*/
+{
+  CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
+}
+
+
+EFI_STATUS
+CoreTerminateMemoryMap (
+  IN UINTN          MapKey
+  )
+/*++
+
+Routine Description:
+
+  Make sure the memory map is following all the construction rules, 
+  it is the last time to check memory map error before exit boot services.
+
+Arguments:
+
+  MapKey        - Memory map key
+
+Returns:
+
+  EFI_INVALID_PARAMETER       - Memory map not consistent with construction rules.
+  
+  EFI_SUCCESS                 - Valid memory map.
+
+--*/
+{
+  EFI_STATUS        Status;
+  LIST_ENTRY        *Link;
+  MEMORY_MAP        *Entry;
+
+  Status = EFI_SUCCESS;
+
+  CoreAcquireMemoryLock ();
+
+  if (MapKey == mMemoryMapKey) {
+
+    //
+    // Make sure the memory map is following all the construction rules
+    // This is the last chance we will be able to display any messages on
+    // the  console devices.
+    //
+
+    for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+      Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+      if (Entry->Attribute & EFI_MEMORY_RUNTIME) { 
+        if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {
+          DEBUG((EFI_D_ERROR, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
+          CoreReleaseMemoryLock ();
+          return EFI_INVALID_PARAMETER;
+        }
+        if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {
+          DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
+          CoreReleaseMemoryLock ();
+          return EFI_INVALID_PARAMETER;
+        }
+        if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {
+          DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
+          CoreReleaseMemoryLock ();
+          return EFI_INVALID_PARAMETER;
+        }
+      }
+    }
+
+    //
+    // The map key they gave us matches what we expect. Fall through and
+    // return success. In an ideal world we would clear out all of
+    // EfiBootServicesCode and EfiBootServicesData. However this function
+    // is not the last one called by ExitBootServices(), so we have to
+    // preserve the memory contents.
+    //
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+  }
+
+  CoreReleaseMemoryLock ();
+
+  return Status;
+}
+
+
+
+
+
+
+
+