1 /** @file
2   UEFI Memory page management functions.
3 
4 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "DxeMain.h"
10 #include "Imem.h"
11 #include "HeapGuard.h"
12 
13 //
14 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
15 //
16 typedef struct {
17   EFI_PHYSICAL_ADDRESS  BaseAddress;
18   EFI_PHYSICAL_ADDRESS  MaximumAddress;
19   UINT64                CurrentNumberOfPages;
20   UINT64                NumberOfPages;
21   UINTN                 InformationIndex;
22   BOOLEAN               Special;
23   BOOLEAN               Runtime;
24 } EFI_MEMORY_TYPE_STATISTICS;
25 
26 //
27 // MemoryMap - The current memory map
28 //
29 UINTN     mMemoryMapKey = 0;
30 
31 #define MAX_MAP_DEPTH 6
32 
33 ///
34 /// mMapDepth - depth of new descriptor stack
35 ///
36 UINTN         mMapDepth = 0;
37 ///
38 /// mMapStack - space to use as temp storage to build new map descriptors
39 ///
40 MEMORY_MAP    mMapStack[MAX_MAP_DEPTH];
41 UINTN         mFreeMapStack = 0;
42 ///
43 /// This list maintain the free memory map list
44 ///
45 LIST_ENTRY   mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
46 BOOLEAN      mMemoryTypeInformationInitialized = FALSE;
47 
48 EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
49   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  FALSE },  // EfiReservedMemoryType
50   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiLoaderCode
51   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiLoaderData
52   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiBootServicesCode
53   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiBootServicesData
54   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  TRUE  },  // EfiRuntimeServicesCode
55   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  TRUE  },  // EfiRuntimeServicesData
56   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiConventionalMemory
57   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiUnusableMemory
58   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  FALSE },  // EfiACPIReclaimMemory
59   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  FALSE },  // EfiACPIMemoryNVS
60   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiMemoryMappedIO
61   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiMemoryMappedIOPortSpace
62   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE,  TRUE  },  // EfiPalCode
63   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE },  // EfiPersistentMemory
64   { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }   // EfiMaxMemoryType
65 };
66 
67 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;
68 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS;
69 
70 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
71   { EfiReservedMemoryType,      0 },
72   { EfiLoaderCode,              0 },
73   { EfiLoaderData,              0 },
74   { EfiBootServicesCode,        0 },
75   { EfiBootServicesData,        0 },
76   { EfiRuntimeServicesCode,     0 },
77   { EfiRuntimeServicesData,     0 },
78   { EfiConventionalMemory,      0 },
79   { EfiUnusableMemory,          0 },
80   { EfiACPIReclaimMemory,       0 },
81   { EfiACPIMemoryNVS,           0 },
82   { EfiMemoryMappedIO,          0 },
83   { EfiMemoryMappedIOPortSpace, 0 },
84   { EfiPalCode,                 0 },
85   { EfiPersistentMemory,        0 },
86   { EfiMaxMemoryType,           0 }
87 };
88 //
89 // Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
90 // and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
91 //  address assigned by DXE core.
92 //
93 GLOBAL_REMOVE_IF_UNREFERENCED   BOOLEAN       gLoadFixedAddressCodeMemoryReady = FALSE;
94 
95 /**
96   Enter critical section by gaining lock on gMemoryLock.
97 
98 **/
99 VOID
CoreAcquireMemoryLock(VOID)100 CoreAcquireMemoryLock (
101   VOID
102   )
103 {
104   CoreAcquireLock (&gMemoryLock);
105 }
106 
107 
108 
109 /**
110   Exit critical section by releasing lock on gMemoryLock.
111 
112 **/
113 VOID
CoreReleaseMemoryLock(VOID)114 CoreReleaseMemoryLock (
115   VOID
116   )
117 {
118   CoreReleaseLock (&gMemoryLock);
119 }
120 
121 
122 
123 
124 /**
125   Internal function.  Removes a descriptor entry.
126 
127   @param  Entry                  The entry to remove
128 
129 **/
130 VOID
RemoveMemoryMapEntry(IN OUT MEMORY_MAP * Entry)131 RemoveMemoryMapEntry (
132   IN OUT MEMORY_MAP      *Entry
133   )
134 {
135   RemoveEntryList (&Entry->Link);
136   Entry->Link.ForwardLink = NULL;
137 
138   if (Entry->FromPages) {
139     //
140     // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
141     //
142     InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
143   }
144 }
145 
146 /**
147   Internal function.  Adds a ranges to the memory map.
148   The range must not already exist in the map.
149 
150   @param  Type                   The type of memory range to add
151   @param  Start                  The starting address in the memory range Must be
152                                  paged aligned
153   @param  End                    The last address in the range Must be the last
154                                  byte of a page
155   @param  Attribute              The attributes of the memory range to add
156 
157 **/
158 VOID
CoreAddRange(IN EFI_MEMORY_TYPE Type,IN EFI_PHYSICAL_ADDRESS Start,IN EFI_PHYSICAL_ADDRESS End,IN UINT64 Attribute)159 CoreAddRange (
160   IN EFI_MEMORY_TYPE          Type,
161   IN EFI_PHYSICAL_ADDRESS     Start,
162   IN EFI_PHYSICAL_ADDRESS     End,
163   IN UINT64                   Attribute
164   )
165 {
166   LIST_ENTRY        *Link;
167   MEMORY_MAP        *Entry;
168 
169   ASSERT ((Start & EFI_PAGE_MASK) == 0);
170   ASSERT (End > Start) ;
171 
172   ASSERT_LOCKED (&gMemoryLock);
173 
174   DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
175 
176   //
177   // If memory of type EfiConventionalMemory is being added that includes the page
178   // starting at address 0, then zero the page starting at address 0.  This has
179   // two benifits.  It helps find NULL pointer bugs and it also maximizes
180   // compatibility with operating systems that may evaluate memory in this page
181   // for legacy data structures.  If memory of any other type is added starting
182   // at address 0, then do not zero the page at address 0 because the page is being
183   // used for other purposes.
184   //
185   if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 1)) {
186     if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
187       SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
188     }
189   }
190 
191   //
192   // Memory map being altered so updated key
193   //
194   mMemoryMapKey += 1;
195 
196   //
197   // UEFI 2.0 added an event group for notificaiton on memory map changes.
198   // So we need to signal this Event Group every time the memory map changes.
199   // If we are in EFI 1.10 compatability mode no event groups will be
200   // found and nothing will happen we we call this function. These events
201   // will get signaled but since a lock is held around the call to this
202   // function the notificaiton events will only be called after this function
203   // returns and the lock is released.
204   //
205   CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
206 
207   //
208   // Look for adjoining memory descriptor
209   //
210 
211   // Two memory descriptors can only be merged if they have the same Type
212   // and the same Attribute
213   //
214 
215   Link = gMemoryMap.ForwardLink;
216   while (Link != &gMemoryMap) {
217     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
218     Link  = Link->ForwardLink;
219 
220     if (Entry->Type != Type) {
221       continue;
222     }
223 
224     if (Entry->Attribute != Attribute) {
225       continue;
226     }
227 
228     if (Entry->End + 1 == Start) {
229 
230       Start = Entry->Start;
231       RemoveMemoryMapEntry (Entry);
232 
233     } else if (Entry->Start == End + 1) {
234 
235       End = Entry->End;
236       RemoveMemoryMapEntry (Entry);
237     }
238   }
239 
240   //
241   // Add descriptor
242   //
243 
244   mMapStack[mMapDepth].Signature     = MEMORY_MAP_SIGNATURE;
245   mMapStack[mMapDepth].FromPages      = FALSE;
246   mMapStack[mMapDepth].Type          = Type;
247   mMapStack[mMapDepth].Start         = Start;
248   mMapStack[mMapDepth].End           = End;
249   mMapStack[mMapDepth].VirtualStart  = 0;
250   mMapStack[mMapDepth].Attribute     = Attribute;
251   InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
252 
253   mMapDepth += 1;
254   ASSERT (mMapDepth < MAX_MAP_DEPTH);
255 
256   return ;
257 }
258 
259 /**
260   Internal function.  Deque a descriptor entry from the mFreeMemoryMapEntryList.
261   If the list is emtry, then allocate a new page to refuel the list.
262   Please Note this algorithm to allocate the memory map descriptor has a property
263   that the memory allocated for memory entries always grows, and will never really be freed
264   For example, if the current boot uses 2000 memory map entries at the maximum point, but
265   ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
266   memory map entries is still allocated from EfiBootServicesMemory.
267 
268 
269   @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
270 
271 **/
272 MEMORY_MAP *
AllocateMemoryMapEntry(VOID)273 AllocateMemoryMapEntry (
274   VOID
275   )
276 {
277   MEMORY_MAP*            FreeDescriptorEntries;
278   MEMORY_MAP*            Entry;
279   UINTN                  Index;
280 
281   if (IsListEmpty (&mFreeMemoryMapEntryList)) {
282     //
283     // The list is empty, to allocate one page to refuel the list
284     //
285     FreeDescriptorEntries = CoreAllocatePoolPages (
286                               EfiBootServicesData,
287                               EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),
288                               DEFAULT_PAGE_ALLOCATION_GRANULARITY,
289                               FALSE
290                               );
291     if (FreeDescriptorEntries != NULL) {
292       //
293       // Enque the free memmory map entries into the list
294       //
295       for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof(MEMORY_MAP); Index++) {
296         FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
297         InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
298       }
299     } else {
300       return NULL;
301     }
302   }
303   //
304   // dequeue the first descriptor from the list
305   //
306   Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
307   RemoveEntryList (&Entry->Link);
308 
309   return Entry;
310 }
311 
312 
313 /**
314   Internal function.  Moves any memory descriptors that are on the
315   temporary descriptor stack to heap.
316 
317 **/
318 VOID
CoreFreeMemoryMapStack(VOID)319 CoreFreeMemoryMapStack (
320   VOID
321   )
322 {
323   MEMORY_MAP      *Entry;
324   MEMORY_MAP      *Entry2;
325   LIST_ENTRY      *Link2;
326 
327   ASSERT_LOCKED (&gMemoryLock);
328 
329   //
330   // If already freeing the map stack, then return
331   //
332   if (mFreeMapStack != 0) {
333     return ;
334   }
335 
336   //
337   // Move the temporary memory descriptor stack into pool
338   //
339   mFreeMapStack += 1;
340 
341   while (mMapDepth != 0) {
342     //
343     // Deque an memory map entry from mFreeMemoryMapEntryList
344     //
345     Entry = AllocateMemoryMapEntry ();
346 
347     ASSERT (Entry);
348 
349     //
350     // Update to proper entry
351     //
352     mMapDepth -= 1;
353 
354     if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
355 
356       //
357       // Move this entry to general memory
358       //
359       RemoveEntryList (&mMapStack[mMapDepth].Link);
360       mMapStack[mMapDepth].Link.ForwardLink = NULL;
361 
362       CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
363       Entry->FromPages = TRUE;
364 
365       //
366       // Find insertion location
367       //
368       for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
369         Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
370         if (Entry2->FromPages && Entry2->Start > Entry->Start) {
371           break;
372         }
373       }
374 
375       InsertTailList (Link2, &Entry->Link);
376 
377     } else {
378       //
379       // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
380       // so here no need to move it to memory.
381       //
382       InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
383     }
384   }
385 
386   mFreeMapStack -= 1;
387 }
388 
389 /**
390   Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
391 
392 **/
393 BOOLEAN
PromoteMemoryResource(VOID)394 PromoteMemoryResource (
395   VOID
396   )
397 {
398   LIST_ENTRY                        *Link;
399   EFI_GCD_MAP_ENTRY                 *Entry;
400   BOOLEAN                           Promoted;
401   EFI_PHYSICAL_ADDRESS              StartAddress;
402   EFI_PHYSICAL_ADDRESS              EndAddress;
403   EFI_GCD_MEMORY_SPACE_DESCRIPTOR   Descriptor;
404 
405   DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
406 
407   CoreAcquireGcdMemoryLock ();
408 
409   Promoted = FALSE;
410   Link = mGcdMemorySpaceMap.ForwardLink;
411   while (Link != &mGcdMemorySpaceMap) {
412 
413     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
414 
415     if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
416         Entry->EndAddress < MAX_ALLOC_ADDRESS &&
417         (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
418           (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
419       //
420       // Update the GCD map
421       //
422       if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
423         Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
424       } else {
425         Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
426       }
427       Entry->Capabilities |= EFI_MEMORY_TESTED;
428       Entry->ImageHandle  = gDxeCoreImageHandle;
429       Entry->DeviceHandle = NULL;
430 
431       //
432       // Add to allocable system memory resource
433       //
434 
435       CoreAddRange (
436         EfiConventionalMemory,
437         Entry->BaseAddress,
438         Entry->EndAddress,
439         Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
440         );
441       CoreFreeMemoryMapStack ();
442 
443       Promoted = TRUE;
444     }
445 
446     Link = Link->ForwardLink;
447   }
448 
449   CoreReleaseGcdMemoryLock ();
450 
451   if (!Promoted) {
452     //
453     // If freed-memory guard is enabled, we could promote pages from
454     // guarded free pages.
455     //
456     Promoted = PromoteGuardedFreePages (&StartAddress, &EndAddress);
457     if (Promoted) {
458       CoreGetMemorySpaceDescriptor (StartAddress, &Descriptor);
459       CoreAddRange (
460         EfiConventionalMemory,
461         StartAddress,
462         EndAddress,
463         Descriptor.Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED |
464                                     EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
465         );
466     }
467   }
468 
469   return Promoted;
470 }
471 /**
472   This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
473   PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
474   size of boot time and runtime code.
475 
476 **/
477 VOID
CoreLoadingFixedAddressHook(VOID)478 CoreLoadingFixedAddressHook (
479   VOID
480   )
481 {
482    UINT32                     RuntimeCodePageNumber;
483    UINT32                     BootTimeCodePageNumber;
484    EFI_PHYSICAL_ADDRESS       RuntimeCodeBase;
485    EFI_PHYSICAL_ADDRESS       BootTimeCodeBase;
486    EFI_STATUS                 Status;
487 
488    //
489    // Make sure these 2 areas are not initialzied.
490    //
491    if (!gLoadFixedAddressCodeMemoryReady) {
492      RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
493      BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
494      RuntimeCodeBase       = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
495      BootTimeCodeBase      = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
496      //
497      // Try to allocate runtime memory.
498      //
499      Status = CoreAllocatePages (
500                        AllocateAddress,
501                        EfiRuntimeServicesCode,
502                        RuntimeCodePageNumber,
503                        &RuntimeCodeBase
504                        );
505      if (EFI_ERROR(Status)) {
506        //
507        // Runtime memory allocation failed
508        //
509        return;
510      }
511      //
512      // Try to allocate boot memory.
513      //
514      Status = CoreAllocatePages (
515                        AllocateAddress,
516                        EfiBootServicesCode,
517                        BootTimeCodePageNumber,
518                        &BootTimeCodeBase
519                        );
520      if (EFI_ERROR(Status)) {
521        //
522         // boot memory allocation failed. Free Runtime code range and will try the allocation again when
523         // new memory range is installed.
524         //
525         CoreFreePages (
526               RuntimeCodeBase,
527               RuntimeCodePageNumber
528               );
529        return;
530      }
531      gLoadFixedAddressCodeMemoryReady = TRUE;
532    }
533    return;
534 }
535 
536 /**
537   Called to initialize the memory map and add descriptors to
538   the current descriptor list.
539   The first descriptor that is added must be general usable
540   memory as the addition allocates heap.
541 
542   @param  Type                   The type of memory to add
543   @param  Start                  The starting address in the memory range Must be
544                                  page aligned
545   @param  NumberOfPages          The number of pages in the range
546   @param  Attribute              Attributes of the memory to add
547 
548   @return None.  The range is added to the memory map
549 
550 **/
551 VOID
CoreAddMemoryDescriptor(IN EFI_MEMORY_TYPE Type,IN EFI_PHYSICAL_ADDRESS Start,IN UINT64 NumberOfPages,IN UINT64 Attribute)552 CoreAddMemoryDescriptor (
553   IN EFI_MEMORY_TYPE       Type,
554   IN EFI_PHYSICAL_ADDRESS  Start,
555   IN UINT64                NumberOfPages,
556   IN UINT64                Attribute
557   )
558 {
559   EFI_PHYSICAL_ADDRESS        End;
560   EFI_STATUS                  Status;
561   UINTN                       Index;
562   UINTN                       FreeIndex;
563 
564   if ((Start & EFI_PAGE_MASK) != 0) {
565     return;
566   }
567 
568   if (Type >= EfiMaxMemoryType && Type < MEMORY_TYPE_OEM_RESERVED_MIN) {
569     return;
570   }
571   CoreAcquireMemoryLock ();
572   End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
573   CoreAddRange (Type, Start, End, Attribute);
574   CoreFreeMemoryMapStack ();
575   CoreReleaseMemoryLock ();
576 
577   ApplyMemoryProtectionPolicy (EfiMaxMemoryType, Type, Start,
578     LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT));
579 
580   //
581   // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
582   //
583   if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
584     CoreLoadingFixedAddressHook();
585   }
586 
587   //
588   // Check to see if the statistics for the different memory types have already been established
589   //
590   if (mMemoryTypeInformationInitialized) {
591     return;
592   }
593 
594 
595   //
596   // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
597   //
598   for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
599     //
600     // Make sure the memory type in the gMemoryTypeInformation[] array is valid
601     //
602     Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
603     if ((UINT32)Type > EfiMaxMemoryType) {
604       continue;
605     }
606     if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
607       //
608       // Allocate pages for the current memory type from the top of available memory
609       //
610       Status = CoreAllocatePages (
611                  AllocateAnyPages,
612                  Type,
613                  gMemoryTypeInformation[Index].NumberOfPages,
614                  &mMemoryTypeStatistics[Type].BaseAddress
615                  );
616       if (EFI_ERROR (Status)) {
617         //
618         // If an error occurs allocating the pages for the current memory type, then
619         // free all the pages allocates for the previous memory types and return.  This
620         // operation with be retied when/if more memory is added to the system
621         //
622         for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
623           //
624           // Make sure the memory type in the gMemoryTypeInformation[] array is valid
625           //
626           Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
627           if ((UINT32)Type > EfiMaxMemoryType) {
628             continue;
629           }
630 
631           if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
632             CoreFreePages (
633               mMemoryTypeStatistics[Type].BaseAddress,
634               gMemoryTypeInformation[FreeIndex].NumberOfPages
635               );
636             mMemoryTypeStatistics[Type].BaseAddress    = 0;
637             mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;
638           }
639         }
640         return;
641       }
642 
643       //
644       // Compute the address at the top of the current statistics
645       //
646       mMemoryTypeStatistics[Type].MaximumAddress =
647         mMemoryTypeStatistics[Type].BaseAddress +
648         LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
649 
650       //
651       // If the current base address is the lowest address so far, then update the default
652       // maximum address
653       //
654       if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
655         mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
656       }
657     }
658   }
659 
660   //
661   // There was enough system memory for all the the memory types were allocated.  So,
662   // those memory areas can be freed for future allocations, and all future memory
663   // allocations can occur within their respective bins
664   //
665   for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
666     //
667     // Make sure the memory type in the gMemoryTypeInformation[] array is valid
668     //
669     Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
670     if ((UINT32)Type > EfiMaxMemoryType) {
671       continue;
672     }
673     if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
674       CoreFreePages (
675         mMemoryTypeStatistics[Type].BaseAddress,
676         gMemoryTypeInformation[Index].NumberOfPages
677         );
678       mMemoryTypeStatistics[Type].NumberOfPages   = gMemoryTypeInformation[Index].NumberOfPages;
679       gMemoryTypeInformation[Index].NumberOfPages = 0;
680     }
681   }
682 
683   //
684   // If the number of pages reserved for a memory type is 0, then all allocations for that type
685   // should be in the default range.
686   //
687   for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
688     for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
689       if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
690         mMemoryTypeStatistics[Type].InformationIndex = Index;
691       }
692     }
693     mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
694     if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
695       mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
696     }
697   }
698 
699   mMemoryTypeInformationInitialized = TRUE;
700 }
701 
702 
703 /**
704   Internal function.  Converts a memory range to the specified type or attributes.
705   The range must exist in the memory map.  Either ChangingType or
706   ChangingAttributes must be set, but not both.
707 
708   @param  Start                  The first address of the range Must be page
709                                  aligned
710   @param  NumberOfPages          The number of pages to convert
711   @param  ChangingType           Boolean indicating that type value should be changed
712   @param  NewType                The new type for the memory range
713   @param  ChangingAttributes     Boolean indicating that attributes value should be changed
714   @param  NewAttributes          The new attributes for the memory range
715 
716   @retval EFI_INVALID_PARAMETER  Invalid parameter
717   @retval EFI_NOT_FOUND          Could not find a descriptor cover the specified
718                                  range  or convertion not allowed.
719   @retval EFI_SUCCESS            Successfully converts the memory range to the
720                                  specified type.
721 
722 **/
723 EFI_STATUS
CoreConvertPagesEx(IN UINT64 Start,IN UINT64 NumberOfPages,IN BOOLEAN ChangingType,IN EFI_MEMORY_TYPE NewType,IN BOOLEAN ChangingAttributes,IN UINT64 NewAttributes)724 CoreConvertPagesEx (
725   IN UINT64           Start,
726   IN UINT64           NumberOfPages,
727   IN BOOLEAN          ChangingType,
728   IN EFI_MEMORY_TYPE  NewType,
729   IN BOOLEAN          ChangingAttributes,
730   IN UINT64           NewAttributes
731   )
732 {
733 
734   UINT64          NumberOfBytes;
735   UINT64          End;
736   UINT64          RangeEnd;
737   UINT64          Attribute;
738   EFI_MEMORY_TYPE MemType;
739   LIST_ENTRY      *Link;
740   MEMORY_MAP      *Entry;
741 
742   Entry = NULL;
743   NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
744   End = Start + NumberOfBytes - 1;
745 
746   ASSERT (NumberOfPages);
747   ASSERT ((Start & EFI_PAGE_MASK) == 0);
748   ASSERT (End > Start) ;
749   ASSERT_LOCKED (&gMemoryLock);
750   ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) );
751 
752   if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
753     return EFI_INVALID_PARAMETER;
754   }
755 
756   //
757   // Convert the entire range
758   //
759 
760   while (Start < End) {
761 
762     //
763     // Find the entry that the covers the range
764     //
765     for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
766       Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
767 
768       if (Entry->Start <= Start && Entry->End > Start) {
769         break;
770       }
771     }
772 
773     if (Link == &gMemoryMap) {
774       DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
775       return EFI_NOT_FOUND;
776     }
777 
778     //
779     // If we are converting the type of the range from EfiConventionalMemory to
780     // another type, we have to ensure that the entire range is covered by a
781     // single entry.
782     //
783     if (ChangingType && (NewType != EfiConventionalMemory)) {
784       if (Entry->End < End) {
785         DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));
786         return EFI_NOT_FOUND;
787       }
788     }
789     //
790     // Convert range to the end, or to the end of the descriptor
791     // if that's all we've got
792     //
793     RangeEnd = End;
794 
795     ASSERT (Entry != NULL);
796     if (Entry->End < End) {
797       RangeEnd = Entry->End;
798     }
799 
800     if (ChangingType) {
801       DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
802     }
803     if (ChangingAttributes) {
804       DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
805     }
806 
807     if (ChangingType) {
808       //
809       // Debug code - verify conversion is allowed
810       //
811       if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
812         DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));
813         if (Entry->Type == EfiConventionalMemory) {
814           DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));
815         } else {
816           DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));
817         }
818         return EFI_NOT_FOUND;
819       }
820 
821       //
822       // Update counters for the number of pages allocated to each memory type
823       //
824       if ((UINT32)Entry->Type < EfiMaxMemoryType) {
825         if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||
826             (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress)                                                          ) {
827           if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
828             mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
829           } else {
830             mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
831           }
832         }
833       }
834 
835       if ((UINT32)NewType < EfiMaxMemoryType) {
836         if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||
837             (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress)                                                  ) {
838           mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
839           if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
840             gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
841           }
842         }
843       }
844     }
845 
846     //
847     // Pull range out of descriptor
848     //
849     if (Entry->Start == Start) {
850 
851       //
852       // Clip start
853       //
854       Entry->Start = RangeEnd + 1;
855 
856     } else if (Entry->End == RangeEnd) {
857 
858       //
859       // Clip end
860       //
861       Entry->End = Start - 1;
862 
863     } else {
864 
865       //
866       // Pull it out of the center, clip current
867       //
868 
869       //
870       // Add a new one
871       //
872       mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
873       mMapStack[mMapDepth].FromPages  = FALSE;
874       mMapStack[mMapDepth].Type      = Entry->Type;
875       mMapStack[mMapDepth].Start     = RangeEnd+1;
876       mMapStack[mMapDepth].End       = Entry->End;
877 
878       //
879       // Inherit Attribute from the Memory Descriptor that is being clipped
880       //
881       mMapStack[mMapDepth].Attribute = Entry->Attribute;
882 
883       Entry->End = Start - 1;
884       ASSERT (Entry->Start < Entry->End);
885 
886       Entry = &mMapStack[mMapDepth];
887       InsertTailList (&gMemoryMap, &Entry->Link);
888 
889       mMapDepth += 1;
890       ASSERT (mMapDepth < MAX_MAP_DEPTH);
891     }
892 
893     //
894     // The new range inherits the same Attribute as the Entry
895     // it is being cut out of unless attributes are being changed
896     //
897     if (ChangingType) {
898       Attribute = Entry->Attribute;
899       MemType = NewType;
900     } else {
901       Attribute = NewAttributes;
902       MemType = Entry->Type;
903     }
904 
905     //
906     // If the descriptor is empty, then remove it from the map
907     //
908     if (Entry->Start == Entry->End + 1) {
909       RemoveMemoryMapEntry (Entry);
910       Entry = NULL;
911     }
912 
913     //
914     // Add our new range in. Don't do this for freed pages if freed-memory
915     // guard is enabled.
916     //
917     if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
918         !ChangingType ||
919         MemType != EfiConventionalMemory) {
920       CoreAddRange (MemType, Start, RangeEnd, Attribute);
921     }
922 
923     if (ChangingType && (MemType == EfiConventionalMemory)) {
924       //
925       // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
926       // macro will ASSERT() if address is 0.  Instead, CoreAddRange() guarantees
927       // that the page starting at address 0 is always filled with zeros.
928       //
929       if (Start == 0) {
930         if (RangeEnd > EFI_PAGE_SIZE) {
931           DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));
932         }
933       } else {
934         DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));
935       }
936     }
937 
938     //
939     // Move any map descriptor stack to general pool
940     //
941     CoreFreeMemoryMapStack ();
942 
943     //
944     // Bump the starting address, and convert the next range
945     //
946     Start = RangeEnd + 1;
947   }
948 
949   //
950   // Converted the whole range, done
951   //
952 
953   return EFI_SUCCESS;
954 }
955 
956 
957 /**
958   Internal function.  Converts a memory range to the specified type.
959   The range must exist in the memory map.
960 
961   @param  Start                  The first address of the range Must be page
962                                  aligned
963   @param  NumberOfPages          The number of pages to convert
964   @param  NewType                The new type for the memory range
965 
966   @retval EFI_INVALID_PARAMETER  Invalid parameter
967   @retval EFI_NOT_FOUND          Could not find a descriptor cover the specified
968                                  range  or convertion not allowed.
969   @retval EFI_SUCCESS            Successfully converts the memory range to the
970                                  specified type.
971 
972 **/
973 EFI_STATUS
CoreConvertPages(IN UINT64 Start,IN UINT64 NumberOfPages,IN EFI_MEMORY_TYPE NewType)974 CoreConvertPages (
975   IN UINT64           Start,
976   IN UINT64           NumberOfPages,
977   IN EFI_MEMORY_TYPE  NewType
978   )
979 {
980   return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);
981 }
982 
983 
984 /**
985   Internal function.  Converts a memory range to use new attributes.
986 
987   @param  Start                  The first address of the range Must be page
988                                  aligned
989   @param  NumberOfPages          The number of pages to convert
990   @param  NewAttributes          The new attributes value for the range.
991 
992 **/
993 VOID
CoreUpdateMemoryAttributes(IN EFI_PHYSICAL_ADDRESS Start,IN UINT64 NumberOfPages,IN UINT64 NewAttributes)994 CoreUpdateMemoryAttributes (
995   IN EFI_PHYSICAL_ADDRESS  Start,
996   IN UINT64                NumberOfPages,
997   IN UINT64                NewAttributes
998   )
999 {
1000   CoreAcquireMemoryLock ();
1001 
1002   //
1003   // Update the attributes to the new value
1004   //
1005   CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
1006 
1007   CoreReleaseMemoryLock ();
1008 }
1009 
1010 
1011 /**
1012   Internal function. Finds a consecutive free page range below
1013   the requested address.
1014 
1015   @param  MaxAddress             The address that the range must be below
1016   @param  MinAddress             The address that the range must be above
1017   @param  NumberOfPages          Number of pages needed
1018   @param  NewType                The type of memory the range is going to be
1019                                  turned into
1020   @param  Alignment              Bits to align with
1021   @param  NeedGuard              Flag to indicate Guard page is needed or not
1022 
1023   @return The base address of the range, or 0 if the range was not found
1024 
1025 **/
1026 UINT64
CoreFindFreePagesI(IN UINT64 MaxAddress,IN UINT64 MinAddress,IN UINT64 NumberOfPages,IN EFI_MEMORY_TYPE NewType,IN UINTN Alignment,IN BOOLEAN NeedGuard)1027 CoreFindFreePagesI (
1028   IN UINT64           MaxAddress,
1029   IN UINT64           MinAddress,
1030   IN UINT64           NumberOfPages,
1031   IN EFI_MEMORY_TYPE  NewType,
1032   IN UINTN            Alignment,
1033   IN BOOLEAN          NeedGuard
1034   )
1035 {
1036   UINT64          NumberOfBytes;
1037   UINT64          Target;
1038   UINT64          DescStart;
1039   UINT64          DescEnd;
1040   UINT64          DescNumberOfBytes;
1041   LIST_ENTRY      *Link;
1042   MEMORY_MAP      *Entry;
1043 
1044   if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
1045     return 0;
1046   }
1047 
1048   if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
1049 
1050     //
1051     // If MaxAddress is not aligned to the end of a page
1052     //
1053 
1054     //
1055     // Change MaxAddress to be 1 page lower
1056     //
1057     MaxAddress -= (EFI_PAGE_MASK + 1);
1058 
1059     //
1060     // Set MaxAddress to a page boundary
1061     //
1062     MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
1063 
1064     //
1065     // Set MaxAddress to end of the page
1066     //
1067     MaxAddress |= EFI_PAGE_MASK;
1068   }
1069 
1070   NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1071   Target = 0;
1072 
1073   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1074     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1075 
1076     //
1077     // If it's not a free entry, don't bother with it
1078     //
1079     if (Entry->Type != EfiConventionalMemory) {
1080       continue;
1081     }
1082 
1083     DescStart = Entry->Start;
1084     DescEnd = Entry->End;
1085 
1086     //
1087     // If desc is past max allowed address or below min allowed address, skip it
1088     //
1089     if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
1090       continue;
1091     }
1092 
1093     //
1094     // If desc ends past max allowed address, clip the end
1095     //
1096     if (DescEnd >= MaxAddress) {
1097       DescEnd = MaxAddress;
1098     }
1099 
1100     DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
1101 
1102     // Skip if DescEnd is less than DescStart after alignment clipping
1103     if (DescEnd < DescStart) {
1104       continue;
1105     }
1106 
1107     //
1108     // Compute the number of bytes we can used from this
1109     // descriptor, and see it's enough to satisfy the request
1110     //
1111     DescNumberOfBytes = DescEnd - DescStart + 1;
1112 
1113     if (DescNumberOfBytes >= NumberOfBytes) {
1114       //
1115       // If the start of the allocated range is below the min address allowed, skip it
1116       //
1117       if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
1118         continue;
1119       }
1120 
1121       //
1122       // If this is the best match so far remember it
1123       //
1124       if (DescEnd > Target) {
1125         if (NeedGuard) {
1126           DescEnd = AdjustMemoryS (
1127                       DescEnd + 1 - DescNumberOfBytes,
1128                       DescNumberOfBytes,
1129                       NumberOfBytes
1130                       );
1131           if (DescEnd == 0) {
1132             continue;
1133           }
1134         }
1135 
1136         Target = DescEnd;
1137       }
1138     }
1139   }
1140 
1141   //
1142   // If this is a grow down, adjust target to be the allocation base
1143   //
1144   Target -= NumberOfBytes - 1;
1145 
1146   //
1147   // If we didn't find a match, return 0
1148   //
1149   if ((Target & EFI_PAGE_MASK) != 0) {
1150     return 0;
1151   }
1152 
1153   return Target;
1154 }
1155 
1156 
1157 /**
1158   Internal function.  Finds a consecutive free page range below
1159   the requested address
1160 
1161   @param  MaxAddress             The address that the range must be below
1162   @param  NoPages                Number of pages needed
1163   @param  NewType                The type of memory the range is going to be
1164                                  turned into
1165   @param  Alignment              Bits to align with
1166   @param  NeedGuard              Flag to indicate Guard page is needed or not
1167 
1168   @return The base address of the range, or 0 if the range was not found.
1169 
1170 **/
1171 UINT64
FindFreePages(IN UINT64 MaxAddress,IN UINT64 NoPages,IN EFI_MEMORY_TYPE NewType,IN UINTN Alignment,IN BOOLEAN NeedGuard)1172 FindFreePages (
1173     IN UINT64           MaxAddress,
1174     IN UINT64           NoPages,
1175     IN EFI_MEMORY_TYPE  NewType,
1176     IN UINTN            Alignment,
1177     IN BOOLEAN          NeedGuard
1178     )
1179 {
1180   UINT64   Start;
1181 
1182   //
1183   // Attempt to find free pages in the preferred bin based on the requested memory type
1184   //
1185   if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
1186     Start = CoreFindFreePagesI (
1187               mMemoryTypeStatistics[NewType].MaximumAddress,
1188               mMemoryTypeStatistics[NewType].BaseAddress,
1189               NoPages,
1190               NewType,
1191               Alignment,
1192               NeedGuard
1193               );
1194     if (Start != 0) {
1195       return Start;
1196     }
1197   }
1198 
1199   //
1200   // Attempt to find free pages in the default allocation bin
1201   //
1202   if (MaxAddress >= mDefaultMaximumAddress) {
1203     Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType,
1204                                 Alignment, NeedGuard);
1205     if (Start != 0) {
1206       if (Start < mDefaultBaseAddress) {
1207         mDefaultBaseAddress = Start;
1208       }
1209       return Start;
1210     }
1211   }
1212 
1213   //
1214   // The allocation did not succeed in any of the prefered bins even after
1215   // promoting resources. Attempt to find free pages anywhere is the requested
1216   // address range.  If this allocation fails, then there are not enough
1217   // resources anywhere to satisfy the request.
1218   //
1219   Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment,
1220                               NeedGuard);
1221   if (Start != 0) {
1222     return Start;
1223   }
1224 
1225   //
1226   // If allocations from the preferred bins fail, then attempt to promote memory resources.
1227   //
1228   if (!PromoteMemoryResource ()) {
1229     return 0;
1230   }
1231 
1232   //
1233   // If any memory resources were promoted, then re-attempt the allocation
1234   //
1235   return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
1236 }
1237 
1238 
1239 /**
1240   Allocates pages from the memory map.
1241 
1242   @param  Type                   The type of allocation to perform
1243   @param  MemoryType             The type of memory to turn the allocated pages
1244                                  into
1245   @param  NumberOfPages          The number of pages to allocate
1246   @param  Memory                 A pointer to receive the base allocated memory
1247                                  address
1248   @param  NeedGuard              Flag to indicate Guard page is needed or not
1249 
1250   @return Status. On success, Memory is filled in with the base address allocated
1251   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in
1252                                  spec.
1253   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
1254   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
1255   @retval EFI_SUCCESS            Pages successfully allocated.
1256 
1257 **/
1258 EFI_STATUS
1259 EFIAPI
CoreInternalAllocatePages(IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN NumberOfPages,IN OUT EFI_PHYSICAL_ADDRESS * Memory,IN BOOLEAN NeedGuard)1260 CoreInternalAllocatePages (
1261   IN EFI_ALLOCATE_TYPE      Type,
1262   IN EFI_MEMORY_TYPE        MemoryType,
1263   IN UINTN                  NumberOfPages,
1264   IN OUT EFI_PHYSICAL_ADDRESS  *Memory,
1265   IN BOOLEAN                NeedGuard
1266   )
1267 {
1268   EFI_STATUS      Status;
1269   UINT64          Start;
1270   UINT64          NumberOfBytes;
1271   UINT64          End;
1272   UINT64          MaxAddress;
1273   UINTN           Alignment;
1274 
1275   if ((UINT32)Type >= MaxAllocateType) {
1276     return EFI_INVALID_PARAMETER;
1277   }
1278 
1279   if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
1280        (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
1281     return EFI_INVALID_PARAMETER;
1282   }
1283 
1284   if (Memory == NULL) {
1285     return EFI_INVALID_PARAMETER;
1286   }
1287 
1288   Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1289 
1290   if  (MemoryType == EfiACPIReclaimMemory   ||
1291        MemoryType == EfiACPIMemoryNVS       ||
1292        MemoryType == EfiRuntimeServicesCode ||
1293        MemoryType == EfiRuntimeServicesData) {
1294 
1295     Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1296   }
1297 
1298   if (Type == AllocateAddress) {
1299     if ((*Memory & (Alignment - 1)) != 0) {
1300       return EFI_NOT_FOUND;
1301     }
1302   }
1303 
1304   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1305   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1306 
1307   //
1308   // If this is for below a particular address, then
1309   //
1310   Start = *Memory;
1311 
1312   //
1313   // The max address is the max natively addressable address for the processor
1314   //
1315   MaxAddress = MAX_ALLOC_ADDRESS;
1316 
1317   //
1318   // Check for Type AllocateAddress,
1319   // if NumberOfPages is 0 or
1320   // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
1321   // if (Start + NumberOfBytes) rolls over 0 or
1322   // if Start is above MAX_ALLOC_ADDRESS or
1323   // if End is above MAX_ALLOC_ADDRESS,
1324   // return EFI_NOT_FOUND.
1325   //
1326   if (Type == AllocateAddress) {
1327     if ((NumberOfPages == 0) ||
1328         (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {
1329       return EFI_NOT_FOUND;
1330     }
1331     NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1332     End = Start + NumberOfBytes - 1;
1333 
1334     if ((Start >= End) ||
1335         (Start > MaxAddress) ||
1336         (End > MaxAddress)) {
1337       return EFI_NOT_FOUND;
1338     }
1339   }
1340 
1341   if (Type == AllocateMaxAddress) {
1342     MaxAddress = Start;
1343   }
1344 
1345   CoreAcquireMemoryLock ();
1346 
1347   //
1348   // If not a specific address, then find an address to allocate
1349   //
1350   if (Type != AllocateAddress) {
1351     Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,
1352                            NeedGuard);
1353     if (Start == 0) {
1354       Status = EFI_OUT_OF_RESOURCES;
1355       goto Done;
1356     }
1357   }
1358 
1359   //
1360   // Convert pages from FreeMemory to the requested type
1361   //
1362   if (NeedGuard) {
1363     Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);
1364   } else {
1365     Status = CoreConvertPages(Start, NumberOfPages, MemoryType);
1366   }
1367 
1368 Done:
1369   CoreReleaseMemoryLock ();
1370 
1371   if (!EFI_ERROR (Status)) {
1372     if (NeedGuard) {
1373       SetGuardForMemory (Start, NumberOfPages);
1374     }
1375     *Memory = Start;
1376   }
1377 
1378   return Status;
1379 }
1380 
1381 /**
1382   Allocates pages from the memory map.
1383 
1384   @param  Type                   The type of allocation to perform
1385   @param  MemoryType             The type of memory to turn the allocated pages
1386                                  into
1387   @param  NumberOfPages          The number of pages to allocate
1388   @param  Memory                 A pointer to receive the base allocated memory
1389                                  address
1390 
1391   @return Status. On success, Memory is filled in with the base address allocated
1392   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in
1393                                  spec.
1394   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
1395   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
1396   @retval EFI_SUCCESS            Pages successfully allocated.
1397 
1398 **/
1399 EFI_STATUS
1400 EFIAPI
CoreAllocatePages(IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN NumberOfPages,OUT EFI_PHYSICAL_ADDRESS * Memory)1401 CoreAllocatePages (
1402   IN  EFI_ALLOCATE_TYPE     Type,
1403   IN  EFI_MEMORY_TYPE       MemoryType,
1404   IN  UINTN                 NumberOfPages,
1405   OUT EFI_PHYSICAL_ADDRESS  *Memory
1406   )
1407 {
1408   EFI_STATUS  Status;
1409   BOOLEAN     NeedGuard;
1410 
1411   NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
1412   Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
1413                                       NeedGuard);
1414   if (!EFI_ERROR (Status)) {
1415     CoreUpdateProfile (
1416       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1417       MemoryProfileActionAllocatePages,
1418       MemoryType,
1419       EFI_PAGES_TO_SIZE (NumberOfPages),
1420       (VOID *) (UINTN) *Memory,
1421       NULL
1422       );
1423     InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1424     ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,
1425       EFI_PAGES_TO_SIZE (NumberOfPages));
1426   }
1427   return Status;
1428 }
1429 
1430 /**
1431   Frees previous allocated pages.
1432 
1433   @param  Memory                 Base address of memory being freed
1434   @param  NumberOfPages          The number of pages to free
1435   @param  MemoryType             Pointer to memory type
1436 
1437   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
1438   @retval EFI_INVALID_PARAMETER  Address not aligned
1439   @return EFI_SUCCESS         -Pages successfully freed.
1440 
1441 **/
1442 EFI_STATUS
1443 EFIAPI
CoreInternalFreePages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages,OUT EFI_MEMORY_TYPE * MemoryType OPTIONAL)1444 CoreInternalFreePages (
1445   IN EFI_PHYSICAL_ADDRESS   Memory,
1446   IN UINTN                  NumberOfPages,
1447   OUT EFI_MEMORY_TYPE       *MemoryType OPTIONAL
1448   )
1449 {
1450   EFI_STATUS      Status;
1451   LIST_ENTRY      *Link;
1452   MEMORY_MAP      *Entry;
1453   UINTN           Alignment;
1454   BOOLEAN         IsGuarded;
1455 
1456   //
1457   // Free the range
1458   //
1459   CoreAcquireMemoryLock ();
1460 
1461   //
1462   // Find the entry that the covers the range
1463   //
1464   IsGuarded = FALSE;
1465   Entry = NULL;
1466   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1467     Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1468     if (Entry->Start <= Memory && Entry->End > Memory) {
1469         break;
1470     }
1471   }
1472   if (Link == &gMemoryMap) {
1473     Status = EFI_NOT_FOUND;
1474     goto Done;
1475   }
1476 
1477   Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1478 
1479   ASSERT (Entry != NULL);
1480   if  (Entry->Type == EfiACPIReclaimMemory   ||
1481        Entry->Type == EfiACPIMemoryNVS       ||
1482        Entry->Type == EfiRuntimeServicesCode ||
1483        Entry->Type == EfiRuntimeServicesData) {
1484 
1485     Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1486 
1487   }
1488 
1489   if ((Memory & (Alignment - 1)) != 0) {
1490     Status = EFI_INVALID_PARAMETER;
1491     goto Done;
1492   }
1493 
1494   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1495   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1496 
1497   if (MemoryType != NULL) {
1498     *MemoryType = Entry->Type;
1499   }
1500 
1501   IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
1502               IsMemoryGuarded (Memory);
1503   if (IsGuarded) {
1504     Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,
1505                                         EfiConventionalMemory);
1506   } else {
1507     Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1508   }
1509 
1510 Done:
1511   CoreReleaseMemoryLock ();
1512   return Status;
1513 }
1514 
1515 /**
1516   Frees previous allocated pages.
1517 
1518   @param  Memory                 Base address of memory being freed
1519   @param  NumberOfPages          The number of pages to free
1520 
1521   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
1522   @retval EFI_INVALID_PARAMETER  Address not aligned
1523   @return EFI_SUCCESS         -Pages successfully freed.
1524 
1525 **/
1526 EFI_STATUS
1527 EFIAPI
CoreFreePages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages)1528 CoreFreePages (
1529   IN EFI_PHYSICAL_ADDRESS  Memory,
1530   IN UINTN                 NumberOfPages
1531   )
1532 {
1533   EFI_STATUS        Status;
1534   EFI_MEMORY_TYPE   MemoryType;
1535 
1536   Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
1537   if (!EFI_ERROR (Status)) {
1538     GuardFreedPagesChecked (Memory, NumberOfPages);
1539     CoreUpdateProfile (
1540       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1541       MemoryProfileActionFreePages,
1542       MemoryType,
1543       EFI_PAGES_TO_SIZE (NumberOfPages),
1544       (VOID *) (UINTN) Memory,
1545       NULL
1546       );
1547     InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1548     ApplyMemoryProtectionPolicy (MemoryType, EfiConventionalMemory, Memory,
1549       EFI_PAGES_TO_SIZE (NumberOfPages));
1550   }
1551   return Status;
1552 }
1553 
1554 /**
1555   This function checks to see if the last memory map descriptor in a memory map
1556   can be merged with any of the other memory map descriptors in a memorymap.
1557   Memory descriptors may be merged if they are adjacent and have the same type
1558   and attributes.
1559 
1560   @param  MemoryMap              A pointer to the start of the memory map.
1561   @param  MemoryMapDescriptor    A pointer to the last descriptor in MemoryMap.
1562   @param  DescriptorSize         The size, in bytes, of an individual
1563                                  EFI_MEMORY_DESCRIPTOR.
1564 
1565   @return  A pointer to the next available descriptor in MemoryMap
1566 
1567 **/
1568 EFI_MEMORY_DESCRIPTOR *
MergeMemoryMapDescriptor(IN EFI_MEMORY_DESCRIPTOR * MemoryMap,IN EFI_MEMORY_DESCRIPTOR * MemoryMapDescriptor,IN UINTN DescriptorSize)1569 MergeMemoryMapDescriptor (
1570   IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,
1571   IN EFI_MEMORY_DESCRIPTOR  *MemoryMapDescriptor,
1572   IN UINTN                  DescriptorSize
1573   )
1574 {
1575   //
1576   // Traverse the array of descriptors in MemoryMap
1577   //
1578   for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1579     //
1580     // Check to see if the Type fields are identical.
1581     //
1582     if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1583       continue;
1584     }
1585 
1586     //
1587     // Check to see if the Attribute fields are identical.
1588     //
1589     if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1590       continue;
1591     }
1592 
1593     //
1594     // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1595     //
1596     if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1597       //
1598       // Merge MemoryMapDescriptor into MemoryMap
1599       //
1600       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1601 
1602       //
1603       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1604       //
1605       return MemoryMapDescriptor;
1606     }
1607 
1608     //
1609     // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1610     //
1611     if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1612       //
1613       // Merge MemoryMapDescriptor into MemoryMap
1614       //
1615       MemoryMap->PhysicalStart  = MemoryMapDescriptor->PhysicalStart;
1616       MemoryMap->VirtualStart   = MemoryMapDescriptor->VirtualStart;
1617       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1618 
1619       //
1620       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1621       //
1622       return MemoryMapDescriptor;
1623     }
1624   }
1625 
1626   //
1627   // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1628   //
1629   // Return the slot immediately after MemoryMapDescriptor as the next available
1630   // slot in the MemoryMap array
1631   //
1632   return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1633 }
1634 
1635 /**
1636   This function returns a copy of the current memory map. The map is an array of
1637   memory descriptors, each of which describes a contiguous block of memory.
1638 
1639   @param  MemoryMapSize          A pointer to the size, in bytes, of the
1640                                  MemoryMap buffer. On input, this is the size of
1641                                  the buffer allocated by the caller.  On output,
1642                                  it is the size of the buffer returned by the
1643                                  firmware  if the buffer was large enough, or the
1644                                  size of the buffer needed  to contain the map if
1645                                  the buffer was too small.
1646   @param  MemoryMap              A pointer to the buffer in which firmware places
1647                                  the current memory map.
1648   @param  MapKey                 A pointer to the location in which firmware
1649                                  returns the key for the current memory map.
1650   @param  DescriptorSize         A pointer to the location in which firmware
1651                                  returns the size, in bytes, of an individual
1652                                  EFI_MEMORY_DESCRIPTOR.
1653   @param  DescriptorVersion      A pointer to the location in which firmware
1654                                  returns the version number associated with the
1655                                  EFI_MEMORY_DESCRIPTOR.
1656 
1657   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
1658                                  buffer.
1659   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
1660                                  buffer size needed to hold the memory map is
1661                                  returned in MemoryMapSize.
1662   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
1663 
1664 **/
1665 EFI_STATUS
1666 EFIAPI
CoreGetMemoryMap(IN OUT UINTN * MemoryMapSize,IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,OUT UINTN * MapKey,OUT UINTN * DescriptorSize,OUT UINT32 * DescriptorVersion)1667 CoreGetMemoryMap (
1668   IN OUT UINTN                  *MemoryMapSize,
1669   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
1670   OUT UINTN                     *MapKey,
1671   OUT UINTN                     *DescriptorSize,
1672   OUT UINT32                    *DescriptorVersion
1673   )
1674 {
1675   EFI_STATUS                        Status;
1676   UINTN                             Size;
1677   UINTN                             BufferSize;
1678   UINTN                             NumberOfEntries;
1679   LIST_ENTRY                        *Link;
1680   MEMORY_MAP                        *Entry;
1681   EFI_GCD_MAP_ENTRY                 *GcdMapEntry;
1682   EFI_GCD_MAP_ENTRY                 MergeGcdMapEntry;
1683   EFI_MEMORY_TYPE                   Type;
1684   EFI_MEMORY_DESCRIPTOR             *MemoryMapStart;
1685   EFI_MEMORY_DESCRIPTOR             *MemoryMapEnd;
1686 
1687   //
1688   // Make sure the parameters are valid
1689   //
1690   if (MemoryMapSize == NULL) {
1691     return EFI_INVALID_PARAMETER;
1692   }
1693 
1694   CoreAcquireGcdMemoryLock ();
1695 
1696   //
1697   // Count the number of Reserved and runtime MMIO entries
1698   // And, count the number of Persistent entries.
1699   //
1700   NumberOfEntries = 0;
1701   for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1702     GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1703     if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
1704         (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1705         ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1706         ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1707       NumberOfEntries ++;
1708     }
1709   }
1710 
1711   Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1712 
1713   //
1714   // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1715   // prevent people from having pointer math bugs in their code.
1716   // now you have to use *DescriptorSize to make things work.
1717   //
1718   Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1719 
1720   if (DescriptorSize != NULL) {
1721     *DescriptorSize = Size;
1722   }
1723 
1724   if (DescriptorVersion != NULL) {
1725     *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1726   }
1727 
1728   CoreAcquireMemoryLock ();
1729 
1730   //
1731   // Compute the buffer size needed to fit the entire map
1732   //
1733   BufferSize = Size * NumberOfEntries;
1734   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1735     BufferSize += Size;
1736   }
1737 
1738   if (*MemoryMapSize < BufferSize) {
1739     Status = EFI_BUFFER_TOO_SMALL;
1740     goto Done;
1741   }
1742 
1743   if (MemoryMap == NULL) {
1744     Status = EFI_INVALID_PARAMETER;
1745     goto Done;
1746   }
1747 
1748   //
1749   // Build the map
1750   //
1751   ZeroMem (MemoryMap, BufferSize);
1752   MemoryMapStart = MemoryMap;
1753   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1754     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1755     ASSERT (Entry->VirtualStart == 0);
1756 
1757     //
1758     // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1759     //
1760     MemoryMap->Type           = Entry->Type;
1761     MemoryMap->PhysicalStart  = Entry->Start;
1762     MemoryMap->VirtualStart   = Entry->VirtualStart;
1763     MemoryMap->NumberOfPages  = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1764     //
1765     // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1766     // memory type bin and needs to be converted to the same memory type as the rest of the
1767     // memory type bin in order to minimize EFI Memory Map changes across reboots.  This
1768     // improves the chances for a successful S4 resume in the presence of minor page allocation
1769     // differences across reboots.
1770     //
1771     if (MemoryMap->Type == EfiConventionalMemory) {
1772       for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1773         if (mMemoryTypeStatistics[Type].Special                        &&
1774             mMemoryTypeStatistics[Type].NumberOfPages > 0              &&
1775             Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress    &&
1776             Entry->End   <= mMemoryTypeStatistics[Type].MaximumAddress) {
1777           MemoryMap->Type = Type;
1778         }
1779       }
1780     }
1781     MemoryMap->Attribute = Entry->Attribute;
1782     if (MemoryMap->Type < EfiMaxMemoryType) {
1783       if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1784         MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1785       }
1786     }
1787 
1788     //
1789     // Check to see if the new Memory Map Descriptor can be merged with an
1790     // existing descriptor if they are adjacent and have the same attributes
1791     //
1792     MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1793   }
1794 
1795 
1796   ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1797   GcdMapEntry = NULL;
1798   for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1799     if (Link != &mGcdMemorySpaceMap) {
1800       //
1801       // Merge adjacent same type and attribute GCD memory range
1802       //
1803       GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1804 
1805       if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1806           (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1807           (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1808           (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
1809         MergeGcdMapEntry.EndAddress  = GcdMapEntry->EndAddress;
1810         continue;
1811       }
1812     }
1813 
1814     if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1815         ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1816         ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1817       //
1818       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1819       // it will be recorded as page PhysicalStart and NumberOfPages.
1820       //
1821       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1822       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1823 
1824       //
1825       // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1826       //
1827       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1828       MemoryMap->VirtualStart  = 0;
1829       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1830       MemoryMap->Attribute     = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1831                                 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1832                                 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1833 
1834       if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1835         MemoryMap->Type = EfiReservedMemoryType;
1836       } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1837         if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1838           MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1839         } else {
1840           MemoryMap->Type = EfiMemoryMappedIO;
1841         }
1842       }
1843 
1844       //
1845       // Check to see if the new Memory Map Descriptor can be merged with an
1846       // existing descriptor if they are adjacent and have the same attributes
1847       //
1848       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1849     }
1850 
1851     if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
1852       //
1853       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1854       // it will be recorded as page PhysicalStart and NumberOfPages.
1855       //
1856       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1857       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1858 
1859       //
1860       // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1861       //
1862       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1863       MemoryMap->VirtualStart  = 0;
1864       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1865       MemoryMap->Attribute     = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1866                                 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1867                                 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1868       MemoryMap->Type          = EfiPersistentMemory;
1869 
1870       //
1871       // Check to see if the new Memory Map Descriptor can be merged with an
1872       // existing descriptor if they are adjacent and have the same attributes
1873       //
1874       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1875     }
1876     if (Link == &mGcdMemorySpaceMap) {
1877       //
1878       // break loop when arrive at head.
1879       //
1880       break;
1881     }
1882     if (GcdMapEntry != NULL) {
1883       //
1884       // Copy new GCD map entry for the following GCD range merge
1885       //
1886       CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1887     }
1888   }
1889 
1890   //
1891   // Compute the size of the buffer actually used after all memory map descriptor merge operations
1892   //
1893   BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1894 
1895   //
1896   // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1897   //       set attributes and change memory paging attribute accordingly.
1898   //       But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1899   //       value from Capabilities in GCD memory map. This might cause
1900   //       boot problems. Clearing all paging related capabilities can
1901   //       workaround it. Following code is supposed to be removed once
1902   //       the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in
1903   //       UEFI spec and adopted by both EDK-II Core and all supported
1904   //       OSs.
1905   //
1906   MemoryMapEnd = MemoryMap;
1907   MemoryMap = MemoryMapStart;
1908   while (MemoryMap < MemoryMapEnd) {
1909     MemoryMap->Attribute &= ~(UINT64)(EFI_MEMORY_RP | EFI_MEMORY_RO |
1910                                       EFI_MEMORY_XP);
1911     MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
1912   }
1913   MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
1914   MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
1915 
1916   Status = EFI_SUCCESS;
1917 
1918 Done:
1919   //
1920   // Update the map key finally
1921   //
1922   if (MapKey != NULL) {
1923     *MapKey = mMemoryMapKey;
1924   }
1925 
1926   CoreReleaseMemoryLock ();
1927 
1928   CoreReleaseGcdMemoryLock ();
1929 
1930   *MemoryMapSize = BufferSize;
1931 
1932   DEBUG_CODE (
1933     DumpGuardedMemoryBitmap ();
1934   );
1935 
1936   return Status;
1937 }
1938 
1939 
1940 /**
1941   Internal function.  Used by the pool functions to allocate pages
1942   to back pool allocation requests.
1943 
1944   @param  PoolType               The type of memory for the new pool pages
1945   @param  NumberOfPages          No of pages to allocate
1946   @param  Alignment              Bits to align.
1947   @param  NeedGuard              Flag to indicate Guard page is needed or not
1948 
1949   @return The allocated memory, or NULL
1950 
1951 **/
1952 VOID *
CoreAllocatePoolPages(IN EFI_MEMORY_TYPE PoolType,IN UINTN NumberOfPages,IN UINTN Alignment,IN BOOLEAN NeedGuard)1953 CoreAllocatePoolPages (
1954   IN EFI_MEMORY_TYPE    PoolType,
1955   IN UINTN              NumberOfPages,
1956   IN UINTN              Alignment,
1957   IN BOOLEAN            NeedGuard
1958   )
1959 {
1960   UINT64            Start;
1961 
1962   //
1963   // Find the pages to convert
1964   //
1965   Start = FindFreePages (MAX_ALLOC_ADDRESS, NumberOfPages, PoolType, Alignment,
1966                          NeedGuard);
1967 
1968   //
1969   // Convert it to boot services data
1970   //
1971   if (Start == 0) {
1972     DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1973   } else {
1974     if (NeedGuard) {
1975       CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
1976     } else {
1977       CoreConvertPages (Start, NumberOfPages, PoolType);
1978     }
1979   }
1980 
1981   return (VOID *)(UINTN) Start;
1982 }
1983 
1984 
1985 /**
1986   Internal function.  Frees pool pages allocated via AllocatePoolPages ()
1987 
1988   @param  Memory                 The base address to free
1989   @param  NumberOfPages          The number of pages to free
1990 
1991 **/
1992 VOID
CoreFreePoolPages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages)1993 CoreFreePoolPages (
1994   IN EFI_PHYSICAL_ADDRESS   Memory,
1995   IN UINTN                  NumberOfPages
1996   )
1997 {
1998   CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1999 }
2000 
2001 
2002 
2003 /**
2004   Make sure the memory map is following all the construction rules,
2005   it is the last time to check memory map error before exit boot services.
2006 
2007   @param  MapKey                 Memory map key
2008 
2009   @retval EFI_INVALID_PARAMETER  Memory map not consistent with construction
2010                                  rules.
2011   @retval EFI_SUCCESS            Valid memory map.
2012 
2013 **/
2014 EFI_STATUS
CoreTerminateMemoryMap(IN UINTN MapKey)2015 CoreTerminateMemoryMap (
2016   IN UINTN          MapKey
2017   )
2018 {
2019   EFI_STATUS        Status;
2020   LIST_ENTRY        *Link;
2021   MEMORY_MAP        *Entry;
2022 
2023   Status = EFI_SUCCESS;
2024 
2025   CoreAcquireMemoryLock ();
2026 
2027   if (MapKey == mMemoryMapKey) {
2028 
2029     //
2030     // Make sure the memory map is following all the construction rules
2031     // This is the last chance we will be able to display any messages on
2032     // the  console devices.
2033     //
2034 
2035     for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
2036       Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
2037       if (Entry->Type < EfiMaxMemoryType) {
2038         if (mMemoryTypeStatistics[Entry->Type].Runtime) {
2039           ASSERT (Entry->Type != EfiACPIReclaimMemory);
2040           ASSERT (Entry->Type != EfiACPIMemoryNVS);
2041           if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2042             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2043             Status =  EFI_INVALID_PARAMETER;
2044             goto Done;
2045           }
2046           if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2047             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2048             Status =  EFI_INVALID_PARAMETER;
2049             goto Done;
2050           }
2051         }
2052       }
2053     }
2054 
2055     //
2056     // The map key they gave us matches what we expect. Fall through and
2057     // return success. In an ideal world we would clear out all of
2058     // EfiBootServicesCode and EfiBootServicesData. However this function
2059     // is not the last one called by ExitBootServices(), so we have to
2060     // preserve the memory contents.
2061     //
2062   } else {
2063     Status = EFI_INVALID_PARAMETER;
2064   }
2065 
2066 Done:
2067   CoreReleaseMemoryLock ();
2068 
2069   return Status;
2070 }
2071 
2072 
2073 
2074 
2075 
2076 
2077 
2078 
2079 
2080