Home | History | Annotate | Download | only in Mem
      1 /** @file
      2   UEFI Memory page management functions.
      3 
      4 Copyright (c) 2007 - 2016, 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 function
    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 >= End)) {
    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          NumberOfBytes;
   1205   UINT64          End;
   1206   UINT64          MaxAddress;
   1207   UINTN           Alignment;
   1208 
   1209   if ((UINT32)Type >= MaxAllocateType) {
   1210     return EFI_INVALID_PARAMETER;
   1211   }
   1212 
   1213   if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
   1214        (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
   1215     return EFI_INVALID_PARAMETER;
   1216   }
   1217 
   1218   if (Memory == NULL) {
   1219     return EFI_INVALID_PARAMETER;
   1220   }
   1221 
   1222   Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
   1223 
   1224   if  (MemoryType == EfiACPIReclaimMemory   ||
   1225        MemoryType == EfiACPIMemoryNVS       ||
   1226        MemoryType == EfiRuntimeServicesCode ||
   1227        MemoryType == EfiRuntimeServicesData) {
   1228 
   1229     Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
   1230   }
   1231 
   1232   if (Type == AllocateAddress) {
   1233     if ((*Memory & (Alignment - 1)) != 0) {
   1234       return EFI_NOT_FOUND;
   1235     }
   1236   }
   1237 
   1238   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
   1239   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
   1240 
   1241   //
   1242   // If this is for below a particular address, then
   1243   //
   1244   Start = *Memory;
   1245 
   1246   //
   1247   // The max address is the max natively addressable address for the processor
   1248   //
   1249   MaxAddress = MAX_ADDRESS;
   1250 
   1251   //
   1252   // Check for Type AllocateAddress,
   1253   // if NumberOfPages is 0 or
   1254   // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ADDRESS or
   1255   // if (Start + NumberOfBytes) rolls over 0 or
   1256   // if Start is above MAX_ADDRESS or
   1257   // if End is above MAX_ADDRESS,
   1258   // return EFI_NOT_FOUND.
   1259   //
   1260   if (Type == AllocateAddress) {
   1261     if ((NumberOfPages == 0) ||
   1262         (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {
   1263       return EFI_NOT_FOUND;
   1264     }
   1265     NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
   1266     End = Start + NumberOfBytes - 1;
   1267 
   1268     if ((Start >= End) ||
   1269         (Start > MaxAddress) ||
   1270         (End > MaxAddress)) {
   1271       return EFI_NOT_FOUND;
   1272     }
   1273   }
   1274 
   1275   if (Type == AllocateMaxAddress) {
   1276     MaxAddress = Start;
   1277   }
   1278 
   1279   CoreAcquireMemoryLock ();
   1280 
   1281   //
   1282   // If not a specific address, then find an address to allocate
   1283   //
   1284   if (Type != AllocateAddress) {
   1285     Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
   1286     if (Start == 0) {
   1287       Status = EFI_OUT_OF_RESOURCES;
   1288       goto Done;
   1289     }
   1290   }
   1291 
   1292   //
   1293   // Convert pages from FreeMemory to the requested type
   1294   //
   1295   Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
   1296 
   1297 Done:
   1298   CoreReleaseMemoryLock ();
   1299 
   1300   if (!EFI_ERROR (Status)) {
   1301     *Memory = Start;
   1302   }
   1303 
   1304   return Status;
   1305 }
   1306 
   1307 /**
   1308   Allocates pages from the memory map.
   1309 
   1310   @param  Type                   The type of allocation to perform
   1311   @param  MemoryType             The type of memory to turn the allocated pages
   1312                                  into
   1313   @param  NumberOfPages          The number of pages to allocate
   1314   @param  Memory                 A pointer to receive the base allocated memory
   1315                                  address
   1316 
   1317   @return Status. On success, Memory is filled in with the base address allocated
   1318   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in
   1319                                  spec.
   1320   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
   1321   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
   1322   @retval EFI_SUCCESS            Pages successfully allocated.
   1323 
   1324 **/
   1325 EFI_STATUS
   1326 EFIAPI
   1327 CoreAllocatePages (
   1328   IN  EFI_ALLOCATE_TYPE     Type,
   1329   IN  EFI_MEMORY_TYPE       MemoryType,
   1330   IN  UINTN                 NumberOfPages,
   1331   OUT EFI_PHYSICAL_ADDRESS  *Memory
   1332   )
   1333 {
   1334   EFI_STATUS  Status;
   1335 
   1336   Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
   1337   if (!EFI_ERROR (Status)) {
   1338     CoreUpdateProfile (
   1339       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
   1340       MemoryProfileActionAllocatePages,
   1341       MemoryType,
   1342       EFI_PAGES_TO_SIZE (NumberOfPages),
   1343       (VOID *) (UINTN) *Memory,
   1344       NULL
   1345       );
   1346     InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
   1347   }
   1348   return Status;
   1349 }
   1350 
   1351 /**
   1352   Frees previous allocated pages.
   1353 
   1354   @param  Memory                 Base address of memory being freed
   1355   @param  NumberOfPages          The number of pages to free
   1356   @param  MemoryType             Pointer to memory type
   1357 
   1358   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
   1359   @retval EFI_INVALID_PARAMETER  Address not aligned
   1360   @return EFI_SUCCESS         -Pages successfully freed.
   1361 
   1362 **/
   1363 EFI_STATUS
   1364 EFIAPI
   1365 CoreInternalFreePages (
   1366   IN EFI_PHYSICAL_ADDRESS   Memory,
   1367   IN UINTN                  NumberOfPages,
   1368   OUT EFI_MEMORY_TYPE       *MemoryType OPTIONAL
   1369   )
   1370 {
   1371   EFI_STATUS      Status;
   1372   LIST_ENTRY      *Link;
   1373   MEMORY_MAP      *Entry;
   1374   UINTN           Alignment;
   1375 
   1376   //
   1377   // Free the range
   1378   //
   1379   CoreAcquireMemoryLock ();
   1380 
   1381   //
   1382   // Find the entry that the covers the range
   1383   //
   1384   Entry = NULL;
   1385   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1386     Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
   1387     if (Entry->Start <= Memory && Entry->End > Memory) {
   1388         break;
   1389     }
   1390   }
   1391   if (Link == &gMemoryMap) {
   1392     Status = EFI_NOT_FOUND;
   1393     goto Done;
   1394   }
   1395 
   1396   Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
   1397 
   1398   ASSERT (Entry != NULL);
   1399   if  (Entry->Type == EfiACPIReclaimMemory   ||
   1400        Entry->Type == EfiACPIMemoryNVS       ||
   1401        Entry->Type == EfiRuntimeServicesCode ||
   1402        Entry->Type == EfiRuntimeServicesData) {
   1403 
   1404     Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
   1405 
   1406   }
   1407 
   1408   if ((Memory & (Alignment - 1)) != 0) {
   1409     Status = EFI_INVALID_PARAMETER;
   1410     goto Done;
   1411   }
   1412 
   1413   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
   1414   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
   1415 
   1416   if (MemoryType != NULL) {
   1417     *MemoryType = Entry->Type;
   1418   }
   1419 
   1420   Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
   1421 
   1422   if (EFI_ERROR (Status)) {
   1423     goto Done;
   1424   }
   1425 
   1426 Done:
   1427   CoreReleaseMemoryLock ();
   1428   return Status;
   1429 }
   1430 
   1431 /**
   1432   Frees previous allocated pages.
   1433 
   1434   @param  Memory                 Base address of memory being freed
   1435   @param  NumberOfPages          The number of pages to free
   1436 
   1437   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
   1438   @retval EFI_INVALID_PARAMETER  Address not aligned
   1439   @return EFI_SUCCESS         -Pages successfully freed.
   1440 
   1441 **/
   1442 EFI_STATUS
   1443 EFIAPI
   1444 CoreFreePages (
   1445   IN EFI_PHYSICAL_ADDRESS  Memory,
   1446   IN UINTN                 NumberOfPages
   1447   )
   1448 {
   1449   EFI_STATUS        Status;
   1450   EFI_MEMORY_TYPE   MemoryType;
   1451 
   1452   Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
   1453   if (!EFI_ERROR (Status)) {
   1454     CoreUpdateProfile (
   1455       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
   1456       MemoryProfileActionFreePages,
   1457       MemoryType,
   1458       EFI_PAGES_TO_SIZE (NumberOfPages),
   1459       (VOID *) (UINTN) Memory,
   1460       NULL
   1461       );
   1462     InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
   1463   }
   1464   return Status;
   1465 }
   1466 
   1467 /**
   1468   This function checks to see if the last memory map descriptor in a memory map
   1469   can be merged with any of the other memory map descriptors in a memorymap.
   1470   Memory descriptors may be merged if they are adjacent and have the same type
   1471   and attributes.
   1472 
   1473   @param  MemoryMap              A pointer to the start of the memory map.
   1474   @param  MemoryMapDescriptor    A pointer to the last descriptor in MemoryMap.
   1475   @param  DescriptorSize         The size, in bytes, of an individual
   1476                                  EFI_MEMORY_DESCRIPTOR.
   1477 
   1478   @return  A pointer to the next available descriptor in MemoryMap
   1479 
   1480 **/
   1481 EFI_MEMORY_DESCRIPTOR *
   1482 MergeMemoryMapDescriptor (
   1483   IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,
   1484   IN EFI_MEMORY_DESCRIPTOR  *MemoryMapDescriptor,
   1485   IN UINTN                  DescriptorSize
   1486   )
   1487 {
   1488   //
   1489   // Traverse the array of descriptors in MemoryMap
   1490   //
   1491   for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
   1492     //
   1493     // Check to see if the Type fields are identical.
   1494     //
   1495     if (MemoryMap->Type != MemoryMapDescriptor->Type) {
   1496       continue;
   1497     }
   1498 
   1499     //
   1500     // Check to see if the Attribute fields are identical.
   1501     //
   1502     if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
   1503       continue;
   1504     }
   1505 
   1506     //
   1507     // Check to see if MemoryMapDescriptor is immediately above MemoryMap
   1508     //
   1509     if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
   1510       //
   1511       // Merge MemoryMapDescriptor into MemoryMap
   1512       //
   1513       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
   1514 
   1515       //
   1516       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
   1517       //
   1518       return MemoryMapDescriptor;
   1519     }
   1520 
   1521     //
   1522     // Check to see if MemoryMapDescriptor is immediately below MemoryMap
   1523     //
   1524     if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
   1525       //
   1526       // Merge MemoryMapDescriptor into MemoryMap
   1527       //
   1528       MemoryMap->PhysicalStart  = MemoryMapDescriptor->PhysicalStart;
   1529       MemoryMap->VirtualStart   = MemoryMapDescriptor->VirtualStart;
   1530       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
   1531 
   1532       //
   1533       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
   1534       //
   1535       return MemoryMapDescriptor;
   1536     }
   1537   }
   1538 
   1539   //
   1540   // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
   1541   //
   1542   // Return the slot immediately after MemoryMapDescriptor as the next available
   1543   // slot in the MemoryMap array
   1544   //
   1545   return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
   1546 }
   1547 
   1548 /**
   1549   This function returns a copy of the current memory map. The map is an array of
   1550   memory descriptors, each of which describes a contiguous block of memory.
   1551 
   1552   @param  MemoryMapSize          A pointer to the size, in bytes, of the
   1553                                  MemoryMap buffer. On input, this is the size of
   1554                                  the buffer allocated by the caller.  On output,
   1555                                  it is the size of the buffer returned by the
   1556                                  firmware  if the buffer was large enough, or the
   1557                                  size of the buffer needed  to contain the map if
   1558                                  the buffer was too small.
   1559   @param  MemoryMap              A pointer to the buffer in which firmware places
   1560                                  the current memory map.
   1561   @param  MapKey                 A pointer to the location in which firmware
   1562                                  returns the key for the current memory map.
   1563   @param  DescriptorSize         A pointer to the location in which firmware
   1564                                  returns the size, in bytes, of an individual
   1565                                  EFI_MEMORY_DESCRIPTOR.
   1566   @param  DescriptorVersion      A pointer to the location in which firmware
   1567                                  returns the version number associated with the
   1568                                  EFI_MEMORY_DESCRIPTOR.
   1569 
   1570   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
   1571                                  buffer.
   1572   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
   1573                                  buffer size needed to hold the memory map is
   1574                                  returned in MemoryMapSize.
   1575   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
   1576 
   1577 **/
   1578 EFI_STATUS
   1579 EFIAPI
   1580 CoreGetMemoryMap (
   1581   IN OUT UINTN                  *MemoryMapSize,
   1582   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
   1583   OUT UINTN                     *MapKey,
   1584   OUT UINTN                     *DescriptorSize,
   1585   OUT UINT32                    *DescriptorVersion
   1586   )
   1587 {
   1588   EFI_STATUS                        Status;
   1589   UINTN                             Size;
   1590   UINTN                             BufferSize;
   1591   UINTN                             NumberOfEntries;
   1592   LIST_ENTRY                        *Link;
   1593   MEMORY_MAP                        *Entry;
   1594   EFI_GCD_MAP_ENTRY                 *GcdMapEntry;
   1595   EFI_GCD_MAP_ENTRY                 MergeGcdMapEntry;
   1596   EFI_MEMORY_TYPE                   Type;
   1597   EFI_MEMORY_DESCRIPTOR             *MemoryMapStart;
   1598 
   1599   //
   1600   // Make sure the parameters are valid
   1601   //
   1602   if (MemoryMapSize == NULL) {
   1603     return EFI_INVALID_PARAMETER;
   1604   }
   1605 
   1606   CoreAcquireGcdMemoryLock ();
   1607 
   1608   //
   1609   // Count the number of Reserved and runtime MMIO entries
   1610   // And, count the number of Persistent entries.
   1611   //
   1612   NumberOfEntries = 0;
   1613   for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
   1614     GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1615     if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) ||
   1616         (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
   1617         ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
   1618         ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
   1619       NumberOfEntries ++;
   1620     }
   1621   }
   1622 
   1623   Size = sizeof (EFI_MEMORY_DESCRIPTOR);
   1624 
   1625   //
   1626   // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
   1627   // prevent people from having pointer math bugs in their code.
   1628   // now you have to use *DescriptorSize to make things work.
   1629   //
   1630   Size += sizeof(UINT64) - (Size % sizeof (UINT64));
   1631 
   1632   if (DescriptorSize != NULL) {
   1633     *DescriptorSize = Size;
   1634   }
   1635 
   1636   if (DescriptorVersion != NULL) {
   1637     *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
   1638   }
   1639 
   1640   CoreAcquireMemoryLock ();
   1641 
   1642   //
   1643   // Compute the buffer size needed to fit the entire map
   1644   //
   1645   BufferSize = Size * NumberOfEntries;
   1646   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1647     BufferSize += Size;
   1648   }
   1649 
   1650   if (*MemoryMapSize < BufferSize) {
   1651     Status = EFI_BUFFER_TOO_SMALL;
   1652     goto Done;
   1653   }
   1654 
   1655   if (MemoryMap == NULL) {
   1656     Status = EFI_INVALID_PARAMETER;
   1657     goto Done;
   1658   }
   1659 
   1660   //
   1661   // Build the map
   1662   //
   1663   ZeroMem (MemoryMap, BufferSize);
   1664   MemoryMapStart = MemoryMap;
   1665   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1666     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
   1667     ASSERT (Entry->VirtualStart == 0);
   1668 
   1669     //
   1670     // Convert internal map into an EFI_MEMORY_DESCRIPTOR
   1671     //
   1672     MemoryMap->Type           = Entry->Type;
   1673     MemoryMap->PhysicalStart  = Entry->Start;
   1674     MemoryMap->VirtualStart   = Entry->VirtualStart;
   1675     MemoryMap->NumberOfPages  = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
   1676     //
   1677     // If the memory type is EfiConventionalMemory, then determine if the range is part of a
   1678     // memory type bin and needs to be converted to the same memory type as the rest of the
   1679     // memory type bin in order to minimize EFI Memory Map changes across reboots.  This
   1680     // improves the chances for a successful S4 resume in the presence of minor page allocation
   1681     // differences across reboots.
   1682     //
   1683     if (MemoryMap->Type == EfiConventionalMemory) {
   1684       for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
   1685         if (mMemoryTypeStatistics[Type].Special                        &&
   1686             mMemoryTypeStatistics[Type].NumberOfPages > 0              &&
   1687             Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress    &&
   1688             Entry->End   <= mMemoryTypeStatistics[Type].MaximumAddress) {
   1689           MemoryMap->Type = Type;
   1690         }
   1691       }
   1692     }
   1693     MemoryMap->Attribute = Entry->Attribute;
   1694     if (MemoryMap->Type < EfiMaxMemoryType) {
   1695       if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
   1696         MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
   1697       }
   1698     }
   1699 
   1700     //
   1701     // Check to see if the new Memory Map Descriptor can be merged with an
   1702     // existing descriptor if they are adjacent and have the same attributes
   1703     //
   1704     MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
   1705   }
   1706 
   1707 
   1708   ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
   1709   GcdMapEntry = NULL;
   1710   for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
   1711     if (Link != &mGcdMemorySpaceMap) {
   1712       //
   1713       // Merge adjacent same type and attribute GCD memory range
   1714       //
   1715       GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1716 
   1717       if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
   1718           (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
   1719           (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
   1720           (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
   1721         MergeGcdMapEntry.EndAddress  = GcdMapEntry->EndAddress;
   1722         continue;
   1723       }
   1724     }
   1725 
   1726     if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
   1727         ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
   1728         ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
   1729       //
   1730       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
   1731       // it will be recorded as page PhysicalStart and NumberOfPages.
   1732       //
   1733       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
   1734       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
   1735 
   1736       //
   1737       // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
   1738       //
   1739       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
   1740       MemoryMap->VirtualStart  = 0;
   1741       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
   1742       MemoryMap->Attribute     = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
   1743                                 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
   1744                                 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
   1745 
   1746       if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
   1747         MemoryMap->Type = EfiReservedMemoryType;
   1748       } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
   1749         if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
   1750           MemoryMap->Type = EfiMemoryMappedIOPortSpace;
   1751         } else {
   1752           MemoryMap->Type = EfiMemoryMappedIO;
   1753         }
   1754       }
   1755 
   1756       //
   1757       // Check to see if the new Memory Map Descriptor can be merged with an
   1758       // existing descriptor if they are adjacent and have the same attributes
   1759       //
   1760       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
   1761     }
   1762 
   1763     if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistentMemory) {
   1764       //
   1765       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
   1766       // it will be recorded as page PhysicalStart and NumberOfPages.
   1767       //
   1768       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
   1769       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
   1770 
   1771       //
   1772       // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
   1773       //
   1774       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
   1775       MemoryMap->VirtualStart  = 0;
   1776       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
   1777       MemoryMap->Attribute     = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
   1778                                 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
   1779                                 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
   1780       MemoryMap->Type          = EfiPersistentMemory;
   1781 
   1782       //
   1783       // Check to see if the new Memory Map Descriptor can be merged with an
   1784       // existing descriptor if they are adjacent and have the same attributes
   1785       //
   1786       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
   1787     }
   1788     if (Link == &mGcdMemorySpaceMap) {
   1789       //
   1790       // break loop when arrive at head.
   1791       //
   1792       break;
   1793     }
   1794     if (GcdMapEntry != NULL) {
   1795       //
   1796       // Copy new GCD map entry for the following GCD range merge
   1797       //
   1798       CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
   1799     }
   1800   }
   1801 
   1802   //
   1803   // Compute the size of the buffer actually used after all memory map descriptor merge operations
   1804   //
   1805   BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
   1806 
   1807   Status = EFI_SUCCESS;
   1808 
   1809 Done:
   1810   //
   1811   // Update the map key finally
   1812   //
   1813   if (MapKey != NULL) {
   1814     *MapKey = mMemoryMapKey;
   1815   }
   1816 
   1817   CoreReleaseMemoryLock ();
   1818 
   1819   CoreReleaseGcdMemoryLock ();
   1820 
   1821   *MemoryMapSize = BufferSize;
   1822 
   1823   return Status;
   1824 }
   1825 
   1826 
   1827 /**
   1828   Internal function.  Used by the pool functions to allocate pages
   1829   to back pool allocation requests.
   1830 
   1831   @param  PoolType               The type of memory for the new pool pages
   1832   @param  NumberOfPages          No of pages to allocate
   1833   @param  Alignment              Bits to align.
   1834 
   1835   @return The allocated memory, or NULL
   1836 
   1837 **/
   1838 VOID *
   1839 CoreAllocatePoolPages (
   1840   IN EFI_MEMORY_TYPE    PoolType,
   1841   IN UINTN              NumberOfPages,
   1842   IN UINTN              Alignment
   1843   )
   1844 {
   1845   UINT64            Start;
   1846 
   1847   //
   1848   // Find the pages to convert
   1849   //
   1850   Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
   1851 
   1852   //
   1853   // Convert it to boot services data
   1854   //
   1855   if (Start == 0) {
   1856     DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
   1857   } else {
   1858     CoreConvertPages (Start, NumberOfPages, PoolType);
   1859   }
   1860 
   1861   return (VOID *)(UINTN) Start;
   1862 }
   1863 
   1864 
   1865 /**
   1866   Internal function.  Frees pool pages allocated via AllocatePoolPages ()
   1867 
   1868   @param  Memory                 The base address to free
   1869   @param  NumberOfPages          The number of pages to free
   1870 
   1871 **/
   1872 VOID
   1873 CoreFreePoolPages (
   1874   IN EFI_PHYSICAL_ADDRESS   Memory,
   1875   IN UINTN                  NumberOfPages
   1876   )
   1877 {
   1878   CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
   1879 }
   1880 
   1881 
   1882 
   1883 /**
   1884   Make sure the memory map is following all the construction rules,
   1885   it is the last time to check memory map error before exit boot services.
   1886 
   1887   @param  MapKey                 Memory map key
   1888 
   1889   @retval EFI_INVALID_PARAMETER  Memory map not consistent with construction
   1890                                  rules.
   1891   @retval EFI_SUCCESS            Valid memory map.
   1892 
   1893 **/
   1894 EFI_STATUS
   1895 CoreTerminateMemoryMap (
   1896   IN UINTN          MapKey
   1897   )
   1898 {
   1899   EFI_STATUS        Status;
   1900   LIST_ENTRY        *Link;
   1901   MEMORY_MAP        *Entry;
   1902 
   1903   Status = EFI_SUCCESS;
   1904 
   1905   CoreAcquireMemoryLock ();
   1906 
   1907   if (MapKey == mMemoryMapKey) {
   1908 
   1909     //
   1910     // Make sure the memory map is following all the construction rules
   1911     // This is the last chance we will be able to display any messages on
   1912     // the  console devices.
   1913     //
   1914 
   1915     for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
   1916       Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
   1917       if (Entry->Type < EfiMaxMemoryType) {
   1918         if (mMemoryTypeStatistics[Entry->Type].Runtime) {
   1919           ASSERT (Entry->Type != EfiACPIReclaimMemory);
   1920           ASSERT (Entry->Type != EfiACPIMemoryNVS);
   1921           if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
   1922             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
   1923             Status =  EFI_INVALID_PARAMETER;
   1924             goto Done;
   1925           }
   1926           if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
   1927             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
   1928             Status =  EFI_INVALID_PARAMETER;
   1929             goto Done;
   1930           }
   1931         }
   1932       }
   1933     }
   1934 
   1935     //
   1936     // The map key they gave us matches what we expect. Fall through and
   1937     // return success. In an ideal world we would clear out all of
   1938     // EfiBootServicesCode and EfiBootServicesData. However this function
   1939     // is not the last one called by ExitBootServices(), so we have to
   1940     // preserve the memory contents.
   1941     //
   1942   } else {
   1943     Status = EFI_INVALID_PARAMETER;
   1944   }
   1945 
   1946 Done:
   1947   CoreReleaseMemoryLock ();
   1948 
   1949   return Status;
   1950 }
   1951 
   1952 
   1953 
   1954 
   1955 
   1956 
   1957 
   1958 
   1959 
   1960