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