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