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