1 /** @file
2   UEFI Memory page management functions.
3 
4 Copyright (c) 2007 - 2015, 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 funciton
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 > (Start + NumberOfBytes))) {
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          MaxAddress;
1205   UINTN           Alignment;
1206 
1207   if ((UINT32)Type >= MaxAllocateType) {
1208     return EFI_INVALID_PARAMETER;
1209   }
1210 
1211   if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
1212        (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
1213     return EFI_INVALID_PARAMETER;
1214   }
1215 
1216   if (Memory == NULL) {
1217     return EFI_INVALID_PARAMETER;
1218   }
1219 
1220   Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1221 
1222   if  (MemoryType == EfiACPIReclaimMemory   ||
1223        MemoryType == EfiACPIMemoryNVS       ||
1224        MemoryType == EfiRuntimeServicesCode ||
1225        MemoryType == EfiRuntimeServicesData) {
1226 
1227     Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1228   }
1229 
1230   if (Type == AllocateAddress) {
1231     if ((*Memory & (Alignment - 1)) != 0) {
1232       return EFI_NOT_FOUND;
1233     }
1234   }
1235 
1236   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1237   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1238 
1239   //
1240   // If this is for below a particular address, then
1241   //
1242   Start = *Memory;
1243 
1244   //
1245   // The max address is the max natively addressable address for the processor
1246   //
1247   MaxAddress = MAX_ADDRESS;
1248 
1249   if (Type == AllocateMaxAddress) {
1250     MaxAddress = Start;
1251   }
1252 
1253   CoreAcquireMemoryLock ();
1254 
1255   //
1256   // If not a specific address, then find an address to allocate
1257   //
1258   if (Type != AllocateAddress) {
1259     Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
1260     if (Start == 0) {
1261       Status = EFI_OUT_OF_RESOURCES;
1262       goto Done;
1263     }
1264   }
1265 
1266   //
1267   // Convert pages from FreeMemory to the requested type
1268   //
1269   Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
1270 
1271 Done:
1272   CoreReleaseMemoryLock ();
1273 
1274   if (!EFI_ERROR (Status)) {
1275     *Memory = Start;
1276   }
1277 
1278   return Status;
1279 }
1280 
1281 /**
1282   Allocates pages from the memory map.
1283 
1284   @param  Type                   The type of allocation to perform
1285   @param  MemoryType             The type of memory to turn the allocated pages
1286                                  into
1287   @param  NumberOfPages          The number of pages to allocate
1288   @param  Memory                 A pointer to receive the base allocated memory
1289                                  address
1290 
1291   @return Status. On success, Memory is filled in with the base address allocated
1292   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in
1293                                  spec.
1294   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
1295   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
1296   @retval EFI_SUCCESS            Pages successfully allocated.
1297 
1298 **/
1299 EFI_STATUS
1300 EFIAPI
CoreAllocatePages(IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN NumberOfPages,OUT EFI_PHYSICAL_ADDRESS * Memory)1301 CoreAllocatePages (
1302   IN  EFI_ALLOCATE_TYPE     Type,
1303   IN  EFI_MEMORY_TYPE       MemoryType,
1304   IN  UINTN                 NumberOfPages,
1305   OUT EFI_PHYSICAL_ADDRESS  *Memory
1306   )
1307 {
1308   EFI_STATUS  Status;
1309 
1310   Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
1311   if (!EFI_ERROR (Status)) {
1312     CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages, MemoryType, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) *Memory);
1313   }
1314   return Status;
1315 }
1316 
1317 /**
1318   Frees previous allocated pages.
1319 
1320   @param  Memory                 Base address of memory being freed
1321   @param  NumberOfPages          The number of pages to free
1322 
1323   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
1324   @retval EFI_INVALID_PARAMETER  Address not aligned
1325   @return EFI_SUCCESS         -Pages successfully freed.
1326 
1327 **/
1328 EFI_STATUS
1329 EFIAPI
CoreInternalFreePages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages)1330 CoreInternalFreePages (
1331   IN EFI_PHYSICAL_ADDRESS   Memory,
1332   IN UINTN                  NumberOfPages
1333   )
1334 {
1335   EFI_STATUS      Status;
1336   LIST_ENTRY      *Link;
1337   MEMORY_MAP      *Entry;
1338   UINTN           Alignment;
1339 
1340   //
1341   // Free the range
1342   //
1343   CoreAcquireMemoryLock ();
1344 
1345   //
1346   // Find the entry that the covers the range
1347   //
1348   Entry = NULL;
1349   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1350     Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1351     if (Entry->Start <= Memory && Entry->End > Memory) {
1352         break;
1353     }
1354   }
1355   if (Link == &gMemoryMap) {
1356     Status = EFI_NOT_FOUND;
1357     goto Done;
1358   }
1359 
1360   Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1361 
1362   ASSERT (Entry != NULL);
1363   if  (Entry->Type == EfiACPIReclaimMemory   ||
1364        Entry->Type == EfiACPIMemoryNVS       ||
1365        Entry->Type == EfiRuntimeServicesCode ||
1366        Entry->Type == EfiRuntimeServicesData) {
1367 
1368     Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1369 
1370   }
1371 
1372   if ((Memory & (Alignment - 1)) != 0) {
1373     Status = EFI_INVALID_PARAMETER;
1374     goto Done;
1375   }
1376 
1377   NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1378   NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1379 
1380   Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1381 
1382   if (EFI_ERROR (Status)) {
1383     goto Done;
1384   }
1385 
1386 Done:
1387   CoreReleaseMemoryLock ();
1388   return Status;
1389 }
1390 
1391 /**
1392   Frees previous allocated pages.
1393 
1394   @param  Memory                 Base address of memory being freed
1395   @param  NumberOfPages          The number of pages to free
1396 
1397   @retval EFI_NOT_FOUND          Could not find the entry that covers the range
1398   @retval EFI_INVALID_PARAMETER  Address not aligned
1399   @return EFI_SUCCESS         -Pages successfully freed.
1400 
1401 **/
1402 EFI_STATUS
1403 EFIAPI
CoreFreePages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages)1404 CoreFreePages (
1405   IN EFI_PHYSICAL_ADDRESS  Memory,
1406   IN UINTN                 NumberOfPages
1407   )
1408 {
1409   EFI_STATUS  Status;
1410 
1411   Status = CoreInternalFreePages (Memory, NumberOfPages);
1412   if (!EFI_ERROR (Status)) {
1413     CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePages, (EFI_MEMORY_TYPE) 0, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) Memory);
1414   }
1415   return Status;
1416 }
1417 
1418 /**
1419   This function checks to see if the last memory map descriptor in a memory map
1420   can be merged with any of the other memory map descriptors in a memorymap.
1421   Memory descriptors may be merged if they are adjacent and have the same type
1422   and attributes.
1423 
1424   @param  MemoryMap              A pointer to the start of the memory map.
1425   @param  MemoryMapDescriptor    A pointer to the last descriptor in MemoryMap.
1426   @param  DescriptorSize         The size, in bytes, of an individual
1427                                  EFI_MEMORY_DESCRIPTOR.
1428 
1429   @return  A pointer to the next available descriptor in MemoryMap
1430 
1431 **/
1432 EFI_MEMORY_DESCRIPTOR *
MergeMemoryMapDescriptor(IN EFI_MEMORY_DESCRIPTOR * MemoryMap,IN EFI_MEMORY_DESCRIPTOR * MemoryMapDescriptor,IN UINTN DescriptorSize)1433 MergeMemoryMapDescriptor (
1434   IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,
1435   IN EFI_MEMORY_DESCRIPTOR  *MemoryMapDescriptor,
1436   IN UINTN                  DescriptorSize
1437   )
1438 {
1439   //
1440   // Traverse the array of descriptors in MemoryMap
1441   //
1442   for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1443     //
1444     // Check to see if the Type fields are identical.
1445     //
1446     if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1447       continue;
1448     }
1449 
1450     //
1451     // Check to see if the Attribute fields are identical.
1452     //
1453     if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1454       continue;
1455     }
1456 
1457     //
1458     // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1459     //
1460     if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1461       //
1462       // Merge MemoryMapDescriptor into MemoryMap
1463       //
1464       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1465 
1466       //
1467       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1468       //
1469       return MemoryMapDescriptor;
1470     }
1471 
1472     //
1473     // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1474     //
1475     if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1476       //
1477       // Merge MemoryMapDescriptor into MemoryMap
1478       //
1479       MemoryMap->PhysicalStart  = MemoryMapDescriptor->PhysicalStart;
1480       MemoryMap->VirtualStart   = MemoryMapDescriptor->VirtualStart;
1481       MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1482 
1483       //
1484       // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1485       //
1486       return MemoryMapDescriptor;
1487     }
1488   }
1489 
1490   //
1491   // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1492   //
1493   // Return the slot immediately after MemoryMapDescriptor as the next available
1494   // slot in the MemoryMap array
1495   //
1496   return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1497 }
1498 
1499 /**
1500   This function returns a copy of the current memory map. The map is an array of
1501   memory descriptors, each of which describes a contiguous block of memory.
1502 
1503   @param  MemoryMapSize          A pointer to the size, in bytes, of the
1504                                  MemoryMap buffer. On input, this is the size of
1505                                  the buffer allocated by the caller.  On output,
1506                                  it is the size of the buffer returned by the
1507                                  firmware  if the buffer was large enough, or the
1508                                  size of the buffer needed  to contain the map if
1509                                  the buffer was too small.
1510   @param  MemoryMap              A pointer to the buffer in which firmware places
1511                                  the current memory map.
1512   @param  MapKey                 A pointer to the location in which firmware
1513                                  returns the key for the current memory map.
1514   @param  DescriptorSize         A pointer to the location in which firmware
1515                                  returns the size, in bytes, of an individual
1516                                  EFI_MEMORY_DESCRIPTOR.
1517   @param  DescriptorVersion      A pointer to the location in which firmware
1518                                  returns the version number associated with the
1519                                  EFI_MEMORY_DESCRIPTOR.
1520 
1521   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
1522                                  buffer.
1523   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
1524                                  buffer size needed to hold the memory map is
1525                                  returned in MemoryMapSize.
1526   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
1527 
1528 **/
1529 EFI_STATUS
1530 EFIAPI
CoreGetMemoryMap(IN OUT UINTN * MemoryMapSize,IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,OUT UINTN * MapKey,OUT UINTN * DescriptorSize,OUT UINT32 * DescriptorVersion)1531 CoreGetMemoryMap (
1532   IN OUT UINTN                  *MemoryMapSize,
1533   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
1534   OUT UINTN                     *MapKey,
1535   OUT UINTN                     *DescriptorSize,
1536   OUT UINT32                    *DescriptorVersion
1537   )
1538 {
1539   EFI_STATUS                        Status;
1540   UINTN                             Size;
1541   UINTN                             BufferSize;
1542   UINTN                             NumberOfEntries;
1543   LIST_ENTRY                        *Link;
1544   MEMORY_MAP                        *Entry;
1545   EFI_GCD_MAP_ENTRY                 *GcdMapEntry;
1546   EFI_GCD_MAP_ENTRY                 MergeGcdMapEntry;
1547   EFI_MEMORY_TYPE                   Type;
1548   EFI_MEMORY_DESCRIPTOR             *MemoryMapStart;
1549 
1550   //
1551   // Make sure the parameters are valid
1552   //
1553   if (MemoryMapSize == NULL) {
1554     return EFI_INVALID_PARAMETER;
1555   }
1556 
1557   CoreAcquireGcdMemoryLock ();
1558 
1559   //
1560   // Count the number of Reserved and runtime MMIO entries
1561   // And, count the number of Persistent entries.
1562   //
1563   NumberOfEntries = 0;
1564   for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1565     GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1566     if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) ||
1567         (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1568         ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1569         ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1570       NumberOfEntries ++;
1571     }
1572   }
1573 
1574   Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1575 
1576   //
1577   // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1578   // prevent people from having pointer math bugs in their code.
1579   // now you have to use *DescriptorSize to make things work.
1580   //
1581   Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1582 
1583   if (DescriptorSize != NULL) {
1584     *DescriptorSize = Size;
1585   }
1586 
1587   if (DescriptorVersion != NULL) {
1588     *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1589   }
1590 
1591   CoreAcquireMemoryLock ();
1592 
1593   //
1594   // Compute the buffer size needed to fit the entire map
1595   //
1596   BufferSize = Size * NumberOfEntries;
1597   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1598     BufferSize += Size;
1599   }
1600 
1601   if (*MemoryMapSize < BufferSize) {
1602     Status = EFI_BUFFER_TOO_SMALL;
1603     goto Done;
1604   }
1605 
1606   if (MemoryMap == NULL) {
1607     Status = EFI_INVALID_PARAMETER;
1608     goto Done;
1609   }
1610 
1611   //
1612   // Build the map
1613   //
1614   ZeroMem (MemoryMap, BufferSize);
1615   MemoryMapStart = MemoryMap;
1616   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1617     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1618     ASSERT (Entry->VirtualStart == 0);
1619 
1620     //
1621     // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1622     //
1623     MemoryMap->Type           = Entry->Type;
1624     MemoryMap->PhysicalStart  = Entry->Start;
1625     MemoryMap->VirtualStart   = Entry->VirtualStart;
1626     MemoryMap->NumberOfPages  = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1627     //
1628     // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1629     // memory type bin and needs to be converted to the same memory type as the rest of the
1630     // memory type bin in order to minimize EFI Memory Map changes across reboots.  This
1631     // improves the chances for a successful S4 resume in the presence of minor page allocation
1632     // differences across reboots.
1633     //
1634     if (MemoryMap->Type == EfiConventionalMemory) {
1635       for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1636         if (mMemoryTypeStatistics[Type].Special                        &&
1637             mMemoryTypeStatistics[Type].NumberOfPages > 0              &&
1638             Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress    &&
1639             Entry->End   <= mMemoryTypeStatistics[Type].MaximumAddress) {
1640           MemoryMap->Type = Type;
1641         }
1642       }
1643     }
1644     MemoryMap->Attribute = Entry->Attribute;
1645     if (MemoryMap->Type < EfiMaxMemoryType) {
1646       if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1647         MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1648       }
1649     }
1650 
1651     //
1652     // Check to see if the new Memory Map Descriptor can be merged with an
1653     // existing descriptor if they are adjacent and have the same attributes
1654     //
1655     MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1656   }
1657 
1658 
1659   ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1660   GcdMapEntry = NULL;
1661   for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1662     if (Link != &mGcdMemorySpaceMap) {
1663       //
1664       // Merge adjacent same type and attribute GCD memory range
1665       //
1666       GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1667 
1668       if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1669           (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1670           (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1671           (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
1672         MergeGcdMapEntry.EndAddress  = GcdMapEntry->EndAddress;
1673         continue;
1674       }
1675     }
1676 
1677     if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1678         ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1679         ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1680       //
1681       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1682       // it will be recorded as page PhysicalStart and NumberOfPages.
1683       //
1684       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1685       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1686 
1687       //
1688       // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1689       //
1690       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1691       MemoryMap->VirtualStart  = 0;
1692       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1693       MemoryMap->Attribute     = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1694                                 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1695                                 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1696 
1697       if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1698         MemoryMap->Type = EfiReservedMemoryType;
1699       } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1700         if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1701           MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1702         } else {
1703           MemoryMap->Type = EfiMemoryMappedIO;
1704         }
1705       }
1706 
1707       //
1708       // Check to see if the new Memory Map Descriptor can be merged with an
1709       // existing descriptor if they are adjacent and have the same attributes
1710       //
1711       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1712     }
1713 
1714     if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistentMemory) {
1715       //
1716       // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1717       // it will be recorded as page PhysicalStart and NumberOfPages.
1718       //
1719       ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1720       ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1721 
1722       //
1723       // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1724       //
1725       MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1726       MemoryMap->VirtualStart  = 0;
1727       MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1728       MemoryMap->Attribute     = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1729                                 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1730                                 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1731       MemoryMap->Type          = EfiPersistentMemory;
1732 
1733       //
1734       // Check to see if the new Memory Map Descriptor can be merged with an
1735       // existing descriptor if they are adjacent and have the same attributes
1736       //
1737       MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1738     }
1739     if (Link == &mGcdMemorySpaceMap) {
1740       //
1741       // break loop when arrive at head.
1742       //
1743       break;
1744     }
1745     if (GcdMapEntry != NULL) {
1746       //
1747       // Copy new GCD map entry for the following GCD range merge
1748       //
1749       CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1750     }
1751   }
1752 
1753   //
1754   // Compute the size of the buffer actually used after all memory map descriptor merge operations
1755   //
1756   BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1757 
1758   Status = EFI_SUCCESS;
1759 
1760 Done:
1761   //
1762   // Update the map key finally
1763   //
1764   if (MapKey != NULL) {
1765     *MapKey = mMemoryMapKey;
1766   }
1767 
1768   CoreReleaseMemoryLock ();
1769 
1770   CoreReleaseGcdMemoryLock ();
1771 
1772   *MemoryMapSize = BufferSize;
1773 
1774   return Status;
1775 }
1776 
1777 
1778 /**
1779   Internal function.  Used by the pool functions to allocate pages
1780   to back pool allocation requests.
1781 
1782   @param  PoolType               The type of memory for the new pool pages
1783   @param  NumberOfPages          No of pages to allocate
1784   @param  Alignment              Bits to align.
1785 
1786   @return The allocated memory, or NULL
1787 
1788 **/
1789 VOID *
CoreAllocatePoolPages(IN EFI_MEMORY_TYPE PoolType,IN UINTN NumberOfPages,IN UINTN Alignment)1790 CoreAllocatePoolPages (
1791   IN EFI_MEMORY_TYPE    PoolType,
1792   IN UINTN              NumberOfPages,
1793   IN UINTN              Alignment
1794   )
1795 {
1796   UINT64            Start;
1797 
1798   //
1799   // Find the pages to convert
1800   //
1801   Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
1802 
1803   //
1804   // Convert it to boot services data
1805   //
1806   if (Start == 0) {
1807     DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1808   } else {
1809     CoreConvertPages (Start, NumberOfPages, PoolType);
1810   }
1811 
1812   return (VOID *)(UINTN) Start;
1813 }
1814 
1815 
1816 /**
1817   Internal function.  Frees pool pages allocated via AllocatePoolPages ()
1818 
1819   @param  Memory                 The base address to free
1820   @param  NumberOfPages          The number of pages to free
1821 
1822 **/
1823 VOID
CoreFreePoolPages(IN EFI_PHYSICAL_ADDRESS Memory,IN UINTN NumberOfPages)1824 CoreFreePoolPages (
1825   IN EFI_PHYSICAL_ADDRESS   Memory,
1826   IN UINTN                  NumberOfPages
1827   )
1828 {
1829   CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1830 }
1831 
1832 
1833 
1834 /**
1835   Make sure the memory map is following all the construction rules,
1836   it is the last time to check memory map error before exit boot services.
1837 
1838   @param  MapKey                 Memory map key
1839 
1840   @retval EFI_INVALID_PARAMETER  Memory map not consistent with construction
1841                                  rules.
1842   @retval EFI_SUCCESS            Valid memory map.
1843 
1844 **/
1845 EFI_STATUS
CoreTerminateMemoryMap(IN UINTN MapKey)1846 CoreTerminateMemoryMap (
1847   IN UINTN          MapKey
1848   )
1849 {
1850   EFI_STATUS        Status;
1851   LIST_ENTRY        *Link;
1852   MEMORY_MAP        *Entry;
1853 
1854   Status = EFI_SUCCESS;
1855 
1856   CoreAcquireMemoryLock ();
1857 
1858   if (MapKey == mMemoryMapKey) {
1859 
1860     //
1861     // Make sure the memory map is following all the construction rules
1862     // This is the last chance we will be able to display any messages on
1863     // the  console devices.
1864     //
1865 
1866     for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1867       Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1868       if (Entry->Type < EfiMaxMemoryType) {
1869         if (mMemoryTypeStatistics[Entry->Type].Runtime) {
1870           ASSERT (Entry->Type != EfiACPIReclaimMemory);
1871           ASSERT (Entry->Type != EfiACPIMemoryNVS);
1872           if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1873             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1874             Status =  EFI_INVALID_PARAMETER;
1875             goto Done;
1876           }
1877           if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1878             DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1879             Status =  EFI_INVALID_PARAMETER;
1880             goto Done;
1881           }
1882         }
1883       }
1884     }
1885 
1886     //
1887     // The map key they gave us matches what we expect. Fall through and
1888     // return success. In an ideal world we would clear out all of
1889     // EfiBootServicesCode and EfiBootServicesData. However this function
1890     // is not the last one called by ExitBootServices(), so we have to
1891     // preserve the memory contents.
1892     //
1893   } else {
1894     Status = EFI_INVALID_PARAMETER;
1895   }
1896 
1897 Done:
1898   CoreReleaseMemoryLock ();
1899 
1900   return Status;
1901 }
1902 
1903 
1904 
1905 
1906 
1907 
1908 
1909 
1910 
1911