Home | History | Annotate | Download | only in Mem
      1 /** @file
      2   UEFI Memory page management functions.
      3 
      4 Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "DxeMain.h"
     16 #include "Imem.h"
     17 
     18 #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT  (EFI_PAGE_SIZE)
     19 
     20 //
     21 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
     22 //
     23 typedef struct {
     24   EFI_PHYSICAL_ADDRESS  BaseAddress;
     25   EFI_PHYSICAL_ADDRESS  MaximumAddress;
     26   UINT64                CurrentNumberOfPages;
     27   UINT64                NumberOfPages;
     28   UINTN                 InformationIndex;
     29   BOOLEAN               Special;
     30   BOOLEAN               Runtime;
     31 } EFI_MEMORY_TYPE_STATISTICS;
     32 
     33 //
     34 // MemoryMap - The current memory map
     35 //
     36 UINTN     mMemoryMapKey = 0;
     37 
     38 #define MAX_MAP_DEPTH 6
     39 
     40 ///
     41 /// mMapDepth - depth of new descriptor stack
     42 ///
     43 UINTN         mMapDepth = 0;
     44 ///
     45 /// mMapStack - space to use as temp storage to build new map descriptors
     46 ///
     47 MEMORY_MAP    mMapStack[MAX_MAP_DEPTH];
     48 UINTN         mFreeMapStack = 0;
     49 ///
     50 /// This list maintain the free memory map list
     51 ///
     52 LIST_ENTRY   mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
     53 BOOLEAN      mMemoryTypeInformationInitialized = FALSE;
     54 
     55 EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
     56   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  FALSE },  // EfiReservedMemoryType
     57   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiLoaderCode
     58   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiLoaderData
     59   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiBootServicesCode
     60   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiBootServicesData
     61   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  TRUE  },  // EfiRuntimeServicesCode
     62   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  TRUE  },  // EfiRuntimeServicesData
     63   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiConventionalMemory
     64   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiUnusableMemory
     65   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  FALSE },  // EfiACPIReclaimMemory
     66   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  FALSE },  // EfiACPIMemoryNVS
     67   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiMemoryMappedIO
     68   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiMemoryMappedIOPortSpace
     69   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  TRUE  },  // EfiPalCode
     70   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiPersistentMemory
     71   { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }   // EfiMaxMemoryType
     72 };
     73 
     74 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ADDRESS;
     75 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ADDRESS;
     76 
     77 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
     78   { EfiReservedMemoryType,      0 },
     79   { EfiLoaderCode,              0 },
     80   { EfiLoaderData,              0 },
     81   { EfiBootServicesCode,        0 },
     82   { EfiBootServicesData,        0 },
     83   { EfiRuntimeServicesCode,     0 },
     84   { EfiRuntimeServicesData,     0 },
     85   { EfiConventionalMemory,      0 },
     86   { EfiUnusableMemory,          0 },
     87   { EfiACPIReclaimMemory,       0 },
     88   { EfiACPIMemoryNVS,           0 },
     89   { EfiMemoryMappedIO,          0 },
     90   { EfiMemoryMappedIOPortSpace, 0 },
     91   { EfiPalCode,                 0 },
     92   { EfiPersistentMemory,        0 },
     93   { EfiMaxMemoryType,           0 }
     94 };
     95 //
     96 // Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
     97 // and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
     98 //  address assigned by DXE core.
     99 //
    100 GLOBAL_REMOVE_IF_UNREFERENCED   BOOLEAN       gLoadFixedAddressCodeMemoryReady = FALSE;
    101 
    102 /**
    103   Enter critical section by gaining lock on gMemoryLock.
    104 
    105 **/
    106 VOID
    107 CoreAcquireMemoryLock (
    108   VOID
    109   )
    110 {
    111   CoreAcquireLock (&gMemoryLock);
    112 }
    113 
    114 
    115 
    116 /**
    117   Exit critical section by releasing lock on gMemoryLock.
    118 
    119 **/
    120 VOID
    121 CoreReleaseMemoryLock (
    122   VOID
    123   )
    124 {
    125   CoreReleaseLock (&gMemoryLock);
    126 }
    127 
    128 
    129 
    130 
    131 /**
    132   Internal function.  Removes a descriptor entry.
    133 
    134   @param  Entry                  The entry to remove
    135 
    136 **/
    137 VOID
    138 RemoveMemoryMapEntry (
    139   IN OUT MEMORY_MAP      *Entry
    140   )
    141 {
    142   RemoveEntryList (&Entry->Link);
    143   Entry->Link.ForwardLink = NULL;
    144 
    145   if (Entry->FromPages) {
    146     //
    147     // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
    148     //
    149     InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
    150   }
    151 }
    152 
    153 /**
    154   Internal function.  Adds a ranges to the memory map.
    155   The range must not already exist in the map.
    156 
    157   @param  Type                   The type of memory range to add
    158   @param  Start                  The starting address in the memory range Must be
    159                                  paged aligned
    160   @param  End                    The last address in the range Must be the last
    161                                  byte of a page
    162   @param  Attribute              The attributes of the memory range to add
    163 
    164 **/
    165 VOID
    166 CoreAddRange (
    167   IN EFI_MEMORY_TYPE          Type,
    168   IN EFI_PHYSICAL_ADDRESS     Start,
    169   IN EFI_PHYSICAL_ADDRESS     End,
    170   IN UINT64                   Attribute
    171   )
    172 {
    173   LIST_ENTRY        *Link;
    174   MEMORY_MAP        *Entry;
    175 
    176   ASSERT ((Start & EFI_PAGE_MASK) == 0);
    177   ASSERT (End > Start) ;
    178 
    179   ASSERT_LOCKED (&gMemoryLock);
    180 
    181   DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
    182 
    183   //
    184   // If memory of type EfiConventionalMemory is being added that includes the page
    185   // starting at address 0, then zero the page starting at address 0.  This has
    186   // two benifits.  It helps find NULL pointer bugs and it also maximizes
    187   // compatibility with operating systems that may evaluate memory in this page
    188   // for legacy data structures.  If memory of any other type is added starting
    189   // at address 0, then do not zero the page at address 0 because the page is being
    190   // used for other purposes.
    191   //
    192   if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 1)) {
    193     SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
    194   }
    195 
    196   //
    197   // Memory map being altered so updated key
    198   //
    199   mMemoryMapKey += 1;
    200 
    201   //
    202   // UEFI 2.0 added an event group for notificaiton on memory map changes.
    203   // So we need to signal this Event Group every time the memory map changes.
    204   // If we are in EFI 1.10 compatability mode no event groups will be
    205   // found and nothing will happen we we call this function. These events
    206   // will get signaled but since a lock is held around the call to this
    207   // function the notificaiton events will only be called after this funciton
    208   // returns and the lock is released.
    209   //
    210   CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
    211 
    212   //
    213   // Look for adjoining memory descriptor
    214   //
    215 
    216   // Two memory descriptors can only be merged if they have the same Type
    217   // and the same Attribute
    218   //
    219 
    220   Link = gMemoryMap.ForwardLink;
    221   while (Link != &gMemoryMap) {
    222     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
    223     Link  = Link->ForwardLink;
    224 
    225     if (Entry->Type != Type) {
    226       continue;
    227     }
    228 
    229     if (Entry->Attribute != Attribute) {
    230       continue;
    231     }
    232 
    233     if (Entry->End + 1 == Start) {
    234 
    235       Start = Entry->Start;
    236       RemoveMemoryMapEntry (Entry);
    237 
    238     } else if (Entry->Start == End + 1) {
    239 
    240       End = Entry->End;
    241       RemoveMemoryMapEntry (Entry);
    242     }
    243   }
    244 
    245   //
    246   // Add descriptor
    247   //
    248 
    249   mMapStack[mMapDepth].Signature     = MEMORY_MAP_SIGNATURE;
    250   mMapStack[mMapDepth].FromPages      = FALSE;
    251   mMapStack[mMapDepth].Type          = Type;
    252   mMapStack[mMapDepth].Start         = Start;
    253   mMapStack[mMapDepth].End           = End;
    254   mMapStack[mMapDepth].VirtualStart  = 0;
    255   mMapStack[mMapDepth].Attribute     = Attribute;
    256   InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
    257 
    258   mMapDepth += 1;
    259   ASSERT (mMapDepth < MAX_MAP_DEPTH);
    260 
    261   return ;
    262 }
    263 
    264 /**
    265   Internal function.  Deque a descriptor entry from the mFreeMemoryMapEntryList.
    266   If the list is emtry, then allocate a new page to refuel the list.
    267   Please Note this algorithm to allocate the memory map descriptor has a property
    268   that the memory allocated for memory entries always grows, and will never really be freed
    269   For example, if the current boot uses 2000 memory map entries at the maximum point, but
    270   ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
    271   memory map entries is still allocated from EfiBootServicesMemory.
    272 
    273 
    274   @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
    275 
    276 **/
    277 MEMORY_MAP *
    278 AllocateMemoryMapEntry (
    279   VOID
    280   )
    281 {
    282   MEMORY_MAP*            FreeDescriptorEntries;
    283   MEMORY_MAP*            Entry;
    284   UINTN                  Index;
    285 
    286   if (IsListEmpty (&mFreeMemoryMapEntryList)) {
    287     //
    288     // The list is empty, to allocate one page to refuel the list
    289     //
    290     FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);
    291     if(FreeDescriptorEntries != NULL) {
    292       //
    293       // Enque the free memmory map entries into the list
    294       //
    295       for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) {
    296         FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
    297         InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
    298       }
    299     } else {
    300       return NULL;
    301     }
    302   }
    303   //
    304   // dequeue the first descriptor from the list
    305   //
    306   Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
    307   RemoveEntryList (&Entry->Link);
    308 
    309   return Entry;
    310 }
    311 
    312 
    313 /**
    314   Internal function.  Moves any memory descriptors that are on the
    315   temporary descriptor stack to heap.
    316 
    317 **/
    318 VOID
    319 CoreFreeMemoryMapStack (
    320   VOID
    321   )
    322 {
    323   MEMORY_MAP      *Entry;
    324   MEMORY_MAP      *Entry2;
    325   LIST_ENTRY      *Link2;
    326 
    327   ASSERT_LOCKED (&gMemoryLock);
    328 
    329   //
    330   // If already freeing the map stack, then return
    331   //
    332   if (mFreeMapStack != 0) {
    333     return ;
    334   }
    335 
    336   //
    337   // Move the temporary memory descriptor stack into pool
    338   //
    339   mFreeMapStack += 1;
    340 
    341   while (mMapDepth != 0) {
    342     //
    343     // Deque an memory map entry from mFreeMemoryMapEntryList
    344     //
    345     Entry = AllocateMemoryMapEntry ();
    346 
    347     ASSERT (Entry);
    348 
    349     //
    350     // Update to proper entry
    351     //
    352     mMapDepth -= 1;
    353 
    354     if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
    355 
    356       //
    357       // Move this entry to general memory
    358       //
    359       RemoveEntryList (&mMapStack[mMapDepth].Link);
    360       mMapStack[mMapDepth].Link.ForwardLink = NULL;
    361 
    362       CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
    363       Entry->FromPages = TRUE;
    364 
    365       //
    366       // Find insertion location
    367       //
    368       for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
    369         Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
    370         if (Entry2->FromPages && Entry2->Start > Entry->Start) {
    371           break;
    372         }
    373       }
    374 
    375       InsertTailList (Link2, &Entry->Link);
    376 
    377     } else {
    378       //
    379       // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
    380       // so here no need to move it to memory.
    381       //
    382       InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
    383     }
    384   }
    385 
    386   mFreeMapStack -= 1;
    387 }
    388 
    389 /**
    390   Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
    391 
    392 **/
    393 BOOLEAN
    394 PromoteMemoryResource (
    395   VOID
    396   )
    397 {
    398   LIST_ENTRY         *Link;
    399   EFI_GCD_MAP_ENTRY  *Entry;
    400   BOOLEAN            Promoted;
    401 
    402   DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
    403 
    404   CoreAcquireGcdMemoryLock ();
    405 
    406   Promoted = FALSE;
    407   Link = mGcdMemorySpaceMap.ForwardLink;
    408   while (Link != &mGcdMemorySpaceMap) {
    409 
    410     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    411 
    412     if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
    413         Entry->EndAddress < MAX_ADDRESS &&
    414         (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
    415           (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
    416       //
    417       // Update the GCD map
    418       //
    419       if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
    420         Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
    421       } else {
    422         Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
    423       }
    424       Entry->Capabilities |= EFI_MEMORY_TESTED;
    425       Entry->ImageHandle  = gDxeCoreImageHandle;
    426       Entry->DeviceHandle = NULL;
    427 
    428       //
    429       // Add to allocable system memory resource
    430       //
    431 
    432       CoreAddRange (
    433         EfiConventionalMemory,
    434         Entry->BaseAddress,
    435         Entry->EndAddress,
    436         Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
    437         );
    438       CoreFreeMemoryMapStack ();
    439 
    440       Promoted = TRUE;
    441     }
    442 
    443     Link = Link->ForwardLink;
    444   }
    445 
    446   CoreReleaseGcdMemoryLock ();
    447 
    448   return Promoted;
    449 }
    450 /**
    451   This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
    452   PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
    453   size of boot time and runtime code.
    454 
    455 **/
    456 VOID
    457 CoreLoadingFixedAddressHook (
    458   VOID
    459   )
    460 {
    461    UINT32                     RuntimeCodePageNumber;
    462    UINT32                     BootTimeCodePageNumber;
    463    EFI_PHYSICAL_ADDRESS       RuntimeCodeBase;
    464    EFI_PHYSICAL_ADDRESS       BootTimeCodeBase;
    465    EFI_STATUS                 Status;
    466 
    467    //
    468    // Make sure these 2 areas are not initialzied.
    469    //
    470    if (!gLoadFixedAddressCodeMemoryReady) {
    471      RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
    472      BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
    473      RuntimeCodeBase       = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
    474      BootTimeCodeBase      = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
    475      //
    476      // Try to allocate runtime memory.
    477      //
    478      Status = CoreAllocatePages (
    479                        AllocateAddress,
    480                        EfiRuntimeServicesCode,
    481                        RuntimeCodePageNumber,
    482                        &RuntimeCodeBase
    483                        );
    484      if (EFI_ERROR(Status)) {
    485        //
    486        // Runtime memory allocation failed
    487        //
    488        return;
    489      }
    490      //
    491      // Try to allocate boot memory.
    492      //
    493      Status = CoreAllocatePages (
    494                        AllocateAddress,
    495                        EfiBootServicesCode,
    496                        BootTimeCodePageNumber,
    497                        &BootTimeCodeBase
    498                        );
    499      if (EFI_ERROR(Status)) {
    500        //
    501      	 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
    502      	 // new memory range is installed.
    503      	 //
    504      	 CoreFreePages (
    505               RuntimeCodeBase,
    506               RuntimeCodePageNumber
    507               );
    508        return;
    509      }
    510      gLoadFixedAddressCodeMemoryReady = TRUE;
    511    }
    512    return;
    513 }
    514 
    515 /**
    516   Called to initialize the memory map and add descriptors to
    517   the current descriptor list.
    518   The first descriptor that is added must be general usable
    519   memory as the addition allocates heap.
    520 
    521   @param  Type                   The type of memory to add
    522   @param  Start                  The starting address in the memory range Must be
    523                                  page aligned
    524   @param  NumberOfPages          The number of pages in the range
    525   @param  Attribute              Attributes of the memory to add
    526 
    527   @return None.  The range is added to the memory map
    528 
    529 **/
    530 VOID
    531 CoreAddMemoryDescriptor (
    532   IN EFI_MEMORY_TYPE       Type,
    533   IN EFI_PHYSICAL_ADDRESS  Start,
    534   IN UINT64                NumberOfPages,
    535   IN UINT64                Attribute
    536   )
    537 {
    538   EFI_PHYSICAL_ADDRESS        End;
    539   EFI_STATUS                  Status;
    540   UINTN                       Index;
    541   UINTN                       FreeIndex;
    542 
    543   if ((Start & EFI_PAGE_MASK) != 0) {
    544     return;
    545   }
    546 
    547   if (Type >= EfiMaxMemoryType && Type < MEMORY_TYPE_OEM_RESERVED_MIN) {
    548     return;
    549   }
    550   CoreAcquireMemoryLock ();
    551   End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
    552   CoreAddRange (Type, Start, End, Attribute);
    553   CoreFreeMemoryMapStack ();
    554   CoreReleaseMemoryLock ();
    555 
    556   //
    557   // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
    558   //
    559   if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
    560     CoreLoadingFixedAddressHook();
    561   }
    562 
    563   //
    564   // Check to see if the statistics for the different memory types have already been established
    565   //
    566   if (mMemoryTypeInformationInitialized) {
    567     return;
    568   }
    569 
    570 
    571   //
    572   // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
    573   //
    574   for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
    575     //
    576     // Make sure the memory type in the gMemoryTypeInformation[] array is valid
    577     //
    578     Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
    579     if ((UINT32)Type > EfiMaxMemoryType) {
    580       continue;
    581     }
    582     if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
    583       //
    584       // Allocate pages for the current memory type from the top of available memory
    585       //
    586       Status = CoreAllocatePages (
    587                  AllocateAnyPages,
    588                  Type,
    589                  gMemoryTypeInformation[Index].NumberOfPages,
    590                  &mMemoryTypeStatistics[Type].BaseAddress
    591                  );
    592       if (EFI_ERROR (Status)) {
    593         //
    594         // If an error occurs allocating the pages for the current memory type, then
    595         // free all the pages allocates for the previous memory types and return.  This
    596         // operation with be retied when/if more memory is added to the system
    597         //
    598         for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
    599           //
    600           // Make sure the memory type in the gMemoryTypeInformation[] array is valid
    601           //
    602           Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
    603           if ((UINT32)Type > EfiMaxMemoryType) {
    604             continue;
    605           }
    606 
    607           if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
    608             CoreFreePages (
    609               mMemoryTypeStatistics[Type].BaseAddress,
    610               gMemoryTypeInformation[FreeIndex].NumberOfPages
    611               );
    612             mMemoryTypeStatistics[Type].BaseAddress    = 0;
    613             mMemoryTypeStatistics[Type].MaximumAddress = MAX_ADDRESS;
    614           }
    615         }
    616         return;
    617       }
    618 
    619       //
    620       // Compute the address at the top of the current statistics
    621       //
    622       mMemoryTypeStatistics[Type].MaximumAddress =
    623         mMemoryTypeStatistics[Type].BaseAddress +
    624         LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
    625 
    626       //
    627       // If the current base address is the lowest address so far, then update the default
    628       // maximum address
    629       //
    630       if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
    631         mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
    632       }
    633     }
    634   }
    635 
    636   //
    637   // There was enough system memory for all the the memory types were allocated.  So,
    638   // those memory areas can be freed for future allocations, and all future memory
    639   // allocations can occur within their respective bins
    640   //
    641   for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
    642     //
    643     // Make sure the memory type in the gMemoryTypeInformation[] array is valid
    644     //
    645     Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
    646     if ((UINT32)Type > EfiMaxMemoryType) {
    647       continue;
    648     }
    649     if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
    650       CoreFreePages (
    651         mMemoryTypeStatistics[Type].BaseAddress,
    652         gMemoryTypeInformation[Index].NumberOfPages
    653         );
    654       mMemoryTypeStatistics[Type].NumberOfPages   = gMemoryTypeInformation[Index].NumberOfPages;
    655       gMemoryTypeInformation[Index].NumberOfPages = 0;
    656     }
    657   }
    658 
    659   //
    660   // If the number of pages reserved for a memory type is 0, then all allocations for that type
    661   // should be in the default range.
    662   //
    663   for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
    664     for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
    665       if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
    666         mMemoryTypeStatistics[Type].InformationIndex = Index;
    667       }
    668     }
    669     mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
    670     if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ADDRESS) {
    671       mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
    672     }
    673   }
    674 
    675   mMemoryTypeInformationInitialized = TRUE;
    676 }
    677 
    678 
    679 /**
    680   Internal function.  Converts a memory range to the specified type or attributes.
    681   The range must exist in the memory map.  Either ChangingType or
    682   ChangingAttributes must be set, but not both.
    683 
    684   @param  Start                  The first address of the range Must be page
    685                                  aligned
    686   @param  NumberOfPages          The number of pages to convert
    687   @param  ChangingType           Boolean indicating that type value should be changed
    688   @param  NewType                The new type for the memory range
    689   @param  ChangingAttributes     Boolean indicating that attributes value should be changed
    690   @param  NewAttributes          The new attributes for the memory range
    691 
    692   @retval EFI_INVALID_PARAMETER  Invalid parameter
    693   @retval EFI_NOT_FOUND          Could not find a descriptor cover the specified
    694                                  range  or convertion not allowed.
    695   @retval EFI_SUCCESS            Successfully converts the memory range to the
    696                                  specified type.
    697 
    698 **/
    699 EFI_STATUS
    700 CoreConvertPagesEx (
    701   IN UINT64           Start,
    702   IN UINT64           NumberOfPages,
    703   IN BOOLEAN          ChangingType,
    704   IN EFI_MEMORY_TYPE  NewType,
    705   IN BOOLEAN          ChangingAttributes,
    706   IN UINT64           NewAttributes
    707   )
    708 {
    709 
    710   UINT64          NumberOfBytes;
    711   UINT64          End;
    712   UINT64          RangeEnd;
    713   UINT64          Attribute;
    714   EFI_MEMORY_TYPE MemType;
    715   LIST_ENTRY      *Link;
    716   MEMORY_MAP      *Entry;
    717 
    718   Entry = NULL;
    719   NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
    720   End = Start + NumberOfBytes - 1;
    721 
    722   ASSERT (NumberOfPages);
    723   ASSERT ((Start & EFI_PAGE_MASK) == 0);
    724   ASSERT (End > Start) ;
    725   ASSERT_LOCKED (&gMemoryLock);
    726   ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) );
    727 
    728   if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start > (Start + NumberOfBytes))) {
    729     return EFI_INVALID_PARAMETER;
    730   }
    731 
    732   //
    733   // Convert the entire range
    734   //
    735 
    736   while (Start < End) {
    737 
    738     //
    739     // Find the entry that the covers the range
    740     //
    741     for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
    742       Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
    743 
    744       if (Entry->Start <= Start && Entry->End > Start) {
    745         break;
    746       }
    747     }
    748 
    749     if (Link == &gMemoryMap) {
    750       DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
    751       return EFI_NOT_FOUND;
    752     }
    753 
    754     //
    755     // Convert range to the end, or to the end of the descriptor
    756     // if that's all we've got
    757     //
    758     RangeEnd = End;
    759 
    760     ASSERT (Entry != NULL);
    761     if (Entry->End < End) {
    762       RangeEnd = Entry->End;
    763     }
    764 
    765     if (ChangingType) {
    766       DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
    767     }
    768     if (ChangingAttributes) {
    769       DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
    770     }
    771 
    772     if (ChangingType) {
    773       //
    774       // Debug code - verify conversion is allowed
    775       //
    776       if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
    777         DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types\n"));
    778         return EFI_NOT_FOUND;
    779       }
    780 
    781       //
    782       // Update counters for the number of pages allocated to each memory type
    783       //
    784       if ((UINT32)Entry->Type < EfiMaxMemoryType) {
    785         if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||
    786             (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress)                                                          ) {
    787           if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
    788             mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
    789           } else {
    790             mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
    791           }
    792         }
    793       }
    794 
    795       if ((UINT32)NewType < EfiMaxMemoryType) {
    796         if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||
    797             (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress)                                                  ) {
    798           mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
    799           if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
    800             gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
    801           }
    802         }
    803       }
    804     }
    805 
    806     //
    807     // Pull range out of descriptor
    808     //
    809     if (Entry->Start == Start) {
    810 
    811       //
    812       // Clip start
    813       //
    814       Entry->Start = RangeEnd + 1;
    815 
    816     } else if (Entry->End == RangeEnd) {
    817 
    818       //
    819       // Clip end
    820       //
    821       Entry->End = Start - 1;
    822 
    823     } else {
    824 
    825       //
    826       // Pull it out of the center, clip current
    827       //
    828 
    829       //
    830       // Add a new one
    831       //
    832       mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
    833       mMapStack[mMapDepth].FromPages  = FALSE;
    834       mMapStack[mMapDepth].Type      = Entry->Type;
    835       mMapStack[mMapDepth].Start     = RangeEnd+1;
    836       mMapStack[mMapDepth].End       = Entry->End;
    837 
    838       //
    839       // Inherit Attribute from the Memory Descriptor that is being clipped
    840       //
    841       mMapStack[mMapDepth].Attribute = Entry->Attribute;
    842 
    843       Entry->End = Start - 1;
    844       ASSERT (Entry->Start < Entry->End);
    845 
    846       Entry = &mMapStack[mMapDepth];
    847       InsertTailList (&gMemoryMap, &Entry->Link);
    848 
    849       mMapDepth += 1;
    850       ASSERT (mMapDepth < MAX_MAP_DEPTH);
    851     }
    852 
    853     //
    854     // The new range inherits the same Attribute as the Entry
    855     // it is being cut out of unless attributes are being changed
    856     //
    857     if (ChangingType) {
    858       Attribute = Entry->Attribute;
    859       MemType = NewType;
    860     } else {
    861       Attribute = NewAttributes;
    862       MemType = Entry->Type;
    863     }
    864 
    865     //
    866     // If the descriptor is empty, then remove it from the map
    867     //
    868     if (Entry->Start == Entry->End + 1) {
    869       RemoveMemoryMapEntry (Entry);
    870       Entry = NULL;
    871     }
    872 
    873     //
    874     // Add our new range in
    875     //
    876     CoreAddRange (MemType, Start, RangeEnd, Attribute);
    877     if (ChangingType && (MemType == EfiConventionalMemory)) {
    878       //
    879       // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
    880       // macro will ASSERT() if address is 0.  Instead, CoreAddRange() guarantees
    881       // that the page starting at address 0 is always filled with zeros.
    882       //
    883       if (Start == 0) {
    884         if (RangeEnd > EFI_PAGE_SIZE) {
    885           DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));
    886         }
    887       } else {
    888         DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));
    889       }
    890     }
    891 
    892     //
    893     // Move any map descriptor stack to general pool
    894     //
    895     CoreFreeMemoryMapStack ();
    896 
    897     //
    898     // Bump the starting address, and convert the next range
    899     //
    900     Start = RangeEnd + 1;
    901   }
    902 
    903   //
    904   // Converted the whole range, done
    905   //
    906 
    907   return EFI_SUCCESS;
    908 }
    909 
    910 
    911 /**
    912   Internal function.  Converts a memory range to the specified type.
    913   The range must exist in the memory map.
    914 
    915   @param  Start                  The first address of the range Must be page
    916                                  aligned
    917   @param  NumberOfPages          The number of pages to convert
    918   @param  NewType                The new type for the memory range
    919 
    920   @retval EFI_INVALID_PARAMETER  Invalid parameter
    921   @retval EFI_NOT_FOUND          Could not find a descriptor cover the specified
    922                                  range  or convertion not allowed.
    923   @retval EFI_SUCCESS            Successfully converts the memory range to the
    924                                  specified type.
    925 
    926 **/
    927 EFI_STATUS
    928 CoreConvertPages (
    929   IN UINT64           Start,
    930   IN UINT64           NumberOfPages,
    931   IN EFI_MEMORY_TYPE  NewType
    932   )
    933 {
    934   return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);
    935 }
    936 
    937 
    938 /**
    939   Internal function.  Converts a memory range to use new attributes.
    940 
    941   @param  Start                  The first address of the range Must be page
    942                                  aligned
    943   @param  NumberOfPages          The number of pages to convert
    944   @param  NewAttributes          The new attributes value for the range.
    945 
    946 **/
    947 VOID
    948 CoreUpdateMemoryAttributes (
    949   IN EFI_PHYSICAL_ADDRESS  Start,
    950   IN UINT64                NumberOfPages,
    951   IN UINT64                NewAttributes
    952   )
    953 {
    954   CoreAcquireMemoryLock ();
    955 
    956   //
    957   // Update the attributes to the new value
    958   //
    959   CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
    960 
    961   CoreReleaseMemoryLock ();
    962 }
    963 
    964 
    965 /**
    966   Internal function. Finds a consecutive free page range below
    967   the requested address.
    968 
    969   @param  MaxAddress             The address that the range must be below
    970   @param  MinAddress             The address that the range must be above
    971   @param  NumberOfPages          Number of pages needed
    972   @param  NewType                The type of memory the range is going to be
    973                                  turned into
    974   @param  Alignment              Bits to align with
    975 
    976   @return The base address of the range, or 0 if the range was not found
    977 
    978 **/
    979 UINT64
    980 CoreFindFreePagesI (
    981   IN UINT64           MaxAddress,
    982   IN UINT64           MinAddress,
    983   IN UINT64           NumberOfPages,
    984   IN EFI_MEMORY_TYPE  NewType,
    985   IN UINTN            Alignment
    986   )
    987 {
    988   UINT64          NumberOfBytes;
    989   UINT64          Target;
    990   UINT64          DescStart;
    991   UINT64          DescEnd;
    992   UINT64          DescNumberOfBytes;
    993   LIST_ENTRY      *Link;
    994   MEMORY_MAP      *Entry;
    995 
    996   if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
    997     return 0;
    998   }
    999 
   1000   if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
   1001 
   1002     //
   1003     // If MaxAddress is not aligned to the end of a page
   1004     //
   1005 
   1006     //
   1007     // Change MaxAddress to be 1 page lower
   1008     //
   1009     MaxAddress -= (EFI_PAGE_MASK + 1);
   1010 
   1011     //
   1012     // Set MaxAddress to a page boundary
   1013     //
   1014     MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
   1015 
   1016     //
   1017     // Set MaxAddress to end of the page
   1018     //
   1019     MaxAddress |= EFI_PAGE_MASK;
   1020   }
   1021 
   1022   NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
   1023   Target = 0;
   1024 
   1025   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1026     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
   1027 
   1028     //
   1029     // If it's not a free entry, don't bother with it
   1030     //
   1031     if (Entry->Type != EfiConventionalMemory) {
   1032       continue;
   1033     }
   1034 
   1035     DescStart = Entry->Start;
   1036     DescEnd = Entry->End;
   1037 
   1038     //
   1039     // If desc is past max allowed address or below min allowed address, skip it
   1040     //
   1041     if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
   1042       continue;
   1043     }
   1044 
   1045     //
   1046     // If desc ends past max allowed address, clip the end
   1047     //
   1048     if (DescEnd >= MaxAddress) {
   1049       DescEnd = MaxAddress;
   1050     }
   1051 
   1052     DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
   1053 
   1054     // Skip if DescEnd is less than DescStart after alignment clipping
   1055     if (DescEnd < DescStart) {
   1056       continue;
   1057     }
   1058 
   1059     //
   1060     // Compute the number of bytes we can used from this
   1061     // descriptor, and see it's enough to satisfy the request
   1062     //
   1063     DescNumberOfBytes = DescEnd - DescStart + 1;
   1064 
   1065     if (DescNumberOfBytes >= NumberOfBytes) {
   1066       //
   1067       // If the start of the allocated range is below the min address allowed, skip it
   1068       //
   1069       if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
   1070         continue;
   1071       }
   1072 
   1073       //
   1074       // If this is the best match so far remember it
   1075       //
   1076       if (DescEnd > Target) {
   1077         Target = DescEnd;
   1078       }
   1079     }
   1080   }
   1081 
   1082   //
   1083   // If this is a grow down, adjust target to be the allocation base
   1084   //
   1085   Target -= NumberOfBytes - 1;
   1086 
   1087   //
   1088   // If we didn't find a match, return 0
   1089   //
   1090   if ((Target & EFI_PAGE_MASK) != 0) {
   1091     return 0;
   1092   }
   1093 
   1094   return Target;
   1095 }
   1096 
   1097 
   1098 /**
   1099   Internal function.  Finds a consecutive free page range below
   1100   the requested address
   1101 
   1102   @param  MaxAddress             The address that the range must be below
   1103   @param  NoPages                Number of pages needed
   1104   @param  NewType                The type of memory the range is going to be
   1105                                  turned into
   1106   @param  Alignment              Bits to align with
   1107 
   1108   @return The base address of the range, or 0 if the range was not found.
   1109 
   1110 **/
   1111 UINT64
   1112 FindFreePages (
   1113     IN UINT64           MaxAddress,
   1114     IN UINT64           NoPages,
   1115     IN EFI_MEMORY_TYPE  NewType,
   1116     IN UINTN            Alignment
   1117     )
   1118 {
   1119   UINT64   Start;
   1120 
   1121   //
   1122   // Attempt to find free pages in the preferred bin based on the requested memory type
   1123   //
   1124   if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
   1125     Start = CoreFindFreePagesI (
   1126               mMemoryTypeStatistics[NewType].MaximumAddress,
   1127               mMemoryTypeStatistics[NewType].BaseAddress,
   1128               NoPages,
   1129               NewType,
   1130               Alignment
   1131               );
   1132     if (Start != 0) {
   1133       return Start;
   1134     }
   1135   }
   1136 
   1137   //
   1138   // Attempt to find free pages in the default allocation bin
   1139   //
   1140   if (MaxAddress >= mDefaultMaximumAddress) {
   1141     Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType, Alignment);
   1142     if (Start != 0) {
   1143       if (Start < mDefaultBaseAddress) {
   1144         mDefaultBaseAddress = Start;
   1145       }
   1146       return Start;
   1147     }
   1148   }
   1149 
   1150   //
   1151   // The allocation did not succeed in any of the prefered bins even after
   1152   // promoting resources. Attempt to find free pages anywhere is the requested
   1153   // address range.  If this allocation fails, then there are not enough
   1154   // resources anywhere to satisfy the request.
   1155   //
   1156   Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment);
   1157   if (Start != 0) {
   1158     return Start;
   1159   }
   1160 
   1161   //
   1162   // If allocations from the preferred bins fail, then attempt to promote memory resources.
   1163   //
   1164   if (!PromoteMemoryResource ()) {
   1165     return 0;
   1166   }
   1167 
   1168   //
   1169   // If any memory resources were promoted, then re-attempt the allocation
   1170   //
   1171   return FindFreePages (MaxAddress, NoPages, NewType, Alignment);
   1172 }
   1173 
   1174 
   1175 /**
   1176   Allocates pages from the memory map.
   1177 
   1178   @param  Type                   The type of allocation to perform
   1179   @param  MemoryType             The type of memory to turn the allocated pages
   1180                                  into
   1181   @param  NumberOfPages          The number of pages to allocate
   1182   @param  Memory                 A pointer to receive the base allocated memory
   1183                                  address
   1184 
   1185   @return Status. On success, Memory is filled in with the base address allocated
   1186   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in
   1187                                  spec.
   1188   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
   1189   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
   1190   @retval EFI_SUCCESS            Pages successfully allocated.
   1191 
   1192 **/
   1193 EFI_STATUS
   1194 EFIAPI
   1195 CoreInternalAllocatePages (
   1196   IN EFI_ALLOCATE_TYPE      Type,
   1197   IN EFI_MEMORY_TYPE        MemoryType,
   1198   IN UINTN                  NumberOfPages,
   1199   IN OUT EFI_PHYSICAL_ADDRESS  *Memory
   1200   )
   1201 {
   1202   EFI_STATUS      Status;
   1203   UINT64          Start;
   1204   UINT64          MaxAddress;
   1205   UINTN           Alignment;
   1206 
   1207   if ((UINT32)Type >= MaxAllocateType) {
   1208     return EFI_INVALID_PARAMETER;
   1209   }
   1210 
   1211   if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
   1212        (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
   1213     return EFI_INVALID_PARAMETER;
   1214   }
   1215 
   1216   if (Memory == NULL) {
   1217     return EFI_INVALID_PARAMETER;
   1218   }
   1219 
   1220   Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
   1221 
   1222   if  (MemoryType == EfiACPIReclaimMemory   ||
   1223        MemoryType == EfiACPIMemoryNVS       ||
   1224        MemoryType == EfiRuntimeServicesCode ||
   1225        MemoryType == EfiRuntimeServicesData) {
   1226 
   1227     Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
   1228   }
   1229 
   1230   if (Type == AllocateAddress) {
   1231     if ((*Memory & (Alignment - 1)) != 0) {
   1232       return EFI_NOT_FOUND;
   1233     }
   1234   }
   1235 
   1236   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
   1237   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
   1238 
   1239   //
   1240   // If this is for below a particular address, then
   1241   //
   1242   Start = *Memory;
   1243 
   1244   //
   1245   // The max address is the max natively addressable address for the processor
   1246   //
   1247   MaxAddress = MAX_ADDRESS;
   1248 
   1249   if (Type == AllocateMaxAddress) {
   1250     MaxAddress = Start;
   1251   }
   1252 
   1253   CoreAcquireMemoryLock ();
   1254 
   1255   //
   1256   // If not a specific address, then find an address to allocate
   1257   //
   1258   if (Type != AllocateAddress) {
   1259     Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
   1260     if (Start == 0) {
   1261       Status = EFI_OUT_OF_RESOURCES;
   1262       goto Done;
   1263     }
   1264   }
   1265 
   1266   //
   1267   // Convert pages from FreeMemory to the requested type
   1268   //
   1269   Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
   1270 
   1271 Done:
   1272   CoreReleaseMemoryLock ();
   1273 
   1274   if (!EFI_ERROR (Status)) {
   1275     *Memory = Start;
   1276   }
   1277 
   1278   return Status;
   1279 }
   1280 
   1281 /**
   1282   Allocates pages from the memory map.
   1283 
   1284   @param  Type                   The type of allocation to perform
   1285   @param  MemoryType             The type of memory to turn the allocated pages
   1286                                  into
   1287   @param  NumberOfPages          The number of pages to allocate
   1288   @param  Memory                 A pointer to receive the base allocated memory
   1289                                  address
   1290 
   1291   @return Status. On success, Memory is filled in with the base address allocated
   1292   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in
   1293                                  spec.
   1294   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
   1295   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
   1296   @retval EFI_SUCCESS            Pages successfully allocated.
   1297 
   1298 **/
   1299 EFI_STATUS
   1300 EFIAPI
   1301 CoreAllocatePages (
   1302   IN  EFI_ALLOCATE_TYPE     Type,
   1303   IN  EFI_MEMORY_TYPE       MemoryType,
   1304   IN  UINTN                 NumberOfPages,
   1305   OUT EFI_PHYSICAL_ADDRESS  *Memory
   1306   )
   1307 {
   1308   EFI_STATUS  Status;
   1309 
   1310   Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
   1311   if (!EFI_ERROR (Status)) {
   1312     CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages, MemoryType, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) *Memory);
   1313   }
   1314   return Status;
   1315 }
   1316 
   1317 /**
   1318   Frees previous allocated pages.
   1319 
   1320   @param  Memory                 Base address of memory being freed
   1321   @param  NumberOfPages          The number of pages to free
   1322 
   1323   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
   1324   @retval EFI_INVALID_PARAMETER  Address not aligned
   1325   @return EFI_SUCCESS         -Pages successfully freed.
   1326 
   1327 **/
   1328 EFI_STATUS
   1329 EFIAPI
   1330 CoreInternalFreePages (
   1331   IN EFI_PHYSICAL_ADDRESS   Memory,
   1332   IN UINTN                  NumberOfPages
   1333   )
   1334 {
   1335   EFI_STATUS      Status;
   1336   LIST_ENTRY      *Link;
   1337   MEMORY_MAP      *Entry;
   1338   UINTN           Alignment;
   1339 
   1340   //
   1341   // Free the range
   1342   //
   1343   CoreAcquireMemoryLock ();
   1344 
   1345   //
   1346   // Find the entry that the covers the range
   1347   //
   1348   Entry = NULL;
   1349   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1350     Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
   1351     if (Entry->Start <= Memory && Entry->End > Memory) {
   1352         break;
   1353     }
   1354   }
   1355   if (Link == &gMemoryMap) {
   1356     Status = EFI_NOT_FOUND;
   1357     goto Done;
   1358   }
   1359 
   1360   Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
   1361 
   1362   ASSERT (Entry != NULL);
   1363   if  (Entry->Type == EfiACPIReclaimMemory   ||
   1364        Entry->Type == EfiACPIMemoryNVS       ||
   1365        Entry->Type == EfiRuntimeServicesCode ||
   1366        Entry->Type == EfiRuntimeServicesData) {
   1367 
   1368     Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
   1369 
   1370   }
   1371 
   1372   if ((Memory & (Alignment - 1)) != 0) {
   1373     Status = EFI_INVALID_PARAMETER;
   1374     goto Done;
   1375   }
   1376 
   1377   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
   1378   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
   1379 
   1380   Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
   1381 
   1382   if (EFI_ERROR (Status)) {
   1383     goto Done;
   1384   }
   1385 
   1386 Done:
   1387   CoreReleaseMemoryLock ();
   1388   return Status;
   1389 }
   1390 
   1391 /**
   1392   Frees previous allocated pages.
   1393 
   1394   @param  Memory                 Base address of memory being freed
   1395   @param  NumberOfPages          The number of pages to free
   1396 
   1397   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
   1398   @retval EFI_INVALID_PARAMETER  Address not aligned
   1399   @return EFI_SUCCESS         -Pages successfully freed.
   1400 
   1401 **/
   1402 EFI_STATUS
   1403 EFIAPI
   1404 CoreFreePages (
   1405   IN EFI_PHYSICAL_ADDRESS  Memory,
   1406   IN UINTN                 NumberOfPages
   1407   )
   1408 {
   1409   EFI_STATUS  Status;
   1410 
   1411   Status = CoreInternalFreePages (Memory, NumberOfPages);
   1412   if (!EFI_ERROR (Status)) {
   1413     CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePages, (EFI_MEMORY_TYPE) 0, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) Memory);
   1414   }
   1415   return Status;
   1416 }
   1417 
   1418 /**
   1419   This function checks to see if the last memory map descriptor in a memory map
   1420   can be merged with any of the other memory map descriptors in a memorymap.
   1421   Memory descriptors may be merged if they are adjacent and have the same type
   1422   and attributes.
   1423 
   1424   @param  MemoryMap              A pointer to the start of the memory map.
   1425   @param  MemoryMapDescriptor    A pointer to the last descriptor in MemoryMap.
   1426   @param  DescriptorSize         The size, in bytes, of an individual
   1427                                  EFI_MEMORY_DESCRIPTOR.
   1428 
   1429   @return  A pointer to the next available descriptor in MemoryMap
   1430 
   1431 **/
   1432 EFI_MEMORY_DESCRIPTOR *
   1433 MergeMemoryMapDescriptor (
   1434   IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,
   1435   IN EFI_MEMORY_DESCRIPTOR  *MemoryMapDescriptor,
   1436   IN UINTN                  DescriptorSize
   1437   )
   1438 {
   1439   //
   1440   // Traverse the array of descriptors in MemoryMap
   1441   //
   1442   for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
   1443     //
   1444     // Check to see if the Type fields are identical.
   1445     //
   1446     if (MemoryMap->Type != MemoryMapDescriptor->Type) {
   1447       continue;
   1448     }
   1449 
   1450     //
   1451     // Check to see if the Attribute fields are identical.
   1452     //
   1453     if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
   1454       continue;
   1455     }
   1456 
   1457     //
   1458     // Check to see if MemoryMapDescriptor is immediately above MemoryMap
   1459     //
   1460     if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
   1461       //
   1462       // Merge MemoryMapDescriptor into MemoryMap
   1463       //
   1464       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
   1465 
   1466       //
   1467       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
   1468       //
   1469       return MemoryMapDescriptor;
   1470     }
   1471 
   1472     //
   1473     // Check to see if MemoryMapDescriptor is immediately below MemoryMap
   1474     //
   1475     if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
   1476       //
   1477       // Merge MemoryMapDescriptor into MemoryMap
   1478       //
   1479       MemoryMap->PhysicalStart  = MemoryMapDescriptor->PhysicalStart;
   1480       MemoryMap->VirtualStart   = MemoryMapDescriptor->VirtualStart;
   1481       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
   1482 
   1483       //
   1484       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
   1485       //
   1486       return MemoryMapDescriptor;
   1487     }
   1488   }
   1489 
   1490   //
   1491   // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
   1492   //
   1493   // Return the slot immediately after MemoryMapDescriptor as the next available
   1494   // slot in the MemoryMap array
   1495   //
   1496   return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
   1497 }
   1498 
   1499 /**
   1500   This function returns a copy of the current memory map. The map is an array of
   1501   memory descriptors, each of which describes a contiguous block of memory.
   1502 
   1503   @param  MemoryMapSize          A pointer to the size, in bytes, of the
   1504                                  MemoryMap buffer. On input, this is the size of
   1505                                  the buffer allocated by the caller.  On output,
   1506                                  it is the size of the buffer returned by the
   1507                                  firmware  if the buffer was large enough, or the
   1508                                  size of the buffer needed  to contain the map if
   1509                                  the buffer was too small.
   1510   @param  MemoryMap              A pointer to the buffer in which firmware places
   1511                                  the current memory map.
   1512   @param  MapKey                 A pointer to the location in which firmware
   1513                                  returns the key for the current memory map.
   1514   @param  DescriptorSize         A pointer to the location in which firmware
   1515                                  returns the size, in bytes, of an individual
   1516                                  EFI_MEMORY_DESCRIPTOR.
   1517   @param  DescriptorVersion      A pointer to the location in which firmware
   1518                                  returns the version number associated with the
   1519                                  EFI_MEMORY_DESCRIPTOR.
   1520 
   1521   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
   1522                                  buffer.
   1523   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
   1524                                  buffer size needed to hold the memory map is
   1525                                  returned in MemoryMapSize.
   1526   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
   1527 
   1528 **/
   1529 EFI_STATUS
   1530 EFIAPI
   1531 CoreGetMemoryMap (
   1532   IN OUT UINTN                  *MemoryMapSize,
   1533   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
   1534   OUT UINTN                     *MapKey,
   1535   OUT UINTN                     *DescriptorSize,
   1536   OUT UINT32                    *DescriptorVersion
   1537   )
   1538 {
   1539   EFI_STATUS                        Status;
   1540   UINTN                             Size;
   1541   UINTN                             BufferSize;
   1542   UINTN                             NumberOfEntries;
   1543   LIST_ENTRY                        *Link;
   1544   MEMORY_MAP                        *Entry;
   1545   EFI_GCD_MAP_ENTRY                 *GcdMapEntry;
   1546   EFI_GCD_MAP_ENTRY                 MergeGcdMapEntry;
   1547   EFI_MEMORY_TYPE                   Type;
   1548   EFI_MEMORY_DESCRIPTOR             *MemoryMapStart;
   1549 
   1550   //
   1551   // Make sure the parameters are valid
   1552   //
   1553   if (MemoryMapSize == NULL) {
   1554     return EFI_INVALID_PARAMETER;
   1555   }
   1556 
   1557   CoreAcquireGcdMemoryLock ();
   1558 
   1559   //
   1560   // Count the number of Reserved and runtime MMIO entries
   1561   // And, count the number of Persistent entries.
   1562   //
   1563   NumberOfEntries = 0;
   1564   for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
   1565     GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1566     if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) ||
   1567         (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
   1568         ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
   1569         ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
   1570       NumberOfEntries ++;
   1571     }
   1572   }
   1573 
   1574   Size = sizeof (EFI_MEMORY_DESCRIPTOR);
   1575 
   1576   //
   1577   // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
   1578   // prevent people from having pointer math bugs in their code.
   1579   // now you have to use *DescriptorSize to make things work.
   1580   //
   1581   Size += sizeof(UINT64) - (Size % sizeof (UINT64));
   1582 
   1583   if (DescriptorSize != NULL) {
   1584     *DescriptorSize = Size;
   1585   }
   1586 
   1587   if (DescriptorVersion != NULL) {
   1588     *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
   1589   }
   1590 
   1591   CoreAcquireMemoryLock ();
   1592 
   1593   //
   1594   // Compute the buffer size needed to fit the entire map
   1595   //
   1596   BufferSize = Size * NumberOfEntries;
   1597   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1598     BufferSize += Size;
   1599   }
   1600 
   1601   if (*MemoryMapSize < BufferSize) {
   1602     Status = EFI_BUFFER_TOO_SMALL;
   1603     goto Done;
   1604   }
   1605 
   1606   if (MemoryMap == NULL) {
   1607     Status = EFI_INVALID_PARAMETER;
   1608     goto Done;
   1609   }
   1610 
   1611   //
   1612   // Build the map
   1613   //
   1614   ZeroMem (MemoryMap, BufferSize);
   1615   MemoryMapStart = MemoryMap;
   1616   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1617     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
   1618     ASSERT (Entry->VirtualStart == 0);
   1619 
   1620     //
   1621     // Convert internal map into an EFI_MEMORY_DESCRIPTOR
   1622     //
   1623     MemoryMap->Type           = Entry->Type;
   1624     MemoryMap->PhysicalStart  = Entry->Start;
   1625     MemoryMap->VirtualStart   = Entry->VirtualStart;
   1626     MemoryMap->NumberOfPages  = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
   1627     //
   1628     // If the memory type is EfiConventionalMemory, then determine if the range is part of a
   1629     // memory type bin and needs to be converted to the same memory type as the rest of the
   1630     // memory type bin in order to minimize EFI Memory Map changes across reboots.  This
   1631     // improves the chances for a successful S4 resume in the presence of minor page allocation
   1632     // differences across reboots.
   1633     //
   1634     if (MemoryMap->Type == EfiConventionalMemory) {
   1635       for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
   1636         if (mMemoryTypeStatistics[Type].Special                        &&
   1637             mMemoryTypeStatistics[Type].NumberOfPages > 0              &&
   1638             Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress    &&
   1639             Entry->End   <= mMemoryTypeStatistics[Type].MaximumAddress) {
   1640           MemoryMap->Type = Type;
   1641         }
   1642       }
   1643     }
   1644     MemoryMap->Attribute = Entry->Attribute;
   1645     if (MemoryMap->Type < EfiMaxMemoryType) {
   1646       if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
   1647         MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
   1648       }
   1649     }
   1650 
   1651     //
   1652     // Check to see if the new Memory Map Descriptor can be merged with an
   1653     // existing descriptor if they are adjacent and have the same attributes
   1654     //
   1655     MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
   1656   }
   1657 
   1658 
   1659   ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
   1660   GcdMapEntry = NULL;
   1661   for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
   1662     if (Link != &mGcdMemorySpaceMap) {
   1663       //
   1664       // Merge adjacent same type and attribute GCD memory range
   1665       //
   1666       GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1667 
   1668       if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
   1669           (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
   1670           (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
   1671           (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
   1672         MergeGcdMapEntry.EndAddress  = GcdMapEntry->EndAddress;
   1673         continue;
   1674       }
   1675     }
   1676 
   1677     if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
   1678         ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
   1679         ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
   1680       //
   1681       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
   1682       // it will be recorded as page PhysicalStart and NumberOfPages.
   1683       //
   1684       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
   1685       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
   1686 
   1687       //
   1688       // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
   1689       //
   1690       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
   1691       MemoryMap->VirtualStart  = 0;
   1692       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
   1693       MemoryMap->Attribute     = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
   1694                                 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
   1695                                 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
   1696 
   1697       if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
   1698         MemoryMap->Type = EfiReservedMemoryType;
   1699       } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
   1700         if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
   1701           MemoryMap->Type = EfiMemoryMappedIOPortSpace;
   1702         } else {
   1703           MemoryMap->Type = EfiMemoryMappedIO;
   1704         }
   1705       }
   1706 
   1707       //
   1708       // Check to see if the new Memory Map Descriptor can be merged with an
   1709       // existing descriptor if they are adjacent and have the same attributes
   1710       //
   1711       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
   1712     }
   1713 
   1714     if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistentMemory) {
   1715       //
   1716       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
   1717       // it will be recorded as page PhysicalStart and NumberOfPages.
   1718       //
   1719       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
   1720       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
   1721 
   1722       //
   1723       // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
   1724       //
   1725       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
   1726       MemoryMap->VirtualStart  = 0;
   1727       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
   1728       MemoryMap->Attribute     = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
   1729                                 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
   1730                                 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
   1731       MemoryMap->Type          = EfiPersistentMemory;
   1732 
   1733       //
   1734       // Check to see if the new Memory Map Descriptor can be merged with an
   1735       // existing descriptor if they are adjacent and have the same attributes
   1736       //
   1737       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
   1738     }
   1739     if (Link == &mGcdMemorySpaceMap) {
   1740       //
   1741       // break loop when arrive at head.
   1742       //
   1743       break;
   1744     }
   1745     if (GcdMapEntry != NULL) {
   1746       //
   1747       // Copy new GCD map entry for the following GCD range merge
   1748       //
   1749       CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
   1750     }
   1751   }
   1752 
   1753   //
   1754   // Compute the size of the buffer actually used after all memory map descriptor merge operations
   1755   //
   1756   BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
   1757 
   1758   Status = EFI_SUCCESS;
   1759 
   1760 Done:
   1761   //
   1762   // Update the map key finally
   1763   //
   1764   if (MapKey != NULL) {
   1765     *MapKey = mMemoryMapKey;
   1766   }
   1767 
   1768   CoreReleaseMemoryLock ();
   1769 
   1770   CoreReleaseGcdMemoryLock ();
   1771 
   1772   *MemoryMapSize = BufferSize;
   1773 
   1774   return Status;
   1775 }
   1776 
   1777 
   1778 /**
   1779   Internal function.  Used by the pool functions to allocate pages
   1780   to back pool allocation requests.
   1781 
   1782   @param  PoolType               The type of memory for the new pool pages
   1783   @param  NumberOfPages          No of pages to allocate
   1784   @param  Alignment              Bits to align.
   1785 
   1786   @return The allocated memory, or NULL
   1787 
   1788 **/
   1789 VOID *
   1790 CoreAllocatePoolPages (
   1791   IN EFI_MEMORY_TYPE    PoolType,
   1792   IN UINTN              NumberOfPages,
   1793   IN UINTN              Alignment
   1794   )
   1795 {
   1796   UINT64            Start;
   1797 
   1798   //
   1799   // Find the pages to convert
   1800   //
   1801   Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
   1802 
   1803   //
   1804   // Convert it to boot services data
   1805   //
   1806   if (Start == 0) {
   1807     DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
   1808   } else {
   1809     CoreConvertPages (Start, NumberOfPages, PoolType);
   1810   }
   1811 
   1812   return (VOID *)(UINTN) Start;
   1813 }
   1814 
   1815 
   1816 /**
   1817   Internal function.  Frees pool pages allocated via AllocatePoolPages ()
   1818 
   1819   @param  Memory                 The base address to free
   1820   @param  NumberOfPages          The number of pages to free
   1821 
   1822 **/
   1823 VOID
   1824 CoreFreePoolPages (
   1825   IN EFI_PHYSICAL_ADDRESS   Memory,
   1826   IN UINTN                  NumberOfPages
   1827   )
   1828 {
   1829   CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
   1830 }
   1831 
   1832 
   1833 
   1834 /**
   1835   Make sure the memory map is following all the construction rules,
   1836   it is the last time to check memory map error before exit boot services.
   1837 
   1838   @param  MapKey                 Memory map key
   1839 
   1840   @retval EFI_INVALID_PARAMETER  Memory map not consistent with construction
   1841                                  rules.
   1842   @retval EFI_SUCCESS            Valid memory map.
   1843 
   1844 **/
   1845 EFI_STATUS
   1846 CoreTerminateMemoryMap (
   1847   IN UINTN          MapKey
   1848   )
   1849 {
   1850   EFI_STATUS        Status;
   1851   LIST_ENTRY        *Link;
   1852   MEMORY_MAP        *Entry;
   1853 
   1854   Status = EFI_SUCCESS;
   1855 
   1856   CoreAcquireMemoryLock ();
   1857 
   1858   if (MapKey == mMemoryMapKey) {
   1859 
   1860     //
   1861     // Make sure the memory map is following all the construction rules
   1862     // This is the last chance we will be able to display any messages on
   1863     // the  console devices.
   1864     //
   1865 
   1866     for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1867       Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
   1868       if (Entry->Type < EfiMaxMemoryType) {
   1869         if (mMemoryTypeStatistics[Entry->Type].Runtime) {
   1870           ASSERT (Entry->Type != EfiACPIReclaimMemory);
   1871           ASSERT (Entry->Type != EfiACPIMemoryNVS);
   1872           if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
   1873             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
   1874             Status =  EFI_INVALID_PARAMETER;
   1875             goto Done;
   1876           }
   1877           if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
   1878             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
   1879             Status =  EFI_INVALID_PARAMETER;
   1880             goto Done;
   1881           }
   1882         }
   1883       }
   1884     }
   1885 
   1886     //
   1887     // The map key they gave us matches what we expect. Fall through and
   1888     // return success. In an ideal world we would clear out all of
   1889     // EfiBootServicesCode and EfiBootServicesData. However this function
   1890     // is not the last one called by ExitBootServices(), so we have to
   1891     // preserve the memory contents.
   1892     //
   1893   } else {
   1894     Status = EFI_INVALID_PARAMETER;
   1895   }
   1896 
   1897 Done:
   1898   CoreReleaseMemoryLock ();
   1899 
   1900   return Status;
   1901 }
   1902 
   1903 
   1904 
   1905 
   1906 
   1907 
   1908 
   1909 
   1910 
   1911