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   EFI_MEMORY_TYPE  CheckType;
1275 
1276   if ((UINT32)Type >= MaxAllocateType) {
1277     return EFI_INVALID_PARAMETER;
1278   }
1279 
1280   if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
1281        (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
1282     return EFI_INVALID_PARAMETER;
1283   }
1284 
1285   if (Memory == NULL) {
1286     return EFI_INVALID_PARAMETER;
1287   }
1288 
1289   Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1290 
1291   if  (MemoryType == EfiACPIReclaimMemory   ||
1292        MemoryType == EfiACPIMemoryNVS       ||
1293        MemoryType == EfiRuntimeServicesCode ||
1294        MemoryType == EfiRuntimeServicesData) {
1295 
1296     Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1297   }
1298 
1299   if (Type == AllocateAddress) {
1300     if ((*Memory & (Alignment - 1)) != 0) {
1301       return EFI_NOT_FOUND;
1302     }
1303   }
1304 
1305   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1306   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1307 
1308   //
1309   // If this is for below a particular address, then
1310   //
1311   Start = *Memory;
1312 
1313   //
1314   // The max address is the max natively addressable address for the processor
1315   //
1316   MaxAddress = MAX_ALLOC_ADDRESS;
1317 
1318   //
1319   // Check for Type AllocateAddress,
1320   // if NumberOfPages is 0 or
1321   // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
1322   // if (Start + NumberOfBytes) rolls over 0 or
1323   // if Start is above MAX_ALLOC_ADDRESS or
1324   // if End is above MAX_ALLOC_ADDRESS,
1325   // if Start..End overlaps any tracked MemoryTypeStatistics range
1326   // return EFI_NOT_FOUND.
1327   //
1328   if (Type == AllocateAddress) {
1329     if ((NumberOfPages == 0) ||
1330         (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {
1331       return EFI_NOT_FOUND;
1332     }
1333     NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1334     End = Start + NumberOfBytes - 1;
1335 
1336     if ((Start >= End) ||
1337         (Start > MaxAddress) ||
1338         (End > MaxAddress)) {
1339       return EFI_NOT_FOUND;
1340     }
1341 
1342     //
1343     // A driver is allowed to call AllocatePages using an AllocateAddress type.  This type of
1344     // AllocatePage request the exact physical address if it is not used.  The existing code
1345     // will allow this request even in 'special' pages.  The problem with this is that the
1346     // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
1347     // fragmented.
1348     //
1349 
1350     for (CheckType = (EFI_MEMORY_TYPE) 0; CheckType < EfiMaxMemoryType; CheckType++) {
1351       if (MemoryType != CheckType &&
1352           mMemoryTypeStatistics[CheckType].Special &&
1353           mMemoryTypeStatistics[CheckType].NumberOfPages > 0) {
1354         if (Start >= mMemoryTypeStatistics[CheckType].BaseAddress &&
1355             Start <= mMemoryTypeStatistics[CheckType].MaximumAddress) {
1356           return EFI_NOT_FOUND;
1357         }
1358         if (End >= mMemoryTypeStatistics[CheckType].BaseAddress &&
1359             End <= mMemoryTypeStatistics[CheckType].MaximumAddress) {
1360           return EFI_NOT_FOUND;
1361         }
1362         if (Start < mMemoryTypeStatistics[CheckType].BaseAddress &&
1363             End   > mMemoryTypeStatistics[CheckType].MaximumAddress) {
1364           return EFI_NOT_FOUND;
1365         }
1366       }
1367     }
1368   }
1369 
1370   if (Type == AllocateMaxAddress) {
1371     MaxAddress = Start;
1372   }
1373 
1374   CoreAcquireMemoryLock ();
1375 
1376   //
1377   // If not a specific address, then find an address to allocate
1378   //
1379   if (Type != AllocateAddress) {
1380     Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,
1381                            NeedGuard);
1382     if (Start == 0) {
1383       Status = EFI_OUT_OF_RESOURCES;
1384       goto Done;
1385     }
1386   }
1387 
1388   //
1389   // Convert pages from FreeMemory to the requested type
1390   //
1391   if (NeedGuard) {
1392     Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);
1393   } else {
1394     Status = CoreConvertPages(Start, NumberOfPages, MemoryType);
1395   }
1396 
1397 Done:
1398   CoreReleaseMemoryLock ();
1399 
1400   if (!EFI_ERROR (Status)) {
1401     if (NeedGuard) {
1402       SetGuardForMemory (Start, NumberOfPages);
1403     }
1404     *Memory = Start;
1405   }
1406 
1407   return Status;
1408 }
1409 
1410 /**
1411   Allocates pages from the memory map.
1412 
1413   @param  Type                   The type of allocation to perform
1414   @param  MemoryType             The type of memory to turn the allocated pages
1415                                  into
1416   @param  NumberOfPages          The number of pages to allocate
1417   @param  Memory                 A pointer to receive the base allocated memory
1418                                  address
1419 
1420   @return Status. On success, Memory is filled in with the base address allocated
1421   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in
1422                                  spec.
1423   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
1424   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
1425   @retval EFI_SUCCESS            Pages successfully allocated.
1426 
1427 **/
1428 EFI_STATUS
1429 EFIAPI
CoreAllocatePages(IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN NumberOfPages,OUT EFI_PHYSICAL_ADDRESS * Memory)1430 CoreAllocatePages (
1431   IN  EFI_ALLOCATE_TYPE     Type,
1432   IN  EFI_MEMORY_TYPE       MemoryType,
1433   IN  UINTN                 NumberOfPages,
1434   OUT EFI_PHYSICAL_ADDRESS  *Memory
1435   )
1436 {
1437   EFI_STATUS  Status;
1438   BOOLEAN     NeedGuard;
1439 
1440   NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
1441   Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
1442                                       NeedGuard);
1443   if (!EFI_ERROR (Status)) {
1444     CoreUpdateProfile (
1445       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1446       MemoryProfileActionAllocatePages,
1447       MemoryType,
1448       EFI_PAGES_TO_SIZE (NumberOfPages),
1449       (VOID *) (UINTN) *Memory,
1450       NULL
1451       );
1452     InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1453     ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,
1454       EFI_PAGES_TO_SIZE (NumberOfPages));
1455   }
1456   return Status;
1457 }
1458 
1459 /**
1460   Frees previous allocated pages.
1461 
1462   @param  Memory                 Base address of memory being freed
1463   @param  NumberOfPages          The number of pages to free
1464   @param  MemoryType             Pointer to memory type
1465 
1466   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
1467   @retval EFI_INVALID_PARAMETER  Address not aligned
1468   @return EFI_SUCCESS         -Pages successfully freed.
1469 
1470 **/
1471 EFI_STATUS
1472 EFIAPI
CoreInternalFreePages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages,OUT EFI_MEMORY_TYPE * MemoryType OPTIONAL)1473 CoreInternalFreePages (
1474   IN EFI_PHYSICAL_ADDRESS   Memory,
1475   IN UINTN                  NumberOfPages,
1476   OUT EFI_MEMORY_TYPE       *MemoryType OPTIONAL
1477   )
1478 {
1479   EFI_STATUS      Status;
1480   LIST_ENTRY      *Link;
1481   MEMORY_MAP      *Entry;
1482   UINTN           Alignment;
1483   BOOLEAN         IsGuarded;
1484 
1485   //
1486   // Free the range
1487   //
1488   CoreAcquireMemoryLock ();
1489 
1490   //
1491   // Find the entry that the covers the range
1492   //
1493   IsGuarded = FALSE;
1494   Entry = NULL;
1495   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1496     Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1497     if (Entry->Start <= Memory && Entry->End > Memory) {
1498         break;
1499     }
1500   }
1501   if (Link == &gMemoryMap) {
1502     Status = EFI_NOT_FOUND;
1503     goto Done;
1504   }
1505 
1506   Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1507 
1508   ASSERT (Entry != NULL);
1509   if  (Entry->Type == EfiACPIReclaimMemory   ||
1510        Entry->Type == EfiACPIMemoryNVS       ||
1511        Entry->Type == EfiRuntimeServicesCode ||
1512        Entry->Type == EfiRuntimeServicesData) {
1513 
1514     Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1515 
1516   }
1517 
1518   if ((Memory & (Alignment - 1)) != 0) {
1519     Status = EFI_INVALID_PARAMETER;
1520     goto Done;
1521   }
1522 
1523   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1524   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1525 
1526   if (MemoryType != NULL) {
1527     *MemoryType = Entry->Type;
1528   }
1529 
1530   IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
1531               IsMemoryGuarded (Memory);
1532   if (IsGuarded) {
1533     Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,
1534                                         EfiConventionalMemory);
1535   } else {
1536     Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1537   }
1538 
1539 Done:
1540   CoreReleaseMemoryLock ();
1541   return Status;
1542 }
1543 
1544 /**
1545   Frees previous allocated pages.
1546 
1547   @param  Memory                 Base address of memory being freed
1548   @param  NumberOfPages          The number of pages to free
1549 
1550   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
1551   @retval EFI_INVALID_PARAMETER  Address not aligned
1552   @return EFI_SUCCESS         -Pages successfully freed.
1553 
1554 **/
1555 EFI_STATUS
1556 EFIAPI
CoreFreePages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages)1557 CoreFreePages (
1558   IN EFI_PHYSICAL_ADDRESS  Memory,
1559   IN UINTN                 NumberOfPages
1560   )
1561 {
1562   EFI_STATUS        Status;
1563   EFI_MEMORY_TYPE   MemoryType;
1564 
1565   Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
1566   if (!EFI_ERROR (Status)) {
1567     GuardFreedPagesChecked (Memory, NumberOfPages);
1568     CoreUpdateProfile (
1569       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1570       MemoryProfileActionFreePages,
1571       MemoryType,
1572       EFI_PAGES_TO_SIZE (NumberOfPages),
1573       (VOID *) (UINTN) Memory,
1574       NULL
1575       );
1576     InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1577     ApplyMemoryProtectionPolicy (MemoryType, EfiConventionalMemory, Memory,
1578       EFI_PAGES_TO_SIZE (NumberOfPages));
1579   }
1580   return Status;
1581 }
1582 
1583 /**
1584   This function checks to see if the last memory map descriptor in a memory map
1585   can be merged with any of the other memory map descriptors in a memorymap.
1586   Memory descriptors may be merged if they are adjacent and have the same type
1587   and attributes.
1588 
1589   @param  MemoryMap              A pointer to the start of the memory map.
1590   @param  MemoryMapDescriptor    A pointer to the last descriptor in MemoryMap.
1591   @param  DescriptorSize         The size, in bytes, of an individual
1592                                  EFI_MEMORY_DESCRIPTOR.
1593 
1594   @return  A pointer to the next available descriptor in MemoryMap
1595 
1596 **/
1597 EFI_MEMORY_DESCRIPTOR *
MergeMemoryMapDescriptor(IN EFI_MEMORY_DESCRIPTOR * MemoryMap,IN EFI_MEMORY_DESCRIPTOR * MemoryMapDescriptor,IN UINTN DescriptorSize)1598 MergeMemoryMapDescriptor (
1599   IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,
1600   IN EFI_MEMORY_DESCRIPTOR  *MemoryMapDescriptor,
1601   IN UINTN                  DescriptorSize
1602   )
1603 {
1604   //
1605   // Traverse the array of descriptors in MemoryMap
1606   //
1607   for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1608     //
1609     // Check to see if the Type fields are identical.
1610     //
1611     if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1612       continue;
1613     }
1614 
1615     //
1616     // Check to see if the Attribute fields are identical.
1617     //
1618     if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1619       continue;
1620     }
1621 
1622     //
1623     // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1624     //
1625     if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1626       //
1627       // Merge MemoryMapDescriptor into MemoryMap
1628       //
1629       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1630 
1631       //
1632       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1633       //
1634       return MemoryMapDescriptor;
1635     }
1636 
1637     //
1638     // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1639     //
1640     if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1641       //
1642       // Merge MemoryMapDescriptor into MemoryMap
1643       //
1644       MemoryMap->PhysicalStart  = MemoryMapDescriptor->PhysicalStart;
1645       MemoryMap->VirtualStart   = MemoryMapDescriptor->VirtualStart;
1646       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1647 
1648       //
1649       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1650       //
1651       return MemoryMapDescriptor;
1652     }
1653   }
1654 
1655   //
1656   // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1657   //
1658   // Return the slot immediately after MemoryMapDescriptor as the next available
1659   // slot in the MemoryMap array
1660   //
1661   return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1662 }
1663 
1664 /**
1665   This function returns a copy of the current memory map. The map is an array of
1666   memory descriptors, each of which describes a contiguous block of memory.
1667 
1668   @param  MemoryMapSize          A pointer to the size, in bytes, of the
1669                                  MemoryMap buffer. On input, this is the size of
1670                                  the buffer allocated by the caller.  On output,
1671                                  it is the size of the buffer returned by the
1672                                  firmware  if the buffer was large enough, or the
1673                                  size of the buffer needed  to contain the map if
1674                                  the buffer was too small.
1675   @param  MemoryMap              A pointer to the buffer in which firmware places
1676                                  the current memory map.
1677   @param  MapKey                 A pointer to the location in which firmware
1678                                  returns the key for the current memory map.
1679   @param  DescriptorSize         A pointer to the location in which firmware
1680                                  returns the size, in bytes, of an individual
1681                                  EFI_MEMORY_DESCRIPTOR.
1682   @param  DescriptorVersion      A pointer to the location in which firmware
1683                                  returns the version number associated with the
1684                                  EFI_MEMORY_DESCRIPTOR.
1685 
1686   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
1687                                  buffer.
1688   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
1689                                  buffer size needed to hold the memory map is
1690                                  returned in MemoryMapSize.
1691   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
1692 
1693 **/
1694 EFI_STATUS
1695 EFIAPI
CoreGetMemoryMap(IN OUT UINTN * MemoryMapSize,IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,OUT UINTN * MapKey,OUT UINTN * DescriptorSize,OUT UINT32 * DescriptorVersion)1696 CoreGetMemoryMap (
1697   IN OUT UINTN                  *MemoryMapSize,
1698   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
1699   OUT UINTN                     *MapKey,
1700   OUT UINTN                     *DescriptorSize,
1701   OUT UINT32                    *DescriptorVersion
1702   )
1703 {
1704   EFI_STATUS                        Status;
1705   UINTN                             Size;
1706   UINTN                             BufferSize;
1707   UINTN                             NumberOfEntries;
1708   LIST_ENTRY                        *Link;
1709   MEMORY_MAP                        *Entry;
1710   EFI_GCD_MAP_ENTRY                 *GcdMapEntry;
1711   EFI_GCD_MAP_ENTRY                 MergeGcdMapEntry;
1712   EFI_MEMORY_TYPE                   Type;
1713   EFI_MEMORY_DESCRIPTOR             *MemoryMapStart;
1714   EFI_MEMORY_DESCRIPTOR             *MemoryMapEnd;
1715 
1716   //
1717   // Make sure the parameters are valid
1718   //
1719   if (MemoryMapSize == NULL) {
1720     return EFI_INVALID_PARAMETER;
1721   }
1722 
1723   CoreAcquireGcdMemoryLock ();
1724 
1725   //
1726   // Count the number of Reserved and runtime MMIO entries
1727   // And, count the number of Persistent entries.
1728   //
1729   NumberOfEntries = 0;
1730   for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1731     GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1732     if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
1733         (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1734         ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1735         ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1736       NumberOfEntries ++;
1737     }
1738   }
1739 
1740   Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1741 
1742   //
1743   // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1744   // prevent people from having pointer math bugs in their code.
1745   // now you have to use *DescriptorSize to make things work.
1746   //
1747   Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1748 
1749   if (DescriptorSize != NULL) {
1750     *DescriptorSize = Size;
1751   }
1752 
1753   if (DescriptorVersion != NULL) {
1754     *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1755   }
1756 
1757   CoreAcquireMemoryLock ();
1758 
1759   //
1760   // Compute the buffer size needed to fit the entire map
1761   //
1762   BufferSize = Size * NumberOfEntries;
1763   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1764     BufferSize += Size;
1765   }
1766 
1767   if (*MemoryMapSize < BufferSize) {
1768     Status = EFI_BUFFER_TOO_SMALL;
1769     goto Done;
1770   }
1771 
1772   if (MemoryMap == NULL) {
1773     Status = EFI_INVALID_PARAMETER;
1774     goto Done;
1775   }
1776 
1777   //
1778   // Build the map
1779   //
1780   ZeroMem (MemoryMap, BufferSize);
1781   MemoryMapStart = MemoryMap;
1782   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1783     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1784     ASSERT (Entry->VirtualStart == 0);
1785 
1786     //
1787     // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1788     //
1789     MemoryMap->Type           = Entry->Type;
1790     MemoryMap->PhysicalStart  = Entry->Start;
1791     MemoryMap->VirtualStart   = Entry->VirtualStart;
1792     MemoryMap->NumberOfPages  = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1793     //
1794     // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1795     // memory type bin and needs to be converted to the same memory type as the rest of the
1796     // memory type bin in order to minimize EFI Memory Map changes across reboots.  This
1797     // improves the chances for a successful S4 resume in the presence of minor page allocation
1798     // differences across reboots.
1799     //
1800     if (MemoryMap->Type == EfiConventionalMemory) {
1801       for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1802         if (mMemoryTypeStatistics[Type].Special                        &&
1803             mMemoryTypeStatistics[Type].NumberOfPages > 0              &&
1804             Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress    &&
1805             Entry->End   <= mMemoryTypeStatistics[Type].MaximumAddress) {
1806           MemoryMap->Type = Type;
1807         }
1808       }
1809     }
1810     MemoryMap->Attribute = Entry->Attribute;
1811     if (MemoryMap->Type < EfiMaxMemoryType) {
1812       if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1813         MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1814       }
1815     }
1816 
1817     //
1818     // Check to see if the new Memory Map Descriptor can be merged with an
1819     // existing descriptor if they are adjacent and have the same attributes
1820     //
1821     MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1822   }
1823 
1824 
1825   ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1826   GcdMapEntry = NULL;
1827   for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1828     if (Link != &mGcdMemorySpaceMap) {
1829       //
1830       // Merge adjacent same type and attribute GCD memory range
1831       //
1832       GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1833 
1834       if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1835           (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1836           (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1837           (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
1838         MergeGcdMapEntry.EndAddress  = GcdMapEntry->EndAddress;
1839         continue;
1840       }
1841     }
1842 
1843     if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1844         ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1845         ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1846       //
1847       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1848       // it will be recorded as page PhysicalStart and NumberOfPages.
1849       //
1850       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1851       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1852 
1853       //
1854       // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1855       //
1856       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1857       MemoryMap->VirtualStart  = 0;
1858       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1859       MemoryMap->Attribute     = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1860                                 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
1861 
1862       if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1863         MemoryMap->Type = EfiReservedMemoryType;
1864       } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1865         if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1866           MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1867         } else {
1868           MemoryMap->Type = EfiMemoryMappedIO;
1869         }
1870       }
1871 
1872       //
1873       // Check to see if the new Memory Map Descriptor can be merged with an
1874       // existing descriptor if they are adjacent and have the same attributes
1875       //
1876       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1877     }
1878 
1879     if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
1880       //
1881       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1882       // it will be recorded as page PhysicalStart and NumberOfPages.
1883       //
1884       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1885       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1886 
1887       //
1888       // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1889       //
1890       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1891       MemoryMap->VirtualStart  = 0;
1892       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1893       MemoryMap->Attribute     = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1894                                 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
1895       MemoryMap->Type          = EfiPersistentMemory;
1896 
1897       //
1898       // Check to see if the new Memory Map Descriptor can be merged with an
1899       // existing descriptor if they are adjacent and have the same attributes
1900       //
1901       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1902     }
1903     if (Link == &mGcdMemorySpaceMap) {
1904       //
1905       // break loop when arrive at head.
1906       //
1907       break;
1908     }
1909     if (GcdMapEntry != NULL) {
1910       //
1911       // Copy new GCD map entry for the following GCD range merge
1912       //
1913       CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1914     }
1915   }
1916 
1917   //
1918   // Compute the size of the buffer actually used after all memory map descriptor merge operations
1919   //
1920   BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1921 
1922   //
1923   // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1924   //       set attributes and change memory paging attribute accordingly.
1925   //       But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1926   //       value from Capabilities in GCD memory map. This might cause
1927   //       boot problems. Clearing all page-access permission related
1928   //       capabilities can workaround it. Following code is supposed to
1929   //       be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute
1930   //       is clarified in UEFI spec and adopted by both EDK-II Core and
1931   //       all supported OSs.
1932   //
1933   MemoryMapEnd = MemoryMap;
1934   MemoryMap = MemoryMapStart;
1935   while (MemoryMap < MemoryMapEnd) {
1936     MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;
1937     MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
1938   }
1939   MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
1940   MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
1941 
1942   Status = EFI_SUCCESS;
1943 
1944 Done:
1945   //
1946   // Update the map key finally
1947   //
1948   if (MapKey != NULL) {
1949     *MapKey = mMemoryMapKey;
1950   }
1951 
1952   CoreReleaseMemoryLock ();
1953 
1954   CoreReleaseGcdMemoryLock ();
1955 
1956   *MemoryMapSize = BufferSize;
1957 
1958   DEBUG_CODE (
1959     DumpGuardedMemoryBitmap ();
1960   );
1961 
1962   return Status;
1963 }
1964 
1965 
1966 /**
1967   Internal function.  Used by the pool functions to allocate pages
1968   to back pool allocation requests.
1969 
1970   @param  PoolType               The type of memory for the new pool pages
1971   @param  NumberOfPages          No of pages to allocate
1972   @param  Alignment              Bits to align.
1973   @param  NeedGuard              Flag to indicate Guard page is needed or not
1974 
1975   @return The allocated memory, or NULL
1976 
1977 **/
1978 VOID *
CoreAllocatePoolPages(IN EFI_MEMORY_TYPE PoolType,IN UINTN NumberOfPages,IN UINTN Alignment,IN BOOLEAN NeedGuard)1979 CoreAllocatePoolPages (
1980   IN EFI_MEMORY_TYPE    PoolType,
1981   IN UINTN              NumberOfPages,
1982   IN UINTN              Alignment,
1983   IN BOOLEAN            NeedGuard
1984   )
1985 {
1986   UINT64            Start;
1987 
1988   //
1989   // Find the pages to convert
1990   //
1991   Start = FindFreePages (MAX_ALLOC_ADDRESS, NumberOfPages, PoolType, Alignment,
1992                          NeedGuard);
1993 
1994   //
1995   // Convert it to boot services data
1996   //
1997   if (Start == 0) {
1998     DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1999   } else {
2000     if (NeedGuard) {
2001       CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
2002     } else {
2003       CoreConvertPages (Start, NumberOfPages, PoolType);
2004     }
2005   }
2006 
2007   return (VOID *)(UINTN) Start;
2008 }
2009 
2010 
2011 /**
2012   Internal function.  Frees pool pages allocated via AllocatePoolPages ()
2013 
2014   @param  Memory                 The base address to free
2015   @param  NumberOfPages          The number of pages to free
2016 
2017 **/
2018 VOID
CoreFreePoolPages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages)2019 CoreFreePoolPages (
2020   IN EFI_PHYSICAL_ADDRESS   Memory,
2021   IN UINTN                  NumberOfPages
2022   )
2023 {
2024   CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
2025 }
2026 
2027 
2028 
2029 /**
2030   Make sure the memory map is following all the construction rules,
2031   it is the last time to check memory map error before exit boot services.
2032 
2033   @param  MapKey                 Memory map key
2034 
2035   @retval EFI_INVALID_PARAMETER  Memory map not consistent with construction
2036                                  rules.
2037   @retval EFI_SUCCESS            Valid memory map.
2038 
2039 **/
2040 EFI_STATUS
CoreTerminateMemoryMap(IN UINTN MapKey)2041 CoreTerminateMemoryMap (
2042   IN UINTN          MapKey
2043   )
2044 {
2045   EFI_STATUS        Status;
2046   LIST_ENTRY        *Link;
2047   MEMORY_MAP        *Entry;
2048 
2049   Status = EFI_SUCCESS;
2050 
2051   CoreAcquireMemoryLock ();
2052 
2053   if (MapKey == mMemoryMapKey) {
2054 
2055     //
2056     // Make sure the memory map is following all the construction rules
2057     // This is the last chance we will be able to display any messages on
2058     // the  console devices.
2059     //
2060 
2061     for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
2062       Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
2063       if (Entry->Type < EfiMaxMemoryType) {
2064         if (mMemoryTypeStatistics[Entry->Type].Runtime) {
2065           ASSERT (Entry->Type != EfiACPIReclaimMemory);
2066           ASSERT (Entry->Type != EfiACPIMemoryNVS);
2067           if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2068             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2069             Status =  EFI_INVALID_PARAMETER;
2070             goto Done;
2071           }
2072           if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2073             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2074             Status =  EFI_INVALID_PARAMETER;
2075             goto Done;
2076           }
2077         }
2078       }
2079     }
2080 
2081     //
2082     // The map key they gave us matches what we expect. Fall through and
2083     // return success. In an ideal world we would clear out all of
2084     // EfiBootServicesCode and EfiBootServicesData. However this function
2085     // is not the last one called by ExitBootServices(), so we have to
2086     // preserve the memory contents.
2087     //
2088   } else {
2089     Status = EFI_INVALID_PARAMETER;
2090   }
2091 
2092 Done:
2093   CoreReleaseMemoryLock ();
2094 
2095   return Status;
2096 }
2097 
2098 
2099 
2100 
2101 
2102 
2103 
2104 
2105 
2106