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