Home | History | Annotate | Download | only in Gcd
      1 /** @file
      2   The file contains the GCD related services in the EFI Boot Services Table.
      3   The GCD services are used to manage the memory and I/O regions that
      4   are accessible to the CPU that is executing the DXE core.
      5 
      6 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "DxeMain.h"
     18 #include "Gcd.h"
     19 
     20 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
     21 
     22 #define MEMORY_ATTRIBUTE_MASK         (EFI_RESOURCE_ATTRIBUTE_PRESENT             | \
     23                                        EFI_RESOURCE_ATTRIBUTE_INITIALIZED         | \
     24                                        EFI_RESOURCE_ATTRIBUTE_TESTED              | \
     25                                        EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED      | \
     26                                        EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED     | \
     27                                        EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
     28                                        EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
     29                                        EFI_RESOURCE_ATTRIBUTE_16_BIT_IO           | \
     30                                        EFI_RESOURCE_ATTRIBUTE_32_BIT_IO           | \
     31                                        EFI_RESOURCE_ATTRIBUTE_64_BIT_IO           | \
     32                                        EFI_RESOURCE_ATTRIBUTE_PERSISTENT          )
     33 
     34 #define TESTED_MEMORY_ATTRIBUTES      (EFI_RESOURCE_ATTRIBUTE_PRESENT     | \
     35                                        EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
     36                                        EFI_RESOURCE_ATTRIBUTE_TESTED      )
     37 
     38 #define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT     | \
     39                                        EFI_RESOURCE_ATTRIBUTE_INITIALIZED )
     40 
     41 #define PRESENT_MEMORY_ATTRIBUTES     (EFI_RESOURCE_ATTRIBUTE_PRESENT)
     42 
     43 #define INVALID_CPU_ARCH_ATTRIBUTES   0xffffffff
     44 
     45 //
     46 // Module Variables
     47 //
     48 EFI_LOCK           mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
     49 EFI_LOCK           mGcdIoSpaceLock     = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
     50 LIST_ENTRY         mGcdMemorySpaceMap  = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap);
     51 LIST_ENTRY         mGcdIoSpaceMap      = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap);
     52 
     53 EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = {
     54   EFI_GCD_MAP_SIGNATURE,
     55   {
     56     NULL,
     57     NULL
     58   },
     59   0,
     60   0,
     61   0,
     62   0,
     63   EfiGcdMemoryTypeNonExistent,
     64   (EFI_GCD_IO_TYPE) 0,
     65   NULL,
     66   NULL
     67 };
     68 
     69 EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {
     70   EFI_GCD_MAP_SIGNATURE,
     71   {
     72     NULL,
     73     NULL
     74   },
     75   0,
     76   0,
     77   0,
     78   0,
     79   (EFI_GCD_MEMORY_TYPE) 0,
     80   EfiGcdIoTypeNonExistent,
     81   NULL,
     82   NULL
     83 };
     84 
     85 GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
     86   { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE,             EFI_MEMORY_UC,              TRUE  },
     87   { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED,       EFI_MEMORY_UCE,             TRUE  },
     88   { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE,       EFI_MEMORY_WC,              TRUE  },
     89   { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT,              TRUE  },
     90   { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE,    EFI_MEMORY_WB,              TRUE  },
     91   { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE,        EFI_MEMORY_RP,              TRUE  },
     92   { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE,       EFI_MEMORY_WP,              TRUE  },
     93   { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE,   EFI_MEMORY_XP,              TRUE  },
     94   { EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE,   EFI_MEMORY_RO,              TRUE  },
     95   { EFI_RESOURCE_ATTRIBUTE_PRESENT,                 EFI_MEMORY_PRESENT,         FALSE },
     96   { EFI_RESOURCE_ATTRIBUTE_INITIALIZED,             EFI_MEMORY_INITIALIZED,     FALSE },
     97   { EFI_RESOURCE_ATTRIBUTE_TESTED,                  EFI_MEMORY_TESTED,          FALSE },
     98   { EFI_RESOURCE_ATTRIBUTE_PERSISTABLE,             EFI_MEMORY_NV,              TRUE  },
     99   { EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE,           EFI_MEMORY_MORE_RELIABLE,   TRUE  },
    100   { 0,                                              0,                          FALSE }
    101 };
    102 
    103 ///
    104 /// Lookup table used to print GCD Memory Space Map
    105 ///
    106 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdMemoryTypeNames[] = {
    107   "NonExist ",  // EfiGcdMemoryTypeNonExistent
    108   "Reserved ",  // EfiGcdMemoryTypeReserved
    109   "SystemMem",  // EfiGcdMemoryTypeSystemMemory
    110   "MMIO     ",  // EfiGcdMemoryTypeMemoryMappedIo
    111   "PersisMem",  // EfiGcdMemoryTypePersistentMemory
    112   "MoreRelia",  // EfiGcdMemoryTypeMoreReliable
    113   "Unknown  "   // EfiGcdMemoryTypeMaximum
    114 };
    115 
    116 ///
    117 /// Lookup table used to print GCD I/O Space Map
    118 ///
    119 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdIoTypeNames[] = {
    120   "NonExist",  // EfiGcdIoTypeNonExistent
    121   "Reserved",  // EfiGcdIoTypeReserved
    122   "I/O     ",  // EfiGcdIoTypeIo
    123   "Unknown "   // EfiGcdIoTypeMaximum
    124 };
    125 
    126 ///
    127 /// Lookup table used to print GCD Allocation Types
    128 ///
    129 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdAllocationTypeNames[] = {
    130   "AnySearchBottomUp        ",  // EfiGcdAllocateAnySearchBottomUp
    131   "MaxAddressSearchBottomUp ",  // EfiGcdAllocateMaxAddressSearchBottomUp
    132   "AtAddress                ",  // EfiGcdAllocateAddress
    133   "AnySearchTopDown         ",  // EfiGcdAllocateAnySearchTopDown
    134   "MaxAddressSearchTopDown  ",  // EfiGcdAllocateMaxAddressSearchTopDown
    135   "Unknown                  "   // EfiGcdMaxAllocateType
    136 };
    137 
    138 /**
    139   Dump the entire contents if the GCD Memory Space Map using DEBUG() macros when
    140   PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
    141 
    142   @param  InitialMap  TRUE if the initial GCD Memory Map is being dumped.  Otherwise, FALSE.
    143 
    144 **/
    145 VOID
    146 EFIAPI
    147 CoreDumpGcdMemorySpaceMap (
    148   BOOLEAN  InitialMap
    149   )
    150 {
    151   DEBUG_CODE (
    152     EFI_STATUS                       Status;
    153     UINTN                            NumberOfDescriptors;
    154     EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemorySpaceMap;
    155     UINTN                            Index;
    156 
    157     Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
    158     ASSERT (Status == EFI_SUCCESS && MemorySpaceMap != NULL);
    159 
    160     if (InitialMap) {
    161       DEBUG ((DEBUG_GCD, "GCD:Initial GCD Memory Space Map\n"));
    162     }
    163     DEBUG ((DEBUG_GCD, "GCDMemType Range                             Capabilities     Attributes      \n"));
    164     DEBUG ((DEBUG_GCD, "========== ================================= ================ ================\n"));
    165     for (Index = 0; Index < NumberOfDescriptors; Index++) {
    166       DEBUG ((DEBUG_GCD, "%a  %016lx-%016lx %016lx %016lx%c\n",
    167         mGcdMemoryTypeNames[MIN (MemorySpaceMap[Index].GcdMemoryType, EfiGcdMemoryTypeMaximum)],
    168         MemorySpaceMap[Index].BaseAddress,
    169         MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1,
    170         MemorySpaceMap[Index].Capabilities,
    171         MemorySpaceMap[Index].Attributes,
    172         MemorySpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
    173         ));
    174     }
    175     DEBUG ((DEBUG_GCD, "\n"));
    176     FreePool (MemorySpaceMap);
    177   );
    178 }
    179 
    180 /**
    181   Dump the entire contents if the GCD I/O Space Map using DEBUG() macros when
    182   PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
    183 
    184   @param  InitialMap  TRUE if the initial GCD I/O Map is being dumped.  Otherwise, FALSE.
    185 
    186 **/
    187 VOID
    188 EFIAPI
    189 CoreDumpGcdIoSpaceMap (
    190   BOOLEAN  InitialMap
    191   )
    192 {
    193   DEBUG_CODE (
    194     EFI_STATUS                   Status;
    195     UINTN                        NumberOfDescriptors;
    196     EFI_GCD_IO_SPACE_DESCRIPTOR  *IoSpaceMap;
    197     UINTN                        Index;
    198 
    199     Status = CoreGetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
    200     ASSERT (Status == EFI_SUCCESS && IoSpaceMap != NULL);
    201 
    202     if (InitialMap) {
    203       DEBUG ((DEBUG_GCD, "GCD:Initial GCD I/O Space Map\n"));
    204     }
    205 
    206     DEBUG ((DEBUG_GCD, "GCDIoType  Range                            \n"));
    207     DEBUG ((DEBUG_GCD, "========== =================================\n"));
    208     for (Index = 0; Index < NumberOfDescriptors; Index++) {
    209       DEBUG ((DEBUG_GCD, "%a   %016lx-%016lx%c\n",
    210         mGcdIoTypeNames[MIN (IoSpaceMap[Index].GcdIoType, EfiGcdIoTypeMaximum)],
    211         IoSpaceMap[Index].BaseAddress,
    212         IoSpaceMap[Index].BaseAddress + IoSpaceMap[Index].Length - 1,
    213         IoSpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
    214         ));
    215     }
    216     DEBUG ((DEBUG_GCD, "\n"));
    217     FreePool (IoSpaceMap);
    218   );
    219 }
    220 
    221 /**
    222   Validate resource descriptor HOB's attributes.
    223 
    224   If Attributes includes some memory resource's settings, it should include
    225   the corresponding capabilites also.
    226 
    227   @param  Attributes  Resource descriptor HOB attributes.
    228 
    229 **/
    230 VOID
    231 CoreValidateResourceDescriptorHobAttributes (
    232   IN UINT64  Attributes
    233   )
    234 {
    235   ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED) == 0) ||
    236           ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE) != 0));
    237   ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED) == 0) ||
    238           ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE) != 0));
    239   ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED) == 0) ||
    240           ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE) != 0));
    241   ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED) == 0) ||
    242           ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE) != 0));
    243   ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == 0) ||
    244           ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTABLE) != 0));
    245 }
    246 
    247 /**
    248   Acquire memory lock on mGcdMemorySpaceLock.
    249 
    250 **/
    251 VOID
    252 CoreAcquireGcdMemoryLock (
    253   VOID
    254   )
    255 {
    256   CoreAcquireLock (&mGcdMemorySpaceLock);
    257 }
    258 
    259 
    260 
    261 /**
    262   Release memory lock on mGcdMemorySpaceLock.
    263 
    264 **/
    265 VOID
    266 CoreReleaseGcdMemoryLock (
    267   VOID
    268   )
    269 {
    270   CoreReleaseLock (&mGcdMemorySpaceLock);
    271 }
    272 
    273 
    274 
    275 /**
    276   Acquire memory lock on mGcdIoSpaceLock.
    277 
    278 **/
    279 VOID
    280 CoreAcquireGcdIoLock (
    281   VOID
    282   )
    283 {
    284   CoreAcquireLock (&mGcdIoSpaceLock);
    285 }
    286 
    287 
    288 /**
    289   Release memory lock on mGcdIoSpaceLock.
    290 
    291 **/
    292 VOID
    293 CoreReleaseGcdIoLock (
    294   VOID
    295   )
    296 {
    297   CoreReleaseLock (&mGcdIoSpaceLock);
    298 }
    299 
    300 
    301 
    302 //
    303 // GCD Initialization Worker Functions
    304 //
    305 /**
    306   Aligns a value to the specified boundary.
    307 
    308   @param  Value                  64 bit value to align
    309   @param  Alignment              Log base 2 of the boundary to align Value to
    310   @param  RoundUp                TRUE if Value is to be rounded up to the nearest
    311                                  aligned boundary.  FALSE is Value is to be
    312                                  rounded down to the nearest aligned boundary.
    313 
    314   @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
    315 
    316 **/
    317 UINT64
    318 AlignValue (
    319   IN UINT64   Value,
    320   IN UINTN    Alignment,
    321   IN BOOLEAN  RoundUp
    322   )
    323 {
    324   UINT64  AlignmentMask;
    325 
    326   AlignmentMask = LShiftU64 (1, Alignment) - 1;
    327   if (RoundUp) {
    328     Value += AlignmentMask;
    329   }
    330   return Value & (~AlignmentMask);
    331 }
    332 
    333 
    334 /**
    335   Aligns address to the page boundary.
    336 
    337   @param  Value                  64 bit address to align
    338 
    339   @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
    340 
    341 **/
    342 UINT64
    343 PageAlignAddress (
    344   IN UINT64 Value
    345   )
    346 {
    347   return AlignValue (Value, EFI_PAGE_SHIFT, TRUE);
    348 }
    349 
    350 
    351 /**
    352   Aligns length to the page boundary.
    353 
    354   @param  Value                  64 bit length to align
    355 
    356   @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
    357 
    358 **/
    359 UINT64
    360 PageAlignLength (
    361   IN UINT64 Value
    362   )
    363 {
    364   return AlignValue (Value, EFI_PAGE_SHIFT, FALSE);
    365 }
    366 
    367 //
    368 // GCD Memory Space Worker Functions
    369 //
    370 
    371 /**
    372   Allocate pool for two entries.
    373 
    374   @param  TopEntry               An entry of GCD map
    375   @param  BottomEntry            An entry of GCD map
    376 
    377   @retval EFI_OUT_OF_RESOURCES   No enough buffer to be allocated.
    378   @retval EFI_SUCCESS            Both entries successfully allocated.
    379 
    380 **/
    381 EFI_STATUS
    382 CoreAllocateGcdMapEntry (
    383   IN OUT EFI_GCD_MAP_ENTRY  **TopEntry,
    384   IN OUT EFI_GCD_MAP_ENTRY  **BottomEntry
    385   )
    386 {
    387   *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
    388   if (*TopEntry == NULL) {
    389     return EFI_OUT_OF_RESOURCES;
    390   }
    391 
    392   *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
    393   if (*BottomEntry == NULL) {
    394     CoreFreePool (*TopEntry);
    395     return EFI_OUT_OF_RESOURCES;
    396   }
    397 
    398   return EFI_SUCCESS;
    399 }
    400 
    401 
    402 /**
    403   Internal function.  Inserts a new descriptor into a sorted list
    404 
    405   @param  Link                   The linked list to insert the range BaseAddress
    406                                  and Length into
    407   @param  Entry                  A pointer to the entry that is inserted
    408   @param  BaseAddress            The base address of the new range
    409   @param  Length                 The length of the new range in bytes
    410   @param  TopEntry               Top pad entry to insert if needed.
    411   @param  BottomEntry            Bottom pad entry to insert if needed.
    412 
    413   @retval EFI_SUCCESS            The new range was inserted into the linked list
    414 
    415 **/
    416 EFI_STATUS
    417 CoreInsertGcdMapEntry (
    418   IN LIST_ENTRY           *Link,
    419   IN EFI_GCD_MAP_ENTRY     *Entry,
    420   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
    421   IN UINT64                Length,
    422   IN EFI_GCD_MAP_ENTRY     *TopEntry,
    423   IN EFI_GCD_MAP_ENTRY     *BottomEntry
    424   )
    425 {
    426   ASSERT (Length != 0);
    427 
    428   if (BaseAddress > Entry->BaseAddress) {
    429     ASSERT (BottomEntry->Signature == 0);
    430 
    431     CopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
    432     Entry->BaseAddress      = BaseAddress;
    433     BottomEntry->EndAddress = BaseAddress - 1;
    434     InsertTailList (Link, &BottomEntry->Link);
    435   }
    436 
    437   if ((BaseAddress + Length - 1) < Entry->EndAddress) {
    438     ASSERT (TopEntry->Signature == 0);
    439 
    440     CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
    441     TopEntry->BaseAddress = BaseAddress + Length;
    442     Entry->EndAddress     = BaseAddress + Length - 1;
    443     InsertHeadList (Link, &TopEntry->Link);
    444   }
    445 
    446   return EFI_SUCCESS;
    447 }
    448 
    449 
    450 /**
    451   Merge the Gcd region specified by Link and its adjacent entry.
    452 
    453   @param  Link                   Specify the entry to be merged (with its
    454                                  adjacent entry).
    455   @param  Forward                Direction (forward or backward).
    456   @param  Map                    Boundary.
    457 
    458   @retval EFI_SUCCESS            Successfully returned.
    459   @retval EFI_UNSUPPORTED        These adjacent regions could not merge.
    460 
    461 **/
    462 EFI_STATUS
    463 CoreMergeGcdMapEntry (
    464   IN LIST_ENTRY      *Link,
    465   IN BOOLEAN         Forward,
    466   IN LIST_ENTRY      *Map
    467   )
    468 {
    469   LIST_ENTRY         *AdjacentLink;
    470   EFI_GCD_MAP_ENTRY  *Entry;
    471   EFI_GCD_MAP_ENTRY  *AdjacentEntry;
    472 
    473   //
    474   // Get adjacent entry
    475   //
    476   if (Forward) {
    477     AdjacentLink = Link->ForwardLink;
    478   } else {
    479     AdjacentLink = Link->BackLink;
    480   }
    481 
    482   //
    483   // If AdjacentLink is the head of the list, then no merge can be performed
    484   //
    485   if (AdjacentLink == Map) {
    486     return EFI_SUCCESS;
    487   }
    488 
    489   Entry         = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    490   AdjacentEntry = CR (AdjacentLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    491 
    492   if (Entry->Capabilities != AdjacentEntry->Capabilities) {
    493     return EFI_UNSUPPORTED;
    494   }
    495   if (Entry->Attributes != AdjacentEntry->Attributes) {
    496     return EFI_UNSUPPORTED;
    497   }
    498   if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) {
    499     return EFI_UNSUPPORTED;
    500   }
    501   if (Entry->GcdIoType != AdjacentEntry->GcdIoType) {
    502     return EFI_UNSUPPORTED;
    503   }
    504   if (Entry->ImageHandle != AdjacentEntry->ImageHandle) {
    505     return EFI_UNSUPPORTED;
    506   }
    507   if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) {
    508     return EFI_UNSUPPORTED;
    509   }
    510 
    511   if (Forward) {
    512     Entry->EndAddress  = AdjacentEntry->EndAddress;
    513   } else {
    514     Entry->BaseAddress = AdjacentEntry->BaseAddress;
    515   }
    516   RemoveEntryList (AdjacentLink);
    517   CoreFreePool (AdjacentEntry);
    518 
    519   return EFI_SUCCESS;
    520 }
    521 
    522 
    523 /**
    524   Merge adjacent entries on total chain.
    525 
    526   @param  TopEntry               Top entry of GCD map.
    527   @param  BottomEntry            Bottom entry of GCD map.
    528   @param  StartLink              Start link of the list for this loop.
    529   @param  EndLink                End link of the list for this loop.
    530   @param  Map                    Boundary.
    531 
    532   @retval EFI_SUCCESS            GCD map successfully cleaned up.
    533 
    534 **/
    535 EFI_STATUS
    536 CoreCleanupGcdMapEntry (
    537   IN EFI_GCD_MAP_ENTRY  *TopEntry,
    538   IN EFI_GCD_MAP_ENTRY  *BottomEntry,
    539   IN LIST_ENTRY         *StartLink,
    540   IN LIST_ENTRY         *EndLink,
    541   IN LIST_ENTRY         *Map
    542   )
    543 {
    544   LIST_ENTRY  *Link;
    545 
    546   if (TopEntry->Signature == 0) {
    547     CoreFreePool (TopEntry);
    548   }
    549   if (BottomEntry->Signature == 0) {
    550     CoreFreePool (BottomEntry);
    551   }
    552 
    553   Link = StartLink;
    554   while (Link != EndLink->ForwardLink) {
    555     CoreMergeGcdMapEntry (Link, FALSE, Map);
    556     Link = Link->ForwardLink;
    557   }
    558   CoreMergeGcdMapEntry (EndLink, TRUE, Map);
    559 
    560   return EFI_SUCCESS;
    561 }
    562 
    563 
    564 /**
    565   Search a segment of memory space in GCD map. The result is a range of GCD entry list.
    566 
    567   @param  BaseAddress            The start address of the segment.
    568   @param  Length                 The length of the segment.
    569   @param  StartLink              The first GCD entry involves this segment of
    570                                  memory space.
    571   @param  EndLink                The first GCD entry involves this segment of
    572                                  memory space.
    573   @param  Map                    Points to the start entry to search.
    574 
    575   @retval EFI_SUCCESS            Successfully found the entry.
    576   @retval EFI_NOT_FOUND          Not found.
    577 
    578 **/
    579 EFI_STATUS
    580 CoreSearchGcdMapEntry (
    581   IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
    582   IN  UINT64                Length,
    583   OUT LIST_ENTRY            **StartLink,
    584   OUT LIST_ENTRY            **EndLink,
    585   IN  LIST_ENTRY            *Map
    586   )
    587 {
    588   LIST_ENTRY         *Link;
    589   EFI_GCD_MAP_ENTRY  *Entry;
    590 
    591   ASSERT (Length != 0);
    592 
    593   *StartLink = NULL;
    594   *EndLink   = NULL;
    595 
    596   Link = Map->ForwardLink;
    597   while (Link != Map) {
    598     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    599     if (BaseAddress >= Entry->BaseAddress && BaseAddress <= Entry->EndAddress) {
    600       *StartLink = Link;
    601     }
    602     if (*StartLink != NULL) {
    603       if ((BaseAddress + Length - 1) >= Entry->BaseAddress &&
    604           (BaseAddress + Length - 1) <= Entry->EndAddress     ) {
    605         *EndLink = Link;
    606         return EFI_SUCCESS;
    607       }
    608     }
    609     Link = Link->ForwardLink;
    610   }
    611 
    612   return EFI_NOT_FOUND;
    613 }
    614 
    615 
    616 /**
    617   Count the amount of GCD map entries.
    618 
    619   @param  Map                    Points to the start entry to do the count loop.
    620 
    621   @return The count.
    622 
    623 **/
    624 UINTN
    625 CoreCountGcdMapEntry (
    626   IN LIST_ENTRY  *Map
    627   )
    628 {
    629   UINTN           Count;
    630   LIST_ENTRY      *Link;
    631 
    632   Count = 0;
    633   Link = Map->ForwardLink;
    634   while (Link != Map) {
    635     Count++;
    636     Link = Link->ForwardLink;
    637   }
    638 
    639   return Count;
    640 }
    641 
    642 
    643 
    644 /**
    645   Return the memory attribute specified by Attributes
    646 
    647   @param  Attributes             A num with some attribute bits on.
    648 
    649   @return The enum value of memory attribute.
    650 
    651 **/
    652 UINT64
    653 ConverToCpuArchAttributes (
    654   UINT64 Attributes
    655   )
    656 {
    657   if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {
    658     return EFI_MEMORY_UC;
    659   }
    660 
    661   if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) {
    662     return EFI_MEMORY_WC;
    663   }
    664 
    665   if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) {
    666     return EFI_MEMORY_WT;
    667   }
    668 
    669   if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) {
    670     return EFI_MEMORY_WB;
    671   }
    672 
    673   if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) {
    674     return EFI_MEMORY_WP;
    675   }
    676 
    677   return INVALID_CPU_ARCH_ATTRIBUTES;
    678 
    679 }
    680 
    681 
    682 /**
    683   Do operation on a segment of memory space specified (add, free, remove, change attribute ...).
    684 
    685   @param  Operation              The type of the operation
    686   @param  GcdMemoryType          Additional information for the operation
    687   @param  GcdIoType              Additional information for the operation
    688   @param  BaseAddress            Start address of the segment
    689   @param  Length                 length of the segment
    690   @param  Capabilities           The alterable attributes of a newly added entry
    691   @param  Attributes             The attributes needs to be set
    692 
    693   @retval EFI_INVALID_PARAMETER  Length is 0 or address (length) not aligned when
    694                                  setting attribute.
    695   @retval EFI_SUCCESS            Action successfully done.
    696   @retval EFI_UNSUPPORTED        Could not find the proper descriptor on this
    697                                  segment or  set an upsupported attribute.
    698   @retval EFI_ACCESS_DENIED      Operate on an space non-exist or is used for an
    699                                  image.
    700   @retval EFI_NOT_FOUND          Free a non-using space or remove a non-exist
    701                                  space, and so on.
    702   @retval EFI_OUT_OF_RESOURCES   No buffer could be allocated.
    703   @retval EFI_NOT_AVAILABLE_YET  The attributes cannot be set because CPU architectural protocol
    704                                  is not available yet.
    705 **/
    706 EFI_STATUS
    707 CoreConvertSpace (
    708   IN UINTN                 Operation,
    709   IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,
    710   IN EFI_GCD_IO_TYPE       GcdIoType,
    711   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
    712   IN UINT64                Length,
    713   IN UINT64                Capabilities,
    714   IN UINT64                Attributes
    715   )
    716 {
    717   EFI_STATUS         Status;
    718   LIST_ENTRY         *Map;
    719   LIST_ENTRY         *Link;
    720   EFI_GCD_MAP_ENTRY  *Entry;
    721   EFI_GCD_MAP_ENTRY  *TopEntry;
    722   EFI_GCD_MAP_ENTRY  *BottomEntry;
    723   LIST_ENTRY         *StartLink;
    724   LIST_ENTRY         *EndLink;
    725   UINT64             CpuArchAttributes;
    726 
    727   if (Length == 0) {
    728     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
    729     return EFI_INVALID_PARAMETER;
    730   }
    731 
    732   Map = NULL;
    733   if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
    734     CoreAcquireGcdMemoryLock ();
    735     Map = &mGcdMemorySpaceMap;
    736   } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
    737     CoreAcquireGcdIoLock ();
    738     Map = &mGcdIoSpaceMap;
    739   } else {
    740     ASSERT (FALSE);
    741   }
    742 
    743   //
    744   // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
    745   //
    746   Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);
    747   if (EFI_ERROR (Status)) {
    748     Status = EFI_UNSUPPORTED;
    749 
    750     goto Done;
    751   }
    752   ASSERT (StartLink != NULL && EndLink != NULL);
    753 
    754   //
    755   // Verify that the list of descriptors are unallocated non-existent memory.
    756   //
    757   Link = StartLink;
    758   while (Link != EndLink->ForwardLink) {
    759     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    760     switch (Operation) {
    761     //
    762     // Add operations
    763     //
    764     case GCD_ADD_MEMORY_OPERATION:
    765       if (Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent ||
    766           Entry->ImageHandle   != NULL                           ) {
    767         Status = EFI_ACCESS_DENIED;
    768         goto Done;
    769       }
    770       break;
    771     case GCD_ADD_IO_OPERATION:
    772       if (Entry->GcdIoType   != EfiGcdIoTypeNonExistent ||
    773           Entry->ImageHandle != NULL                       ) {
    774         Status = EFI_ACCESS_DENIED;
    775         goto Done;
    776       }
    777       break;
    778     //
    779     // Free operations
    780     //
    781     case GCD_FREE_MEMORY_OPERATION:
    782     case GCD_FREE_IO_OPERATION:
    783       if (Entry->ImageHandle == NULL) {
    784         Status = EFI_NOT_FOUND;
    785         goto Done;
    786       }
    787       break;
    788     //
    789     // Remove operations
    790     //
    791     case GCD_REMOVE_MEMORY_OPERATION:
    792       if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
    793         Status = EFI_NOT_FOUND;
    794         goto Done;
    795       }
    796       if (Entry->ImageHandle != NULL) {
    797         Status = EFI_ACCESS_DENIED;
    798         goto Done;
    799       }
    800       break;
    801     case GCD_REMOVE_IO_OPERATION:
    802       if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {
    803         Status = EFI_NOT_FOUND;
    804         goto Done;
    805       }
    806       if (Entry->ImageHandle != NULL) {
    807         Status = EFI_ACCESS_DENIED;
    808         goto Done;
    809       }
    810       break;
    811     //
    812     // Set attributes operation
    813     //
    814     case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
    815       if ((Attributes & EFI_MEMORY_RUNTIME) != 0) {
    816         if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
    817           Status = EFI_INVALID_PARAMETER;
    818           goto Done;
    819         }
    820       }
    821       if ((Entry->Capabilities & Attributes) != Attributes) {
    822         Status = EFI_UNSUPPORTED;
    823         goto Done;
    824       }
    825       break;
    826     //
    827     // Set capabilities operation
    828     //
    829     case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
    830       if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
    831         Status = EFI_INVALID_PARAMETER;
    832 
    833         goto Done;
    834       }
    835       //
    836       // Current attributes must still be supported with new capabilities
    837       //
    838       if ((Capabilities & Entry->Attributes) != Entry->Attributes) {
    839         Status = EFI_UNSUPPORTED;
    840         goto Done;
    841       }
    842       break;
    843     }
    844     Link = Link->ForwardLink;
    845   }
    846 
    847   //
    848   // Allocate work space to perform this operation
    849   //
    850   Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
    851   if (EFI_ERROR (Status)) {
    852     Status = EFI_OUT_OF_RESOURCES;
    853     goto Done;
    854   }
    855   ASSERT (TopEntry != NULL && BottomEntry != NULL);
    856 
    857   if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
    858     //
    859     // Call CPU Arch Protocol to attempt to set attributes on the range
    860     //
    861     CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
    862     if (CpuArchAttributes != INVALID_CPU_ARCH_ATTRIBUTES) {
    863       if (gCpu == NULL) {
    864         Status = EFI_NOT_AVAILABLE_YET;
    865       } else {
    866         Status = gCpu->SetMemoryAttributes (
    867                          gCpu,
    868                          BaseAddress,
    869                          Length,
    870                          CpuArchAttributes
    871                          );
    872       }
    873       if (EFI_ERROR (Status)) {
    874         CoreFreePool (TopEntry);
    875         CoreFreePool (BottomEntry);
    876         goto Done;
    877       }
    878     }
    879   }
    880 
    881   //
    882   // Convert/Insert the list of descriptors from StartLink to EndLink
    883   //
    884   Link = StartLink;
    885   while (Link != EndLink->ForwardLink) {
    886     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    887     CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);
    888     switch (Operation) {
    889     //
    890     // Add operations
    891     //
    892     case GCD_ADD_MEMORY_OPERATION:
    893       Entry->GcdMemoryType = GcdMemoryType;
    894       if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
    895         Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
    896       } else {
    897         Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME;
    898       }
    899       break;
    900     case GCD_ADD_IO_OPERATION:
    901       Entry->GcdIoType = GcdIoType;
    902       break;
    903     //
    904     // Free operations
    905     //
    906     case GCD_FREE_MEMORY_OPERATION:
    907     case GCD_FREE_IO_OPERATION:
    908       Entry->ImageHandle  = NULL;
    909       Entry->DeviceHandle = NULL;
    910       break;
    911     //
    912     // Remove operations
    913     //
    914     case GCD_REMOVE_MEMORY_OPERATION:
    915       Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
    916       Entry->Capabilities  = 0;
    917       break;
    918     case GCD_REMOVE_IO_OPERATION:
    919       Entry->GcdIoType = EfiGcdIoTypeNonExistent;
    920       break;
    921     //
    922     // Set attributes operation
    923     //
    924     case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
    925       Entry->Attributes = Attributes;
    926       break;
    927     //
    928     // Set capabilities operation
    929     //
    930     case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
    931       Entry->Capabilities = Capabilities;
    932       break;
    933     }
    934     Link = Link->ForwardLink;
    935   }
    936 
    937   //
    938   // Cleanup
    939   //
    940   Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
    941 
    942 Done:
    943   DEBUG ((DEBUG_GCD, "  Status = %r\n", Status));
    944 
    945   if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
    946     CoreReleaseGcdMemoryLock ();
    947     CoreDumpGcdMemorySpaceMap (FALSE);
    948   }
    949   if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
    950     CoreReleaseGcdIoLock ();
    951     CoreDumpGcdIoSpaceMap (FALSE);
    952   }
    953 
    954   return Status;
    955 }
    956 
    957 
    958 /**
    959   Check whether an entry could be used to allocate space.
    960 
    961   @param  Operation              Allocate memory or IO
    962   @param  Entry                  The entry to be tested
    963   @param  GcdMemoryType          The desired memory type
    964   @param  GcdIoType              The desired IO type
    965 
    966   @retval EFI_NOT_FOUND          The memory type does not match or there's an
    967                                  image handle on the entry.
    968   @retval EFI_UNSUPPORTED        The operation unsupported.
    969   @retval EFI_SUCCESS            It's ok for this entry to be used to allocate
    970                                  space.
    971 
    972 **/
    973 EFI_STATUS
    974 CoreAllocateSpaceCheckEntry (
    975   IN UINTN                Operation,
    976   IN EFI_GCD_MAP_ENTRY    *Entry,
    977   IN EFI_GCD_MEMORY_TYPE  GcdMemoryType,
    978   IN EFI_GCD_IO_TYPE      GcdIoType
    979   )
    980 {
    981   if (Entry->ImageHandle != NULL) {
    982     return EFI_NOT_FOUND;
    983   }
    984   switch (Operation) {
    985   case GCD_ALLOCATE_MEMORY_OPERATION:
    986     if (Entry->GcdMemoryType != GcdMemoryType) {
    987       return EFI_NOT_FOUND;
    988     }
    989     break;
    990   case GCD_ALLOCATE_IO_OPERATION:
    991     if (Entry->GcdIoType != GcdIoType) {
    992       return EFI_NOT_FOUND;
    993     }
    994     break;
    995   default:
    996     return EFI_UNSUPPORTED;
    997   }
    998   return EFI_SUCCESS;
    999 }
   1000 
   1001 
   1002 /**
   1003   Allocate space on specified address and length.
   1004 
   1005   @param  Operation              The type of operation (memory or IO)
   1006   @param  GcdAllocateType        The type of allocate operation
   1007   @param  GcdMemoryType          The desired memory type
   1008   @param  GcdIoType              The desired IO type
   1009   @param  Alignment              Align with 2^Alignment
   1010   @param  Length                 Length to allocate
   1011   @param  BaseAddress            Base address to allocate
   1012   @param  ImageHandle            The image handle consume the allocated space.
   1013   @param  DeviceHandle           The device handle consume the allocated space.
   1014 
   1015   @retval EFI_INVALID_PARAMETER  Invalid parameter.
   1016   @retval EFI_NOT_FOUND          No descriptor for the desired space exists.
   1017   @retval EFI_SUCCESS            Space successfully allocated.
   1018 
   1019 **/
   1020 EFI_STATUS
   1021 CoreAllocateSpace (
   1022   IN     UINTN                  Operation,
   1023   IN     EFI_GCD_ALLOCATE_TYPE  GcdAllocateType,
   1024   IN     EFI_GCD_MEMORY_TYPE    GcdMemoryType,
   1025   IN     EFI_GCD_IO_TYPE        GcdIoType,
   1026   IN     UINTN                  Alignment,
   1027   IN     UINT64                 Length,
   1028   IN OUT EFI_PHYSICAL_ADDRESS   *BaseAddress,
   1029   IN     EFI_HANDLE             ImageHandle,
   1030   IN     EFI_HANDLE             DeviceHandle OPTIONAL
   1031   )
   1032 {
   1033   EFI_STATUS            Status;
   1034   EFI_PHYSICAL_ADDRESS  AlignmentMask;
   1035   EFI_PHYSICAL_ADDRESS  MaxAddress;
   1036   LIST_ENTRY            *Map;
   1037   LIST_ENTRY            *Link;
   1038   LIST_ENTRY            *SubLink;
   1039   EFI_GCD_MAP_ENTRY     *Entry;
   1040   EFI_GCD_MAP_ENTRY     *TopEntry;
   1041   EFI_GCD_MAP_ENTRY     *BottomEntry;
   1042   LIST_ENTRY            *StartLink;
   1043   LIST_ENTRY            *EndLink;
   1044   BOOLEAN               Found;
   1045 
   1046   //
   1047   // Make sure parameters are valid
   1048   //
   1049   if ((UINT32)GcdAllocateType >= EfiGcdMaxAllocateType) {
   1050     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
   1051     return EFI_INVALID_PARAMETER;
   1052   }
   1053   if ((UINT32)GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
   1054     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
   1055     return EFI_INVALID_PARAMETER;
   1056   }
   1057   if ((UINT32)GcdIoType >= EfiGcdIoTypeMaximum) {
   1058     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
   1059     return EFI_INVALID_PARAMETER;
   1060   }
   1061   if (BaseAddress == NULL) {
   1062     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
   1063     return EFI_INVALID_PARAMETER;
   1064   }
   1065   if (ImageHandle == NULL) {
   1066     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
   1067     return EFI_INVALID_PARAMETER;
   1068   }
   1069   if (Alignment >= 64) {
   1070     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_NOT_FOUND));
   1071     return EFI_NOT_FOUND;
   1072   }
   1073   if (Length == 0) {
   1074     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
   1075     return EFI_INVALID_PARAMETER;
   1076   }
   1077 
   1078   Map = NULL;
   1079   if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
   1080     CoreAcquireGcdMemoryLock ();
   1081     Map = &mGcdMemorySpaceMap;
   1082   } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
   1083     CoreAcquireGcdIoLock ();
   1084     Map = &mGcdIoSpaceMap;
   1085   } else {
   1086     ASSERT (FALSE);
   1087   }
   1088 
   1089   Found     = FALSE;
   1090   StartLink = NULL;
   1091   EndLink   = NULL;
   1092   //
   1093   // Compute alignment bit mask
   1094   //
   1095   AlignmentMask = LShiftU64 (1, Alignment) - 1;
   1096 
   1097   if (GcdAllocateType == EfiGcdAllocateAddress) {
   1098     //
   1099     // Verify that the BaseAddress passed in is aligned correctly
   1100     //
   1101     if ((*BaseAddress & AlignmentMask) != 0) {
   1102       Status = EFI_NOT_FOUND;
   1103       goto Done;
   1104     }
   1105 
   1106     //
   1107     // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
   1108     //
   1109     Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
   1110     if (EFI_ERROR (Status)) {
   1111       Status = EFI_NOT_FOUND;
   1112       goto Done;
   1113     }
   1114     ASSERT (StartLink != NULL && EndLink != NULL);
   1115 
   1116     //
   1117     // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
   1118     //
   1119     Link = StartLink;
   1120     while (Link != EndLink->ForwardLink) {
   1121       Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1122       Link = Link->ForwardLink;
   1123       Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
   1124       if (EFI_ERROR (Status)) {
   1125         goto Done;
   1126       }
   1127     }
   1128     Found = TRUE;
   1129   } else {
   1130 
   1131     Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1132 
   1133     //
   1134     // Compute the maximum address to use in the search algorithm
   1135     //
   1136     if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp ||
   1137         GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown     ) {
   1138       MaxAddress = *BaseAddress;
   1139     } else {
   1140       MaxAddress = Entry->EndAddress;
   1141     }
   1142 
   1143     //
   1144     // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
   1145     //
   1146     if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
   1147         GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
   1148       Link = Map->BackLink;
   1149     } else {
   1150       Link = Map->ForwardLink;
   1151     }
   1152     while (Link != Map) {
   1153       Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1154 
   1155       if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
   1156           GcdAllocateType == EfiGcdAllocateAnySearchTopDown           ) {
   1157         Link = Link->BackLink;
   1158       } else {
   1159         Link = Link->ForwardLink;
   1160       }
   1161 
   1162       Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
   1163       if (EFI_ERROR (Status)) {
   1164         continue;
   1165       }
   1166 
   1167       if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
   1168           GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
   1169         if ((Entry->BaseAddress + Length) > MaxAddress) {
   1170           continue;
   1171         }
   1172         if (Length > (Entry->EndAddress + 1)) {
   1173           Status = EFI_NOT_FOUND;
   1174           goto Done;
   1175         }
   1176         if (Entry->EndAddress > MaxAddress) {
   1177           *BaseAddress = MaxAddress;
   1178         } else {
   1179           *BaseAddress = Entry->EndAddress;
   1180         }
   1181         *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
   1182       } else {
   1183         *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
   1184         if ((*BaseAddress + Length - 1) > MaxAddress) {
   1185           Status = EFI_NOT_FOUND;
   1186           goto Done;
   1187         }
   1188       }
   1189 
   1190       //
   1191       // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
   1192       //
   1193       Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
   1194       if (EFI_ERROR (Status)) {
   1195         Status = EFI_NOT_FOUND;
   1196         goto Done;
   1197       }
   1198       ASSERT (StartLink != NULL && EndLink != NULL);
   1199 
   1200       Link = StartLink;
   1201       //
   1202       // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
   1203       //
   1204       Found = TRUE;
   1205       SubLink = StartLink;
   1206       while (SubLink != EndLink->ForwardLink) {
   1207         Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1208         Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
   1209         if (EFI_ERROR (Status)) {
   1210           Link = SubLink;
   1211           Found = FALSE;
   1212           break;
   1213         }
   1214         SubLink = SubLink->ForwardLink;
   1215       }
   1216       if (Found) {
   1217         break;
   1218       }
   1219     }
   1220   }
   1221   if (!Found) {
   1222     Status = EFI_NOT_FOUND;
   1223     goto Done;
   1224   }
   1225 
   1226   //
   1227   // Allocate work space to perform this operation
   1228   //
   1229   Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
   1230   if (EFI_ERROR (Status)) {
   1231     Status = EFI_OUT_OF_RESOURCES;
   1232     goto Done;
   1233   }
   1234   ASSERT (TopEntry != NULL && BottomEntry != NULL);
   1235 
   1236   //
   1237   // Convert/Insert the list of descriptors from StartLink to EndLink
   1238   //
   1239   Link = StartLink;
   1240   while (Link != EndLink->ForwardLink) {
   1241     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1242     CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
   1243     Entry->ImageHandle  = ImageHandle;
   1244     Entry->DeviceHandle = DeviceHandle;
   1245     Link = Link->ForwardLink;
   1246   }
   1247 
   1248   //
   1249   // Cleanup
   1250   //
   1251   Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
   1252 
   1253 Done:
   1254   DEBUG ((DEBUG_GCD, "  Status = %r", Status));
   1255   if (!EFI_ERROR (Status)) {
   1256     DEBUG ((DEBUG_GCD, "  (BaseAddress = %016lx)", *BaseAddress));
   1257   }
   1258   DEBUG ((DEBUG_GCD, "\n"));
   1259 
   1260   if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
   1261     CoreReleaseGcdMemoryLock ();
   1262     CoreDumpGcdMemorySpaceMap (FALSE);
   1263   }
   1264   if ((Operation & GCD_IO_SPACE_OPERATION) !=0) {
   1265     CoreReleaseGcdIoLock ();
   1266     CoreDumpGcdIoSpaceMap (FALSE);
   1267   }
   1268 
   1269   return Status;
   1270 }
   1271 
   1272 
   1273 /**
   1274   Add a segment of memory to GCD map.
   1275 
   1276   @param  GcdMemoryType          Memory type of the segment.
   1277   @param  BaseAddress            Base address of the segment.
   1278   @param  Length                 Length of the segment.
   1279   @param  Capabilities           alterable attributes of the segment.
   1280 
   1281   @retval EFI_INVALID_PARAMETER  Invalid parameters.
   1282   @retval EFI_SUCCESS            Successfully add a segment of memory space.
   1283 
   1284 **/
   1285 EFI_STATUS
   1286 CoreInternalAddMemorySpace (
   1287   IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,
   1288   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1289   IN UINT64                Length,
   1290   IN UINT64                Capabilities
   1291   )
   1292 {
   1293   DEBUG ((DEBUG_GCD, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
   1294   DEBUG ((DEBUG_GCD, "  GcdMemoryType   = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
   1295   DEBUG ((DEBUG_GCD, "  Capabilities    = %016lx\n", Capabilities));
   1296 
   1297   //
   1298   // Make sure parameters are valid
   1299   //
   1300   if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
   1301     return EFI_INVALID_PARAMETER;
   1302   }
   1303 
   1304   return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
   1305 }
   1306 
   1307 //
   1308 // GCD Core Services
   1309 //
   1310 
   1311 /**
   1312   Allocates nonexistent memory, reserved memory, system memory, or memorymapped
   1313   I/O resources from the global coherency domain of the processor.
   1314 
   1315   @param  GcdAllocateType        The type of allocate operation
   1316   @param  GcdMemoryType          The desired memory type
   1317   @param  Alignment              Align with 2^Alignment
   1318   @param  Length                 Length to allocate
   1319   @param  BaseAddress            Base address to allocate
   1320   @param  ImageHandle            The image handle consume the allocated space.
   1321   @param  DeviceHandle           The device handle consume the allocated space.
   1322 
   1323   @retval EFI_INVALID_PARAMETER  Invalid parameter.
   1324   @retval EFI_NOT_FOUND          No descriptor contains the desired space.
   1325   @retval EFI_SUCCESS            Memory space successfully allocated.
   1326 
   1327 **/
   1328 EFI_STATUS
   1329 EFIAPI
   1330 CoreAllocateMemorySpace (
   1331   IN     EFI_GCD_ALLOCATE_TYPE  GcdAllocateType,
   1332   IN     EFI_GCD_MEMORY_TYPE    GcdMemoryType,
   1333   IN     UINTN                  Alignment,
   1334   IN     UINT64                 Length,
   1335   IN OUT EFI_PHYSICAL_ADDRESS   *BaseAddress,
   1336   IN     EFI_HANDLE             ImageHandle,
   1337   IN     EFI_HANDLE             DeviceHandle OPTIONAL
   1338   )
   1339 {
   1340   DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
   1341   DEBUG ((DEBUG_GCD, "  GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
   1342   DEBUG ((DEBUG_GCD, "  GcdMemoryType   = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
   1343   DEBUG ((DEBUG_GCD, "  Alignment       = %016lx\n", LShiftU64 (1, Alignment)));
   1344   DEBUG ((DEBUG_GCD, "  ImageHandle     = %p\n", ImageHandle));
   1345   DEBUG ((DEBUG_GCD, "  DeviceHandle    = %p\n", DeviceHandle));
   1346 
   1347   return CoreAllocateSpace (
   1348            GCD_ALLOCATE_MEMORY_OPERATION,
   1349            GcdAllocateType,
   1350            GcdMemoryType,
   1351            (EFI_GCD_IO_TYPE) 0,
   1352            Alignment,
   1353            Length,
   1354            BaseAddress,
   1355            ImageHandle,
   1356            DeviceHandle
   1357            );
   1358 }
   1359 
   1360 
   1361 /**
   1362   Adds reserved memory, system memory, or memory-mapped I/O resources to the
   1363   global coherency domain of the processor.
   1364 
   1365   @param  GcdMemoryType          Memory type of the memory space.
   1366   @param  BaseAddress            Base address of the memory space.
   1367   @param  Length                 Length of the memory space.
   1368   @param  Capabilities           alterable attributes of the memory space.
   1369 
   1370   @retval EFI_SUCCESS            Merged this memory space into GCD map.
   1371 
   1372 **/
   1373 EFI_STATUS
   1374 EFIAPI
   1375 CoreAddMemorySpace (
   1376   IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,
   1377   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1378   IN UINT64                Length,
   1379   IN UINT64                Capabilities
   1380   )
   1381 {
   1382   EFI_STATUS            Status;
   1383   EFI_PHYSICAL_ADDRESS  PageBaseAddress;
   1384   UINT64                PageLength;
   1385 
   1386   Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);
   1387 
   1388   if (!EFI_ERROR (Status) && ((GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
   1389 
   1390     PageBaseAddress = PageAlignAddress (BaseAddress);
   1391     PageLength      = PageAlignLength (BaseAddress + Length - PageBaseAddress);
   1392 
   1393     Status = CoreAllocateMemorySpace (
   1394                EfiGcdAllocateAddress,
   1395                GcdMemoryType,
   1396                EFI_PAGE_SHIFT,
   1397                PageLength,
   1398                &PageBaseAddress,
   1399                gDxeCoreImageHandle,
   1400                NULL
   1401                );
   1402 
   1403     if (!EFI_ERROR (Status)) {
   1404       CoreAddMemoryDescriptor (
   1405         EfiConventionalMemory,
   1406         PageBaseAddress,
   1407         RShiftU64 (PageLength, EFI_PAGE_SHIFT),
   1408         Capabilities
   1409         );
   1410     } else {
   1411       for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
   1412         Status = CoreAllocateMemorySpace (
   1413                    EfiGcdAllocateAddress,
   1414                    GcdMemoryType,
   1415                    EFI_PAGE_SHIFT,
   1416                    EFI_PAGE_SIZE,
   1417                    &PageBaseAddress,
   1418                    gDxeCoreImageHandle,
   1419                    NULL
   1420                    );
   1421 
   1422         if (!EFI_ERROR (Status)) {
   1423           CoreAddMemoryDescriptor (
   1424             EfiConventionalMemory,
   1425             PageBaseAddress,
   1426             1,
   1427             Capabilities
   1428             );
   1429         }
   1430       }
   1431     }
   1432   }
   1433   return Status;
   1434 }
   1435 
   1436 
   1437 /**
   1438   Frees nonexistent memory, reserved memory, system memory, or memory-mapped
   1439   I/O resources from the global coherency domain of the processor.
   1440 
   1441   @param  BaseAddress            Base address of the memory space.
   1442   @param  Length                 Length of the memory space.
   1443 
   1444   @retval EFI_SUCCESS            Space successfully freed.
   1445 
   1446 **/
   1447 EFI_STATUS
   1448 EFIAPI
   1449 CoreFreeMemorySpace (
   1450   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1451   IN UINT64                Length
   1452   )
   1453 {
   1454   DEBUG ((DEBUG_GCD, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
   1455 
   1456   return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
   1457 }
   1458 
   1459 
   1460 /**
   1461   Removes reserved memory, system memory, or memory-mapped I/O resources from
   1462   the global coherency domain of the processor.
   1463 
   1464   @param  BaseAddress            Base address of the memory space.
   1465   @param  Length                 Length of the memory space.
   1466 
   1467   @retval EFI_SUCCESS            Successfully remove a segment of memory space.
   1468 
   1469 **/
   1470 EFI_STATUS
   1471 EFIAPI
   1472 CoreRemoveMemorySpace (
   1473   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1474   IN UINT64                Length
   1475   )
   1476 {
   1477   DEBUG ((DEBUG_GCD, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
   1478 
   1479   return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
   1480 }
   1481 
   1482 
   1483 /**
   1484   Build a memory descriptor according to an entry.
   1485 
   1486   @param  Descriptor             The descriptor to be built
   1487   @param  Entry                  According to this entry
   1488 
   1489 **/
   1490 VOID
   1491 BuildMemoryDescriptor (
   1492   IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor,
   1493   IN EFI_GCD_MAP_ENTRY                *Entry
   1494   )
   1495 {
   1496   Descriptor->BaseAddress   = Entry->BaseAddress;
   1497   Descriptor->Length        = Entry->EndAddress - Entry->BaseAddress + 1;
   1498   Descriptor->Capabilities  = Entry->Capabilities;
   1499   Descriptor->Attributes    = Entry->Attributes;
   1500   Descriptor->GcdMemoryType = Entry->GcdMemoryType;
   1501   Descriptor->ImageHandle   = Entry->ImageHandle;
   1502   Descriptor->DeviceHandle  = Entry->DeviceHandle;
   1503 }
   1504 
   1505 
   1506 /**
   1507   Retrieves the descriptor for a memory region containing a specified address.
   1508 
   1509   @param  BaseAddress            Specified start address
   1510   @param  Descriptor             Specified length
   1511 
   1512   @retval EFI_INVALID_PARAMETER  Invalid parameter
   1513   @retval EFI_SUCCESS            Successfully get memory space descriptor.
   1514 
   1515 **/
   1516 EFI_STATUS
   1517 EFIAPI
   1518 CoreGetMemorySpaceDescriptor (
   1519   IN  EFI_PHYSICAL_ADDRESS             BaseAddress,
   1520   OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor
   1521   )
   1522 {
   1523   EFI_STATUS         Status;
   1524   LIST_ENTRY         *StartLink;
   1525   LIST_ENTRY         *EndLink;
   1526   EFI_GCD_MAP_ENTRY  *Entry;
   1527 
   1528   //
   1529   // Make sure parameters are valid
   1530   //
   1531   if (Descriptor == NULL) {
   1532     return EFI_INVALID_PARAMETER;
   1533   }
   1534 
   1535   CoreAcquireGcdMemoryLock ();
   1536 
   1537   //
   1538   // Search for the list of descriptors that contain BaseAddress
   1539   //
   1540   Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);
   1541   if (EFI_ERROR (Status)) {
   1542     Status = EFI_NOT_FOUND;
   1543   } else {
   1544     ASSERT (StartLink != NULL && EndLink != NULL);
   1545     //
   1546     // Copy the contents of the found descriptor into Descriptor
   1547     //
   1548     Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1549     BuildMemoryDescriptor (Descriptor, Entry);
   1550   }
   1551 
   1552   CoreReleaseGcdMemoryLock ();
   1553 
   1554   return Status;
   1555 }
   1556 
   1557 
   1558 /**
   1559   Modifies the attributes for a memory region in the global coherency domain of the
   1560   processor.
   1561 
   1562   @param  BaseAddress            Specified start address
   1563   @param  Length                 Specified length
   1564   @param  Attributes             Specified attributes
   1565 
   1566   @retval EFI_SUCCESS           The attributes were set for the memory region.
   1567   @retval EFI_INVALID_PARAMETER Length is zero.
   1568   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
   1569                                 resource range specified by BaseAddress and Length.
   1570   @retval EFI_UNSUPPORTED       The bit mask of attributes is not support for the memory resource
   1571                                 range specified by BaseAddress and Length.
   1572   @retval EFI_ACCESS_DEFINED    The attributes for the memory resource range specified by
   1573                                 BaseAddress and Length cannot be modified.
   1574   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
   1575                                 the memory resource range.
   1576   @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
   1577                                 not available yet.
   1578 
   1579 **/
   1580 EFI_STATUS
   1581 EFIAPI
   1582 CoreSetMemorySpaceAttributes (
   1583   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1584   IN UINT64                Length,
   1585   IN UINT64                Attributes
   1586   )
   1587 {
   1588   DEBUG ((DEBUG_GCD, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
   1589   DEBUG ((DEBUG_GCD, "  Attributes  = %016lx\n", Attributes));
   1590 
   1591   return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, Attributes);
   1592 }
   1593 
   1594 
   1595 /**
   1596   Modifies the capabilities for a memory region in the global coherency domain of the
   1597   processor.
   1598 
   1599   @param  BaseAddress      The physical address that is the start address of a memory region.
   1600   @param  Length           The size in bytes of the memory region.
   1601   @param  Capabilities     The bit mask of capabilities that the memory region supports.
   1602 
   1603   @retval EFI_SUCCESS           The capabilities were set for the memory region.
   1604   @retval EFI_INVALID_PARAMETER Length is zero.
   1605   @retval EFI_UNSUPPORTED       The capabilities specified by Capabilities do not include the
   1606                                 memory region attributes currently in use.
   1607   @retval EFI_ACCESS_DENIED     The capabilities for the memory resource range specified by
   1608                                 BaseAddress and Length cannot be modified.
   1609   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the capabilities
   1610                                 of the memory resource range.
   1611 **/
   1612 EFI_STATUS
   1613 EFIAPI
   1614 CoreSetMemorySpaceCapabilities (
   1615   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1616   IN UINT64                Length,
   1617   IN UINT64                Capabilities
   1618   )
   1619 {
   1620   EFI_STATUS    Status;
   1621 
   1622   DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
   1623   DEBUG ((DEBUG_GCD, "  Capabilities  = %016lx\n", Capabilities));
   1624 
   1625   Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
   1626   if (!EFI_ERROR(Status)) {
   1627     CoreUpdateMemoryAttributes(BaseAddress, RShiftU64(Length, EFI_PAGE_SHIFT), Capabilities);
   1628   }
   1629 
   1630   return Status;
   1631 }
   1632 
   1633 
   1634 /**
   1635   Returns a map of the memory resources in the global coherency domain of the
   1636   processor.
   1637 
   1638   @param  NumberOfDescriptors    Number of descriptors.
   1639   @param  MemorySpaceMap         Descriptor array
   1640 
   1641   @retval EFI_INVALID_PARAMETER  Invalid parameter
   1642   @retval EFI_OUT_OF_RESOURCES   No enough buffer to allocate
   1643   @retval EFI_SUCCESS            Successfully get memory space map.
   1644 
   1645 **/
   1646 EFI_STATUS
   1647 EFIAPI
   1648 CoreGetMemorySpaceMap (
   1649   OUT UINTN                            *NumberOfDescriptors,
   1650   OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  **MemorySpaceMap
   1651   )
   1652 {
   1653   EFI_STATUS                       Status;
   1654   LIST_ENTRY                       *Link;
   1655   EFI_GCD_MAP_ENTRY                *Entry;
   1656   EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor;
   1657 
   1658   //
   1659   // Make sure parameters are valid
   1660   //
   1661   if (NumberOfDescriptors == NULL) {
   1662     return EFI_INVALID_PARAMETER;
   1663   }
   1664   if (MemorySpaceMap == NULL) {
   1665     return EFI_INVALID_PARAMETER;
   1666   }
   1667 
   1668   CoreAcquireGcdMemoryLock ();
   1669 
   1670   //
   1671   // Count the number of descriptors
   1672   //
   1673   *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);
   1674 
   1675   //
   1676   // Allocate the MemorySpaceMap
   1677   //
   1678   *MemorySpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
   1679   if (*MemorySpaceMap == NULL) {
   1680     Status = EFI_OUT_OF_RESOURCES;
   1681     goto Done;
   1682   }
   1683 
   1684   //
   1685   // Fill in the MemorySpaceMap
   1686   //
   1687   Descriptor = *MemorySpaceMap;
   1688   Link = mGcdMemorySpaceMap.ForwardLink;
   1689   while (Link != &mGcdMemorySpaceMap) {
   1690     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1691     BuildMemoryDescriptor (Descriptor, Entry);
   1692     Descriptor++;
   1693     Link = Link->ForwardLink;
   1694   }
   1695   Status = EFI_SUCCESS;
   1696 
   1697 Done:
   1698   CoreReleaseGcdMemoryLock ();
   1699   return Status;
   1700 }
   1701 
   1702 
   1703 /**
   1704   Adds reserved I/O or I/O resources to the global coherency domain of the processor.
   1705 
   1706   @param  GcdIoType              IO type of the segment.
   1707   @param  BaseAddress            Base address of the segment.
   1708   @param  Length                 Length of the segment.
   1709 
   1710   @retval EFI_SUCCESS            Merged this segment into GCD map.
   1711   @retval EFI_INVALID_PARAMETER  Parameter not valid
   1712 
   1713 **/
   1714 EFI_STATUS
   1715 EFIAPI
   1716 CoreAddIoSpace (
   1717   IN EFI_GCD_IO_TYPE       GcdIoType,
   1718   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1719   IN UINT64                Length
   1720   )
   1721 {
   1722   DEBUG ((DEBUG_GCD, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
   1723   DEBUG ((DEBUG_GCD, "  GcdIoType    = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
   1724 
   1725   //
   1726   // Make sure parameters are valid
   1727   //
   1728   if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) {
   1729     return EFI_INVALID_PARAMETER;
   1730   }
   1731   return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, GcdIoType, BaseAddress, Length, 0, 0);
   1732 }
   1733 
   1734 
   1735 /**
   1736   Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
   1737   domain of the processor.
   1738 
   1739   @param  GcdAllocateType        The type of allocate operation
   1740   @param  GcdIoType              The desired IO type
   1741   @param  Alignment              Align with 2^Alignment
   1742   @param  Length                 Length to allocate
   1743   @param  BaseAddress            Base address to allocate
   1744   @param  ImageHandle            The image handle consume the allocated space.
   1745   @param  DeviceHandle           The device handle consume the allocated space.
   1746 
   1747   @retval EFI_INVALID_PARAMETER  Invalid parameter.
   1748   @retval EFI_NOT_FOUND          No descriptor contains the desired space.
   1749   @retval EFI_SUCCESS            IO space successfully allocated.
   1750 
   1751 **/
   1752 EFI_STATUS
   1753 EFIAPI
   1754 CoreAllocateIoSpace (
   1755   IN     EFI_GCD_ALLOCATE_TYPE  GcdAllocateType,
   1756   IN     EFI_GCD_IO_TYPE        GcdIoType,
   1757   IN     UINTN                  Alignment,
   1758   IN     UINT64                 Length,
   1759   IN OUT EFI_PHYSICAL_ADDRESS   *BaseAddress,
   1760   IN     EFI_HANDLE             ImageHandle,
   1761   IN     EFI_HANDLE             DeviceHandle OPTIONAL
   1762   )
   1763 {
   1764   DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
   1765   DEBUG ((DEBUG_GCD, "  GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
   1766   DEBUG ((DEBUG_GCD, "  GcdIoType       = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
   1767   DEBUG ((DEBUG_GCD, "  Alignment       = %016lx\n", LShiftU64 (1, Alignment)));
   1768   DEBUG ((DEBUG_GCD, "  ImageHandle     = %p\n", ImageHandle));
   1769   DEBUG ((DEBUG_GCD, "  DeviceHandle    = %p\n", DeviceHandle));
   1770 
   1771   return CoreAllocateSpace (
   1772            GCD_ALLOCATE_IO_OPERATION,
   1773            GcdAllocateType,
   1774            (EFI_GCD_MEMORY_TYPE) 0,
   1775            GcdIoType,
   1776            Alignment,
   1777            Length,
   1778            BaseAddress,
   1779            ImageHandle,
   1780            DeviceHandle
   1781            );
   1782 }
   1783 
   1784 
   1785 /**
   1786   Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
   1787   domain of the processor.
   1788 
   1789   @param  BaseAddress            Base address of the segment.
   1790   @param  Length                 Length of the segment.
   1791 
   1792   @retval EFI_SUCCESS            Space successfully freed.
   1793 
   1794 **/
   1795 EFI_STATUS
   1796 EFIAPI
   1797 CoreFreeIoSpace (
   1798   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1799   IN UINT64                Length
   1800   )
   1801 {
   1802   DEBUG ((DEBUG_GCD, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
   1803 
   1804   return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
   1805 }
   1806 
   1807 
   1808 /**
   1809   Removes reserved I/O or I/O resources from the global coherency domain of the
   1810   processor.
   1811 
   1812   @param  BaseAddress            Base address of the segment.
   1813   @param  Length                 Length of the segment.
   1814 
   1815   @retval EFI_SUCCESS            Successfully removed a segment of IO space.
   1816 
   1817 **/
   1818 EFI_STATUS
   1819 EFIAPI
   1820 CoreRemoveIoSpace (
   1821   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
   1822   IN UINT64                Length
   1823   )
   1824 {
   1825   DEBUG ((DEBUG_GCD, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
   1826 
   1827   return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
   1828 }
   1829 
   1830 
   1831 /**
   1832   Build a IO descriptor according to an entry.
   1833 
   1834   @param  Descriptor             The descriptor to be built
   1835   @param  Entry                  According to this entry
   1836 
   1837 **/
   1838 VOID
   1839 BuildIoDescriptor (
   1840   IN EFI_GCD_IO_SPACE_DESCRIPTOR  *Descriptor,
   1841   IN EFI_GCD_MAP_ENTRY            *Entry
   1842   )
   1843 {
   1844   Descriptor->BaseAddress  = Entry->BaseAddress;
   1845   Descriptor->Length       = Entry->EndAddress - Entry->BaseAddress + 1;
   1846   Descriptor->GcdIoType    = Entry->GcdIoType;
   1847   Descriptor->ImageHandle  = Entry->ImageHandle;
   1848   Descriptor->DeviceHandle = Entry->DeviceHandle;
   1849 }
   1850 
   1851 
   1852 /**
   1853   Retrieves the descriptor for an I/O region containing a specified address.
   1854 
   1855   @param  BaseAddress            Specified start address
   1856   @param  Descriptor             Specified length
   1857 
   1858   @retval EFI_INVALID_PARAMETER  Descriptor is NULL.
   1859   @retval EFI_SUCCESS            Successfully get the IO space descriptor.
   1860 
   1861 **/
   1862 EFI_STATUS
   1863 EFIAPI
   1864 CoreGetIoSpaceDescriptor (
   1865   IN  EFI_PHYSICAL_ADDRESS         BaseAddress,
   1866   OUT EFI_GCD_IO_SPACE_DESCRIPTOR  *Descriptor
   1867   )
   1868 {
   1869   EFI_STATUS         Status;
   1870   LIST_ENTRY         *StartLink;
   1871   LIST_ENTRY         *EndLink;
   1872   EFI_GCD_MAP_ENTRY  *Entry;
   1873 
   1874   //
   1875   // Make sure parameters are valid
   1876   //
   1877   if (Descriptor == NULL) {
   1878     return EFI_INVALID_PARAMETER;
   1879   }
   1880 
   1881   CoreAcquireGcdIoLock ();
   1882 
   1883   //
   1884   // Search for the list of descriptors that contain BaseAddress
   1885   //
   1886   Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);
   1887   if (EFI_ERROR (Status)) {
   1888     Status = EFI_NOT_FOUND;
   1889   } else {
   1890     ASSERT (StartLink != NULL && EndLink != NULL);
   1891     //
   1892     // Copy the contents of the found descriptor into Descriptor
   1893     //
   1894     Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1895     BuildIoDescriptor (Descriptor, Entry);
   1896   }
   1897 
   1898   CoreReleaseGcdIoLock ();
   1899 
   1900   return Status;
   1901 }
   1902 
   1903 
   1904 /**
   1905   Returns a map of the I/O resources in the global coherency domain of the processor.
   1906 
   1907   @param  NumberOfDescriptors    Number of descriptors.
   1908   @param  IoSpaceMap             Descriptor array
   1909 
   1910   @retval EFI_INVALID_PARAMETER  Invalid parameter
   1911   @retval EFI_OUT_OF_RESOURCES   No enough buffer to allocate
   1912   @retval EFI_SUCCESS            Successfully get IO space map.
   1913 
   1914 **/
   1915 EFI_STATUS
   1916 EFIAPI
   1917 CoreGetIoSpaceMap (
   1918   OUT UINTN                        *NumberOfDescriptors,
   1919   OUT EFI_GCD_IO_SPACE_DESCRIPTOR  **IoSpaceMap
   1920   )
   1921 {
   1922   EFI_STATUS                   Status;
   1923   LIST_ENTRY                   *Link;
   1924   EFI_GCD_MAP_ENTRY            *Entry;
   1925   EFI_GCD_IO_SPACE_DESCRIPTOR  *Descriptor;
   1926 
   1927   //
   1928   // Make sure parameters are valid
   1929   //
   1930   if (NumberOfDescriptors == NULL) {
   1931     return EFI_INVALID_PARAMETER;
   1932   }
   1933   if (IoSpaceMap == NULL) {
   1934     return EFI_INVALID_PARAMETER;
   1935   }
   1936 
   1937   CoreAcquireGcdIoLock ();
   1938 
   1939   //
   1940   // Count the number of descriptors
   1941   //
   1942   *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);
   1943 
   1944   //
   1945   // Allocate the IoSpaceMap
   1946   //
   1947   *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));
   1948   if (*IoSpaceMap == NULL) {
   1949     Status = EFI_OUT_OF_RESOURCES;
   1950     goto Done;
   1951   }
   1952 
   1953   //
   1954   // Fill in the IoSpaceMap
   1955   //
   1956   Descriptor = *IoSpaceMap;
   1957   Link = mGcdIoSpaceMap.ForwardLink;
   1958   while (Link != &mGcdIoSpaceMap) {
   1959     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
   1960     BuildIoDescriptor (Descriptor, Entry);
   1961     Descriptor++;
   1962     Link = Link->ForwardLink;
   1963   }
   1964   Status = EFI_SUCCESS;
   1965 
   1966 Done:
   1967   CoreReleaseGcdIoLock ();
   1968   return Status;
   1969 }
   1970 
   1971 
   1972 /**
   1973   Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
   1974   capabilities mask
   1975 
   1976   @param  GcdMemoryType          Type of resource in the GCD memory map.
   1977   @param  Attributes             The attribute mask in the Resource Descriptor
   1978                                  HOB.
   1979 
   1980   @return The capabilities mask for an EFI Memory Descriptor.
   1981 
   1982 **/
   1983 UINT64
   1984 CoreConvertResourceDescriptorHobAttributesToCapabilities (
   1985   EFI_GCD_MEMORY_TYPE  GcdMemoryType,
   1986   UINT64               Attributes
   1987   )
   1988 {
   1989   UINT64                          Capabilities;
   1990   GCD_ATTRIBUTE_CONVERSION_ENTRY  *Conversion;
   1991 
   1992   //
   1993   // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
   1994   //
   1995   for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {
   1996     if (Conversion->Memory || ((GcdMemoryType != EfiGcdMemoryTypeSystemMemory) && (GcdMemoryType != EfiGcdMemoryTypeMoreReliable))) {
   1997       if (Attributes & Conversion->Attribute) {
   1998         Capabilities |= Conversion->Capability;
   1999       }
   2000     }
   2001   }
   2002 
   2003   return Capabilities;
   2004 }
   2005 
   2006 /**
   2007   Calculate total memory bin size neeeded.
   2008 
   2009   @return The total memory bin size neeeded.
   2010 
   2011 **/
   2012 UINT64
   2013 CalculateTotalMemoryBinSizeNeeded (
   2014   VOID
   2015   )
   2016 {
   2017   UINTN     Index;
   2018   UINT64    TotalSize;
   2019 
   2020   //
   2021   // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
   2022   //
   2023   TotalSize = 0;
   2024   for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
   2025     TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);
   2026   }
   2027 
   2028   return TotalSize;
   2029 }
   2030 
   2031 /**
   2032   External function. Initializes memory services based on the memory
   2033   descriptor HOBs.  This function is responsible for priming the memory
   2034   map, so memory allocations and resource allocations can be made.
   2035   The first part of this function can not depend on any memory services
   2036   until at least one memory descriptor is provided to the memory services.
   2037 
   2038   @param  HobStart               The start address of the HOB.
   2039   @param  MemoryBaseAddress      Start address of memory region found to init DXE
   2040                                  core.
   2041   @param  MemoryLength           Length of memory region found to init DXE core.
   2042 
   2043   @retval EFI_SUCCESS            Memory services successfully initialized.
   2044 
   2045 **/
   2046 EFI_STATUS
   2047 CoreInitializeMemoryServices (
   2048   IN  VOID                  **HobStart,
   2049   OUT EFI_PHYSICAL_ADDRESS  *MemoryBaseAddress,
   2050   OUT UINT64                *MemoryLength
   2051   )
   2052 {
   2053   EFI_PEI_HOB_POINTERS               Hob;
   2054   EFI_MEMORY_TYPE_INFORMATION        *EfiMemoryTypeInformation;
   2055   UINTN                              DataSize;
   2056   BOOLEAN                            Found;
   2057   EFI_HOB_HANDOFF_INFO_TABLE         *PhitHob;
   2058   EFI_HOB_RESOURCE_DESCRIPTOR        *ResourceHob;
   2059   EFI_HOB_RESOURCE_DESCRIPTOR        *PhitResourceHob;
   2060   EFI_PHYSICAL_ADDRESS               BaseAddress;
   2061   UINT64                             Length;
   2062   UINT64                             Attributes;
   2063   UINT64                             Capabilities;
   2064   EFI_PHYSICAL_ADDRESS               TestedMemoryBaseAddress;
   2065   UINT64                             TestedMemoryLength;
   2066   EFI_PHYSICAL_ADDRESS               HighAddress;
   2067   EFI_HOB_GUID_TYPE                  *GuidHob;
   2068   UINT32                             ReservedCodePageNumber;
   2069   UINT64                             MinimalMemorySizeNeeded;
   2070 
   2071   //
   2072   // Point at the first HOB.  This must be the PHIT HOB.
   2073   //
   2074   Hob.Raw = *HobStart;
   2075   ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
   2076 
   2077   //
   2078   // Initialize the spin locks and maps in the memory services.
   2079   // Also fill in the memory services into the EFI Boot Services Table
   2080   //
   2081   CoreInitializePool ();
   2082 
   2083   //
   2084   // Initialize Local Variables
   2085   //
   2086   PhitResourceHob       = NULL;
   2087   ResourceHob           = NULL;
   2088   BaseAddress           = 0;
   2089   Length                = 0;
   2090   Attributes            = 0;
   2091 
   2092   //
   2093   // Cache the PHIT HOB for later use
   2094   //
   2095   PhitHob = Hob.HandoffInformationTable;
   2096 
   2097   if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
   2098   	ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
   2099   	ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
   2100 
   2101   	//
   2102   	// cache the Top address for loading modules at Fixed Address
   2103   	//
   2104     gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
   2105                                                                    + EFI_PAGES_TO_SIZE(ReservedCodePageNumber);
   2106   }
   2107   //
   2108   // See if a Memory Type Information HOB is available
   2109   //
   2110   GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
   2111   if (GuidHob != NULL) {
   2112     EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
   2113     DataSize                 = GET_GUID_HOB_DATA_SIZE (GuidHob);
   2114     if (EfiMemoryTypeInformation != NULL && DataSize > 0 && DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION)) {
   2115       CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);
   2116     }
   2117   }
   2118 
   2119   //
   2120   // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
   2121   //
   2122   MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
   2123 
   2124   //
   2125   // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
   2126   //
   2127   Found  = FALSE;
   2128   for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
   2129     //
   2130     // Skip all HOBs except Resource Descriptor HOBs
   2131     //
   2132     if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
   2133       continue;
   2134     }
   2135 
   2136     //
   2137     // Skip Resource Descriptor HOBs that do not describe tested system memory
   2138     //
   2139     ResourceHob = Hob.ResourceDescriptor;
   2140     if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
   2141       continue;
   2142     }
   2143     if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
   2144       continue;
   2145     }
   2146 
   2147     //
   2148     // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
   2149     //
   2150     if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {
   2151       continue;
   2152     }
   2153     if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
   2154       continue;
   2155     }
   2156 
   2157     //
   2158     // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
   2159     //
   2160     PhitResourceHob = ResourceHob;
   2161     Found = TRUE;
   2162 
   2163     //
   2164     // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB
   2165     //
   2166     Attributes  = PhitResourceHob->ResourceAttribute;
   2167     BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
   2168     Length      = PageAlignLength  (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
   2169     if (Length < MinimalMemorySizeNeeded) {
   2170       //
   2171       // If that range is not large enough to intialize the DXE Core, then
   2172       // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop
   2173       //
   2174       BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);
   2175       Length      = PageAlignLength  (PhitHob->EfiFreeMemoryTop - BaseAddress);
   2176       if (Length < MinimalMemorySizeNeeded) {
   2177         //
   2178         // If that range is not large enough to intialize the DXE Core, then
   2179         // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List
   2180         //
   2181         BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
   2182         Length      = PageAlignLength  ((UINT64)((UINTN)*HobStart - BaseAddress));
   2183       }
   2184     }
   2185     break;
   2186   }
   2187 
   2188   //
   2189   // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
   2190   //
   2191   ASSERT (Found);
   2192 
   2193   //
   2194   // Take the range in the resource descriptor HOB for the memory region described
   2195   // by the PHIT as higher priority if it is big enough. It can make the memory bin
   2196   // allocated to be at the same memory region with PHIT that has more better compatibility
   2197   // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.
   2198   //
   2199   if (Length < MinimalMemorySizeNeeded) {
   2200     //
   2201     // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
   2202     // region that is big enough to initialize the DXE core.  Always skip the PHIT Resource HOB.
   2203     // The max address must be within the physically addressible range for the processor.
   2204     //
   2205     HighAddress = MAX_ADDRESS;
   2206     for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
   2207       //
   2208       // Skip the Resource Descriptor HOB that contains the PHIT
   2209       //
   2210       if (Hob.ResourceDescriptor == PhitResourceHob) {
   2211         continue;
   2212       }
   2213       //
   2214       // Skip all HOBs except Resource Descriptor HOBs
   2215       //
   2216       if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
   2217         continue;
   2218       }
   2219 
   2220       //
   2221       // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ADDRESS
   2222       //
   2223       ResourceHob = Hob.ResourceDescriptor;
   2224       if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
   2225         continue;
   2226       }
   2227       if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
   2228         continue;
   2229       }
   2230       if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS) {
   2231         continue;
   2232       }
   2233 
   2234       //
   2235       // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB
   2236       //
   2237       if (HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS && ResourceHob->PhysicalStart <= HighAddress) {
   2238         continue;
   2239       }
   2240 
   2241       //
   2242       // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core
   2243       //
   2244       TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
   2245       TestedMemoryLength      = PageAlignLength  (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
   2246       if (TestedMemoryLength < MinimalMemorySizeNeeded) {
   2247         continue;
   2248       }
   2249 
   2250       //
   2251       // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core
   2252       //
   2253       BaseAddress = TestedMemoryBaseAddress;
   2254       Length      = TestedMemoryLength;
   2255       Attributes  = ResourceHob->ResourceAttribute;
   2256       HighAddress = ResourceHob->PhysicalStart;
   2257     }
   2258   }
   2259 
   2260   DEBUG ((EFI_D_INFO, "CoreInitializeMemoryServices:\n"));
   2261   DEBUG ((EFI_D_INFO, "  BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded));
   2262 
   2263   //
   2264   // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
   2265   //
   2266   ASSERT (Length >= MinimalMemorySizeNeeded);
   2267 
   2268   //
   2269   // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
   2270   //
   2271   if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
   2272     Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
   2273   } else {
   2274     Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
   2275   }
   2276 
   2277   //
   2278   // Declare the very first memory region, so the EFI Memory Services are available.
   2279   //
   2280   CoreAddMemoryDescriptor (
   2281     EfiConventionalMemory,
   2282     BaseAddress,
   2283     RShiftU64 (Length, EFI_PAGE_SHIFT),
   2284     Capabilities
   2285     );
   2286 
   2287   *MemoryBaseAddress = BaseAddress;
   2288   *MemoryLength      = Length;
   2289 
   2290   return EFI_SUCCESS;
   2291 }
   2292 
   2293 
   2294 /**
   2295   External function. Initializes the GCD and memory services based on the memory
   2296   descriptor HOBs.  This function is responsible for priming the GCD map and the
   2297   memory map, so memory allocations and resource allocations can be made. The
   2298   HobStart will be relocated to a pool buffer.
   2299 
   2300   @param  HobStart               The start address of the HOB
   2301   @param  MemoryBaseAddress      Start address of memory region found to init DXE
   2302                                  core.
   2303   @param  MemoryLength           Length of memory region found to init DXE core.
   2304 
   2305   @retval EFI_SUCCESS            GCD services successfully initialized.
   2306 
   2307 **/
   2308 EFI_STATUS
   2309 CoreInitializeGcdServices (
   2310   IN OUT VOID              **HobStart,
   2311   IN EFI_PHYSICAL_ADDRESS  MemoryBaseAddress,
   2312   IN UINT64                MemoryLength
   2313   )
   2314 {
   2315   EFI_PEI_HOB_POINTERS               Hob;
   2316   VOID                               *NewHobList;
   2317   EFI_HOB_HANDOFF_INFO_TABLE         *PhitHob;
   2318   UINT8                              SizeOfMemorySpace;
   2319   UINT8                              SizeOfIoSpace;
   2320   EFI_HOB_RESOURCE_DESCRIPTOR        *ResourceHob;
   2321   EFI_PHYSICAL_ADDRESS               BaseAddress;
   2322   UINT64                             Length;
   2323   EFI_STATUS                         Status;
   2324   EFI_GCD_MAP_ENTRY                  *Entry;
   2325   EFI_GCD_MEMORY_TYPE                GcdMemoryType;
   2326   EFI_GCD_IO_TYPE                    GcdIoType;
   2327   EFI_GCD_MEMORY_SPACE_DESCRIPTOR    Descriptor;
   2328   EFI_HOB_MEMORY_ALLOCATION          *MemoryHob;
   2329   EFI_HOB_FIRMWARE_VOLUME            *FirmwareVolumeHob;
   2330   UINTN                              NumberOfDescriptors;
   2331   EFI_GCD_MEMORY_SPACE_DESCRIPTOR    *MemorySpaceMap;
   2332   UINTN                              Index;
   2333   UINT64                             Capabilities;
   2334   EFI_HOB_CPU *                      CpuHob;
   2335   EFI_GCD_MEMORY_SPACE_DESCRIPTOR    *MemorySpaceMapHobList;
   2336 
   2337   //
   2338   // Cache the PHIT HOB for later use
   2339   //
   2340   PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
   2341 
   2342   //
   2343   // Get the number of address lines in the I/O and Memory space for the CPU
   2344   //
   2345   CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);
   2346   ASSERT (CpuHob != NULL);
   2347   SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;
   2348   SizeOfIoSpace     = CpuHob->SizeOfIoSpace;
   2349 
   2350   //
   2351   // Initialize the GCD Memory Space Map
   2352   //
   2353   Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);
   2354   ASSERT (Entry != NULL);
   2355 
   2356   Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;
   2357 
   2358   InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);
   2359 
   2360   CoreDumpGcdMemorySpaceMap (TRUE);
   2361 
   2362   //
   2363   // Initialize the GCD I/O Space Map
   2364   //
   2365   Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);
   2366   ASSERT (Entry != NULL);
   2367 
   2368   Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;
   2369 
   2370   InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);
   2371 
   2372   CoreDumpGcdIoSpaceMap (TRUE);
   2373 
   2374   //
   2375   // Walk the HOB list and add all resource descriptors to the GCD
   2376   //
   2377   for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
   2378 
   2379     GcdMemoryType = EfiGcdMemoryTypeNonExistent;
   2380     GcdIoType     = EfiGcdIoTypeNonExistent;
   2381 
   2382     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
   2383 
   2384       ResourceHob = Hob.ResourceDescriptor;
   2385 
   2386       switch (ResourceHob->ResourceType) {
   2387       case EFI_RESOURCE_SYSTEM_MEMORY:
   2388         if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
   2389           if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
   2390             GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
   2391           } else {
   2392             GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
   2393           }
   2394         }
   2395         if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
   2396           GcdMemoryType = EfiGcdMemoryTypeReserved;
   2397         }
   2398         if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
   2399           GcdMemoryType = EfiGcdMemoryTypeReserved;
   2400         }
   2401         if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {
   2402           GcdMemoryType = EfiGcdMemoryTypePersistentMemory;
   2403         }
   2404         break;
   2405       case EFI_RESOURCE_MEMORY_MAPPED_IO:
   2406       case EFI_RESOURCE_FIRMWARE_DEVICE:
   2407         GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;
   2408         break;
   2409       case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
   2410       case EFI_RESOURCE_MEMORY_RESERVED:
   2411         GcdMemoryType = EfiGcdMemoryTypeReserved;
   2412         break;
   2413       case EFI_RESOURCE_IO:
   2414         GcdIoType = EfiGcdIoTypeIo;
   2415         break;
   2416       case EFI_RESOURCE_IO_RESERVED:
   2417         GcdIoType = EfiGcdIoTypeReserved;
   2418         break;
   2419       }
   2420 
   2421       if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {
   2422         //
   2423         // Validate the Resource HOB Attributes
   2424         //
   2425         CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);
   2426 
   2427         //
   2428         // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
   2429         //
   2430         Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (
   2431                          GcdMemoryType,
   2432                          ResourceHob->ResourceAttribute
   2433                          );
   2434 
   2435         Status = CoreInternalAddMemorySpace (
   2436                    GcdMemoryType,
   2437                    ResourceHob->PhysicalStart,
   2438                    ResourceHob->ResourceLength,
   2439                    Capabilities
   2440                    );
   2441       }
   2442 
   2443       if (GcdIoType != EfiGcdIoTypeNonExistent) {
   2444         Status = CoreAddIoSpace (
   2445                    GcdIoType,
   2446                    ResourceHob->PhysicalStart,
   2447                    ResourceHob->ResourceLength
   2448                    );
   2449       }
   2450     }
   2451   }
   2452 
   2453   //
   2454   // Allocate first memory region from the GCD by the DXE core
   2455   //
   2456   Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);
   2457   if (!EFI_ERROR (Status)) {
   2458     ASSERT ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
   2459             (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable));
   2460     Status = CoreAllocateMemorySpace (
   2461                EfiGcdAllocateAddress,
   2462                Descriptor.GcdMemoryType,
   2463                0,
   2464                MemoryLength,
   2465                &MemoryBaseAddress,
   2466                gDxeCoreImageHandle,
   2467                NULL
   2468                );
   2469   }
   2470 
   2471   //
   2472   // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
   2473   // and Firmware Volume HOBs.  Also update the EFI Memory Map with the memory allocation HOBs.
   2474   //
   2475   for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
   2476     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
   2477       MemoryHob = Hob.MemoryAllocation;
   2478       BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
   2479       Status = CoreGetMemorySpaceDescriptor  (BaseAddress, &Descriptor);
   2480       if (!EFI_ERROR (Status)) {
   2481         Status = CoreAllocateMemorySpace (
   2482                    EfiGcdAllocateAddress,
   2483                    Descriptor.GcdMemoryType,
   2484                    0,
   2485                    MemoryHob->AllocDescriptor.MemoryLength,
   2486                    &BaseAddress,
   2487                    gDxeCoreImageHandle,
   2488                    NULL
   2489                    );
   2490         if (!EFI_ERROR (Status) &&
   2491             ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
   2492              (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
   2493           CoreAddMemoryDescriptor (
   2494             MemoryHob->AllocDescriptor.MemoryType,
   2495             MemoryHob->AllocDescriptor.MemoryBaseAddress,
   2496             RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),
   2497             Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)
   2498             );
   2499         }
   2500       }
   2501     }
   2502 
   2503     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
   2504       FirmwareVolumeHob = Hob.FirmwareVolume;
   2505       BaseAddress = FirmwareVolumeHob->BaseAddress;
   2506       Status = CoreAllocateMemorySpace (
   2507                  EfiGcdAllocateAddress,
   2508                  EfiGcdMemoryTypeMemoryMappedIo,
   2509                  0,
   2510                  FirmwareVolumeHob->Length,
   2511                  &BaseAddress,
   2512                  gDxeCoreImageHandle,
   2513                  NULL
   2514                  );
   2515     }
   2516   }
   2517 
   2518   //
   2519   // Add and allocate the remaining unallocated system memory to the memory services.
   2520   //
   2521   Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
   2522   ASSERT (Status == EFI_SUCCESS);
   2523 
   2524   MemorySpaceMapHobList = NULL;
   2525   for (Index = 0; Index < NumberOfDescriptors; Index++) {
   2526     if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
   2527         (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) {
   2528       if (MemorySpaceMap[Index].ImageHandle == NULL) {
   2529         BaseAddress  = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);
   2530         Length       = PageAlignLength  (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);
   2531         if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) {
   2532           continue;
   2533         }
   2534         if (((UINTN) MemorySpaceMap[Index].BaseAddress <= (UINTN) (*HobStart)) &&
   2535             ((UINTN) (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN) PhitHob->EfiFreeMemoryBottom)) {
   2536           //
   2537           // Skip the memory space that covers HOB List, it should be processed
   2538           // after HOB List relocation to avoid the resources allocated by others
   2539           // to corrupt HOB List before its relocation.
   2540           //
   2541           MemorySpaceMapHobList = &MemorySpaceMap[Index];
   2542           continue;
   2543         }
   2544         CoreAddMemoryDescriptor (
   2545           EfiConventionalMemory,
   2546           BaseAddress,
   2547           RShiftU64 (Length, EFI_PAGE_SHIFT),
   2548           MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)
   2549           );
   2550         Status = CoreAllocateMemorySpace (
   2551                    EfiGcdAllocateAddress,
   2552                    MemorySpaceMap[Index].GcdMemoryType,
   2553                    0,
   2554                    Length,
   2555                    &BaseAddress,
   2556                    gDxeCoreImageHandle,
   2557                    NULL
   2558                    );
   2559       }
   2560     }
   2561   }
   2562 
   2563   //
   2564   // Relocate HOB List to an allocated pool buffer.
   2565   // The relocation should be at after all the tested memory resources added
   2566   // (except the memory space that covers HOB List) to the memory services,
   2567   // because the memory resource found in CoreInitializeMemoryServices()
   2568   // may have not enough remaining resource for HOB List.
   2569   //
   2570   NewHobList = AllocateCopyPool (
   2571                  (UINTN) PhitHob->EfiFreeMemoryBottom - (UINTN) (*HobStart),
   2572                  *HobStart
   2573                  );
   2574   ASSERT (NewHobList != NULL);
   2575 
   2576   *HobStart = NewHobList;
   2577   gHobList  = NewHobList;
   2578 
   2579   if (MemorySpaceMapHobList != NULL) {
   2580     //
   2581     // Add and allocate the memory space that covers HOB List to the memory services
   2582     // after HOB List relocation.
   2583     //
   2584     BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);
   2585     Length      = PageAlignLength  (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);
   2586     CoreAddMemoryDescriptor (
   2587       EfiConventionalMemory,
   2588       BaseAddress,
   2589       RShiftU64 (Length, EFI_PAGE_SHIFT),
   2590       MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME)
   2591       );
   2592     Status = CoreAllocateMemorySpace (
   2593                EfiGcdAllocateAddress,
   2594                MemorySpaceMapHobList->GcdMemoryType,
   2595                0,
   2596                Length,
   2597                &BaseAddress,
   2598                gDxeCoreImageHandle,
   2599                NULL
   2600                );
   2601   }
   2602 
   2603   CoreFreePool (MemorySpaceMap);
   2604 
   2605   return EFI_SUCCESS;
   2606 }
   2607