2 UEFI Memory page management functions.
4 Copyright (c) 2007 - 2008, Intel Corporation. <BR>
5 All rights reserved. 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
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.
17 #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
20 // Entry for tracking the memory regions for each memory type to help cooalese like memory types
23 EFI_PHYSICAL_ADDRESS BaseAddress
;
24 EFI_PHYSICAL_ADDRESS MaximumAddress
;
25 UINT64 CurrentNumberOfPages
;
27 UINTN InformationIndex
;
30 } EFI_MEMORY_TYPE_STAISTICS
;
33 // MemoryMap - The current memory map
35 UINTN mMemoryMapKey
= 0;
38 // mMapStack - space to use as temp storage to build new map descriptors
39 // mMapDepth - depth of new descriptor stack
42 #define MAX_MAP_DEPTH 6
44 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
45 UINTN mFreeMapStack
= 0;
47 // This list maintain the free memory map list
49 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
50 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
52 EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
53 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
54 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
55 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
56 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
57 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
58 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
59 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
60 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
61 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
62 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
63 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
64 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
65 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
66 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
67 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
70 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= EFI_MAX_ADDRESS
;
72 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
73 { EfiReservedMemoryType
, 0 },
76 { EfiBootServicesCode
, 0 },
77 { EfiBootServicesData
, 0 },
78 { EfiRuntimeServicesCode
, 0 },
79 { EfiRuntimeServicesData
, 0 },
80 { EfiConventionalMemory
, 0 },
81 { EfiUnusableMemory
, 0 },
82 { EfiACPIReclaimMemory
, 0 },
83 { EfiACPIMemoryNVS
, 0 },
84 { EfiMemoryMappedIO
, 0 },
85 { EfiMemoryMappedIOPortSpace
, 0 },
87 { EfiMaxMemoryType
, 0 }
91 // Internal prototypes
94 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
98 PromoteMemoryResource (
103 Internal function. Adds a ranges to the memory map.
104 The range must not already exist in the map.
106 @param Type The type of memory range to add
107 @param Start The starting address in the memory range Must be
109 @param End The last address in the range Must be the last
111 @param Attribute The attributes of the memory range to add
113 @return None. The range is added to the memory map
118 IN EFI_MEMORY_TYPE Type
,
119 IN EFI_PHYSICAL_ADDRESS Start
,
120 IN EFI_PHYSICAL_ADDRESS End
,
125 Internal function. Moves any memory descriptors that are on the
126 temporary descriptor stack to heap.
130 CoreFreeMemoryMapStack (
135 Internal function. Converts a memory range to the specified type.
136 The range must exist in the memory map.
138 @param Start The first address of the range Must be page
140 @param NumberOfPages The number of pages to convert
141 @param NewType The new type for the memory range
143 @retval EFI_INVALID_PARAMETER Invalid parameter
144 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
145 range or convertion not allowed.
146 @retval EFI_SUCCESS Successfully converts the memory range to the
153 IN UINT64 NumberOfPages
,
154 IN EFI_MEMORY_TYPE NewType
158 Internal function. Removes a descriptor entry.
160 @param Entry The entry to remove
164 RemoveMemoryMapEntry (
169 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
170 If the list is emtry, then allocate a new page to refuel the list.
171 Please Note this algorithm to allocate the memory map descriptor has a property
172 that the memory allocated for memory entries always grows, and will never really be freed
173 For example, if the current boot uses 2000 memory map entries at the maximum point, but
174 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
175 memory map entries is still allocated from EfiBootServicesMemory.
178 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
182 AllocateMemoryMapEntry (
188 Enter critical section by gaining lock on gMemoryLock.
192 CoreAcquireMemoryLock (
196 CoreAcquireLock (&gMemoryLock
);
202 Exit critical section by releasing lock on gMemoryLock.
206 CoreReleaseMemoryLock (
210 CoreReleaseLock (&gMemoryLock
);
215 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
219 PromoteMemoryResource (
224 EFI_GCD_MAP_ENTRY
*Entry
;
226 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "Promote the memory resource\n"));
228 CoreAcquireGcdMemoryLock ();
230 Link
= mGcdMemorySpaceMap
.ForwardLink
;
231 while (Link
!= &mGcdMemorySpaceMap
) {
233 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
235 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
236 Entry
->EndAddress
< EFI_MAX_ADDRESS
&&
237 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
238 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
240 // Update the GCD map
242 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
243 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
244 Entry
->ImageHandle
= gDxeCoreImageHandle
;
245 Entry
->DeviceHandle
= NULL
;
248 // Add to allocable system memory resource
252 EfiConventionalMemory
,
255 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
257 CoreFreeMemoryMapStack ();
261 Link
= Link
->ForwardLink
;
264 CoreReleaseGcdMemoryLock ();
271 Called to initialize the memory map and add descriptors to
272 the current descriptor list.
273 The first descriptor that is added must be general usable
274 memory as the addition allocates heap.
276 @param Type The type of memory to add
277 @param Start The starting address in the memory range Must be
279 @param NumberOfPages The number of pages in the range
280 @param Attribute Attributes of the memory to add
282 @return None. The range is added to the memory map
286 CoreAddMemoryDescriptor (
287 IN EFI_MEMORY_TYPE Type
,
288 IN EFI_PHYSICAL_ADDRESS Start
,
289 IN UINT64 NumberOfPages
,
293 EFI_PHYSICAL_ADDRESS End
;
298 if ((Start
& EFI_PAGE_MASK
) != 0) {
302 if (Type
>= EfiMaxMemoryType
&& Type
<= 0x7fffffff) {
306 CoreAcquireMemoryLock ();
307 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
308 CoreAddRange (Type
, Start
, End
, Attribute
);
309 CoreFreeMemoryMapStack ();
310 CoreReleaseMemoryLock ();
313 // Check to see if the statistics for the different memory types have already been established
315 if (mMemoryTypeInformationInitialized
) {
320 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
322 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
324 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
326 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
327 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
331 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
333 // Allocate pages for the current memory type from the top of available memory
335 Status
= CoreAllocatePages (
338 gMemoryTypeInformation
[Index
].NumberOfPages
,
339 &mMemoryTypeStatistics
[Type
].BaseAddress
341 if (EFI_ERROR (Status
)) {
343 // If an error occurs allocating the pages for the current memory type, then
344 // free all the pages allocates for the previous memory types and return. This
345 // operation with be retied when/if more memory is added to the system
347 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
349 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
351 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
352 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
356 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
358 mMemoryTypeStatistics
[Type
].BaseAddress
,
359 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
361 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
362 mMemoryTypeStatistics
[Type
].MaximumAddress
= EFI_MAX_ADDRESS
;
369 // Compute the address at the top of the current statistics
371 mMemoryTypeStatistics
[Type
].MaximumAddress
=
372 mMemoryTypeStatistics
[Type
].BaseAddress
+
373 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
376 // If the current base address is the lowest address so far, then update the default
379 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
380 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
386 // There was enough system memory for all the the memory types were allocated. So,
387 // those memory areas can be freed for future allocations, and all future memory
388 // allocations can occur within their respective bins
390 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
392 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
394 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
395 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
399 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
401 mMemoryTypeStatistics
[Type
].BaseAddress
,
402 gMemoryTypeInformation
[Index
].NumberOfPages
404 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
405 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
410 // If the number of pages reserved for a memory type is 0, then all allocations for that type
411 // should be in the default range.
413 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
414 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
415 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
416 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
419 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
420 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== EFI_MAX_ADDRESS
) {
421 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
425 mMemoryTypeInformationInitialized
= TRUE
;
431 Internal function. Adds a ranges to the memory map.
432 The range must not already exist in the map.
434 @param Type The type of memory range to add
435 @param Start The starting address in the memory range Must be
437 @param End The last address in the range Must be the last
439 @param Attribute The attributes of the memory range to add
441 @return None. The range is added to the memory map
446 IN EFI_MEMORY_TYPE Type
,
447 IN EFI_PHYSICAL_ADDRESS Start
,
448 IN EFI_PHYSICAL_ADDRESS End
,
455 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
456 ASSERT (End
> Start
) ;
458 ASSERT_LOCKED (&gMemoryLock
);
460 DEBUG ((DEBUG_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
463 // Memory map being altered so updated key
468 // UEFI 2.0 added an event group for notificaiton on memory map changes.
469 // So we need to signal this Event Group every time the memory map changes.
470 // If we are in EFI 1.10 compatability mode no event groups will be
471 // found and nothing will happen we we call this function. These events
472 // will get signaled but since a lock is held around the call to this
473 // function the notificaiton events will only be called after this funciton
474 // returns and the lock is released.
476 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
479 // Look for adjoining memory descriptor
482 // Two memory descriptors can only be merged if they have the same Type
483 // and the same Attribute
486 Link
= gMemoryMap
.ForwardLink
;
487 while (Link
!= &gMemoryMap
) {
488 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
489 Link
= Link
->ForwardLink
;
491 if (Entry
->Type
!= Type
) {
495 if (Entry
->Attribute
!= Attribute
) {
499 if (Entry
->End
+ 1 == Start
) {
501 Start
= Entry
->Start
;
502 RemoveMemoryMapEntry (Entry
);
504 } else if (Entry
->Start
== End
+ 1) {
507 RemoveMemoryMapEntry (Entry
);
515 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
516 mMapStack
[mMapDepth
].FromPages
= FALSE
;
517 mMapStack
[mMapDepth
].Type
= Type
;
518 mMapStack
[mMapDepth
].Start
= Start
;
519 mMapStack
[mMapDepth
].End
= End
;
520 mMapStack
[mMapDepth
].VirtualStart
= 0;
521 mMapStack
[mMapDepth
].Attribute
= Attribute
;
522 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
525 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
532 Internal function. Moves any memory descriptors that are on the
533 temporary descriptor stack to heap.
537 CoreFreeMemoryMapStack (
545 ASSERT_LOCKED (&gMemoryLock
);
548 // If already freeing the map stack, then return
550 if (mFreeMapStack
!= 0) {
555 // Move the temporary memory descriptor stack into pool
559 while (mMapDepth
!= 0) {
561 // Deque an memory map entry from mFreeMemoryMapEntryList
563 Entry
= AllocateMemoryMapEntry ();
568 // Update to proper entry
572 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
575 // Move this entry to general memory
577 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
578 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
580 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
581 Entry
->FromPages
= TRUE
;
584 // Find insertion location
586 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
587 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
588 if (Entry2
->FromPages
&& Entry2
->Start
> Entry
->Start
) {
593 InsertTailList (Link2
, &Entry
->Link
);
597 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
598 // so here no need to move it to memory.
600 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
609 Internal function. Removes a descriptor entry.
611 @param Entry The entry to remove
615 RemoveMemoryMapEntry (
619 RemoveEntryList (&Entry
->Link
);
620 Entry
->Link
.ForwardLink
= NULL
;
622 if (Entry
->FromPages
) {
624 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
626 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
632 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
633 If the list is emtry, then allocate a new page to refuel the list.
634 Please Note this algorithm to allocate the memory map descriptor has a property
635 that the memory allocated for memory entries always grows, and will never really be freed
636 For example, if the current boot uses 2000 memory map entries at the maximum point, but
637 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
638 memory map entries is still allocated from EfiBootServicesMemory.
641 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
645 AllocateMemoryMapEntry (
649 MEMORY_MAP
* FreeDescriptorEntries
;
653 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
655 // The list is empty, to allocate one page to refuel the list
657 FreeDescriptorEntries
= CoreAllocatePoolPages (EfiBootServicesData
, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
658 if(FreeDescriptorEntries
!= NULL
) {
660 // Enque the free memmory map entries into the list
662 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION
/ sizeof(MEMORY_MAP
); Index
++) {
663 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
664 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
671 // dequeue the first descriptor from the list
673 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
674 RemoveEntryList (&Entry
->Link
);
681 Internal function. Converts a memory range to the specified type.
682 The range must exist in the memory map.
684 @param Start The first address of the range Must be page
686 @param NumberOfPages The number of pages to convert
687 @param NewType The new type for the memory range
689 @retval EFI_INVALID_PARAMETER Invalid parameter
690 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
691 range or convertion not allowed.
692 @retval EFI_SUCCESS Successfully converts the memory range to the
699 IN UINT64 NumberOfPages
,
700 IN EFI_MEMORY_TYPE NewType
704 UINT64 NumberOfBytes
;
712 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
713 End
= Start
+ NumberOfBytes
- 1;
715 ASSERT (NumberOfPages
);
716 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
717 ASSERT (End
> Start
) ;
718 ASSERT_LOCKED (&gMemoryLock
);
720 if (NumberOfPages
== 0 || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
> (Start
+ NumberOfBytes
))) {
721 return EFI_INVALID_PARAMETER
;
725 // Convert the entire range
728 while (Start
< End
) {
731 // Find the entry that the covers the range
733 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
734 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
736 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
741 if (Link
== &gMemoryMap
) {
742 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
743 return EFI_NOT_FOUND
;
747 // Convert range to the end, or to the end of the descriptor
748 // if that's all we've got
751 if (Entry
->End
< End
) {
752 RangeEnd
= Entry
->End
;
755 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to %d\n", Start
, RangeEnd
, NewType
));
758 // Debug code - verify conversion is allowed
760 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
761 DEBUG ((DEBUG_ERROR
, "ConvertPages: Incompatible memory types\n"));
762 return EFI_NOT_FOUND
;
766 // Update counters for the number of pages allocated to each memory type
768 if (Entry
->Type
>= 0 && Entry
->Type
< EfiMaxMemoryType
) {
769 if (Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&&
770 Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) {
771 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
772 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
774 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
779 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
) {
780 if (Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
781 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
782 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
>
783 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
784 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
790 // Pull range out of descriptor
792 if (Entry
->Start
== Start
) {
797 Entry
->Start
= RangeEnd
+ 1;
799 } else if (Entry
->End
== RangeEnd
) {
804 Entry
->End
= Start
- 1;
809 // Pull it out of the center, clip current
815 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
816 mMapStack
[mMapDepth
].FromPages
= FALSE
;
817 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
818 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
819 mMapStack
[mMapDepth
].End
= Entry
->End
;
822 // Inherit Attribute from the Memory Descriptor that is being clipped
824 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
826 Entry
->End
= Start
- 1;
827 ASSERT (Entry
->Start
< Entry
->End
);
829 Entry
= &mMapStack
[mMapDepth
];
830 InsertTailList (&gMemoryMap
, &Entry
->Link
);
833 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
837 // The new range inherits the same Attribute as the Entry
838 //it is being cut out of
840 Attribute
= Entry
->Attribute
;
843 // If the descriptor is empty, then remove it from the map
845 if (Entry
->Start
== Entry
->End
+ 1) {
846 RemoveMemoryMapEntry (Entry
);
851 // Add our new range in
853 CoreAddRange (NewType
, Start
, RangeEnd
, Attribute
);
856 // Move any map descriptor stack to general pool
858 CoreFreeMemoryMapStack ();
861 // Bump the starting address, and convert the next range
863 Start
= RangeEnd
+ 1;
867 // Converted the whole range, done
876 Internal function. Finds a consecutive free page range below
877 the requested address.
879 @param MaxAddress The address that the range must be below
880 @param NumberOfPages Number of pages needed
881 @param NewType The type of memory the range is going to be
883 @param Alignment Bits to align with
885 @return The base address of the range, or 0 if the range was not found
890 IN UINT64 MaxAddress
,
891 IN UINT64 NumberOfPages
,
892 IN EFI_MEMORY_TYPE NewType
,
896 UINT64 NumberOfBytes
;
900 UINT64 DescNumberOfBytes
;
904 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
908 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
911 // If MaxAddress is not aligned to the end of a page
915 // Change MaxAddress to be 1 page lower
917 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
920 // Set MaxAddress to a page boundary
922 MaxAddress
&= ~EFI_PAGE_MASK
;
925 // Set MaxAddress to end of the page
927 MaxAddress
|= EFI_PAGE_MASK
;
930 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
933 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
934 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
937 // If it's not a free entry, don't bother with it
939 if (Entry
->Type
!= EfiConventionalMemory
) {
943 DescStart
= Entry
->Start
;
944 DescEnd
= Entry
->End
;
947 // If desc is past max allowed address, skip it
949 if (DescStart
>= MaxAddress
) {
954 // If desc ends past max allowed address, clip the end
956 if (DescEnd
>= MaxAddress
) {
957 DescEnd
= MaxAddress
;
960 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
963 // Compute the number of bytes we can used from this
964 // descriptor, and see it's enough to satisfy the request
966 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
968 if (DescNumberOfBytes
>= NumberOfBytes
) {
971 // If this is the best match so far remember it
973 if (DescEnd
> Target
) {
980 // If this is a grow down, adjust target to be the allocation base
982 Target
-= NumberOfBytes
- 1;
985 // If we didn't find a match, return 0
987 if ((Target
& EFI_PAGE_MASK
) != 0) {
996 Internal function. Finds a consecutive free page range below
997 the requested address
999 @param MaxAddress The address that the range must be below
1000 @param NoPages Number of pages needed
1001 @param NewType The type of memory the range is going to be
1003 @param Alignment Bits to align with
1005 @return The base address of the range, or 0 if the range was not found.
1010 IN UINT64 MaxAddress
,
1012 IN EFI_MEMORY_TYPE NewType
,
1016 UINT64 NewMaxAddress
;
1019 NewMaxAddress
= MaxAddress
;
1021 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
&& NewMaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1022 NewMaxAddress
= mMemoryTypeStatistics
[NewType
].MaximumAddress
;
1024 if (NewMaxAddress
> mDefaultMaximumAddress
) {
1025 NewMaxAddress
= mDefaultMaximumAddress
;
1029 Start
= CoreFindFreePagesI (NewMaxAddress
, NoPages
, NewType
, Alignment
);
1031 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1034 // Here means there may be no enough memory to use, so try to go through
1035 // all the memory descript to promote the untested memory directly
1037 PromoteMemoryResource ();
1040 // Allocate memory again after the memory resource re-arranged
1042 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1052 Allocates pages from the memory map.
1054 @param Type The type of allocation to perform
1055 @param MemoryType The type of memory to turn the allocated pages
1057 @param NumberOfPages The number of pages to allocate
1058 @param Memory A pointer to receive the base allocated memory
1061 @return Status. On success, Memory is filled in with the base address allocated
1062 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1064 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1065 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1066 @retval EFI_SUCCESS Pages successfully allocated.
1072 IN EFI_ALLOCATE_TYPE Type
,
1073 IN EFI_MEMORY_TYPE MemoryType
,
1074 IN UINTN NumberOfPages
,
1075 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
1083 if (Type
< AllocateAnyPages
|| Type
>= (UINTN
) MaxAllocateType
) {
1084 return EFI_INVALID_PARAMETER
;
1087 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
<= 0x7fffffff) ||
1088 MemoryType
== EfiConventionalMemory
) {
1089 return EFI_INVALID_PARAMETER
;
1092 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1094 if (MemoryType
== EfiACPIReclaimMemory
||
1095 MemoryType
== EfiACPIMemoryNVS
||
1096 MemoryType
== EfiRuntimeServicesCode
||
1097 MemoryType
== EfiRuntimeServicesData
) {
1099 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1102 if (Type
== AllocateAddress
) {
1103 if ((*Memory
& (Alignment
- 1)) != 0) {
1104 return EFI_NOT_FOUND
;
1108 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1109 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1112 // If this is for below a particular address, then
1117 // The max address is the max natively addressable address for the processor
1119 MaxAddress
= EFI_MAX_ADDRESS
;
1121 if (Type
== AllocateMaxAddress
) {
1125 CoreAcquireMemoryLock ();
1128 // If not a specific address, then find an address to allocate
1130 if (Type
!= AllocateAddress
) {
1131 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
);
1133 Status
= EFI_OUT_OF_RESOURCES
;
1139 // Convert pages from FreeMemory to the requested type
1141 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1144 CoreReleaseMemoryLock ();
1146 if (!EFI_ERROR (Status
)) {
1158 Frees previous allocated pages.
1160 @param Memory Base address of memory being freed
1161 @param NumberOfPages The number of pages to free
1163 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1164 @retval EFI_INVALID_PARAMETER Address not aligned
1165 @return EFI_SUCCESS -Pages successfully freed.
1171 IN EFI_PHYSICAL_ADDRESS Memory
,
1172 IN UINTN NumberOfPages
1183 CoreAcquireMemoryLock ();
1186 // Find the entry that the covers the range
1189 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1190 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1191 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1195 if (Link
== &gMemoryMap
) {
1196 CoreReleaseMemoryLock ();
1197 return EFI_NOT_FOUND
;
1200 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1202 if (Entry
->Type
== EfiACPIReclaimMemory
||
1203 Entry
->Type
== EfiACPIMemoryNVS
||
1204 Entry
->Type
== EfiRuntimeServicesCode
||
1205 Entry
->Type
== EfiRuntimeServicesData
) {
1207 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1211 if ((Memory
& (Alignment
- 1)) != 0) {
1212 CoreReleaseMemoryLock ();
1213 return EFI_INVALID_PARAMETER
;
1216 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1217 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1219 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1221 CoreReleaseMemoryLock ();
1223 if (EFI_ERROR (Status
)) {
1228 // Destroy the contents
1230 if (Memory
< EFI_MAX_ADDRESS
) {
1231 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Memory
, NumberOfPages
<< EFI_PAGE_SHIFT
);
1241 This function returns a copy of the current memory map. The map is an array of
1242 memory descriptors, each of which describes a contiguous block of memory.
1244 @param MemoryMapSize A pointer to the size, in bytes, of the
1245 MemoryMap buffer. On input, this is the size of
1246 the buffer allocated by the caller. On output,
1247 it is the size of the buffer returned by the
1248 firmware if the buffer was large enough, or the
1249 size of the buffer needed to contain the map if
1250 the buffer was too small.
1251 @param MemoryMap A pointer to the buffer in which firmware places
1252 the current memory map.
1253 @param MapKey A pointer to the location in which firmware
1254 returns the key for the current memory map.
1255 @param DescriptorSize A pointer to the location in which firmware
1256 returns the size, in bytes, of an individual
1257 EFI_MEMORY_DESCRIPTOR.
1258 @param DescriptorVersion A pointer to the location in which firmware
1259 returns the version number associated with the
1260 EFI_MEMORY_DESCRIPTOR.
1262 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1264 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1265 buffer size needed to hold the memory map is
1266 returned in MemoryMapSize.
1267 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1273 IN OUT UINTN
*MemoryMapSize
,
1274 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1276 OUT UINTN
*DescriptorSize
,
1277 OUT UINT32
*DescriptorVersion
1283 UINTN NumberOfRuntimeEntries
;
1286 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1287 EFI_MEMORY_TYPE Type
;
1290 // Make sure the parameters are valid
1292 if (MemoryMapSize
== NULL
) {
1293 return EFI_INVALID_PARAMETER
;
1296 CoreAcquireGcdMemoryLock ();
1299 // Count the number of Reserved and MMIO entries that are marked for runtime use
1301 NumberOfRuntimeEntries
= 0;
1302 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1303 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1304 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1305 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1306 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1307 NumberOfRuntimeEntries
++;
1312 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1315 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1316 // prevent people from having pointer math bugs in their code.
1317 // now you have to use *DescriptorSize to make things work.
1319 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1321 if (DescriptorSize
!= NULL
) {
1322 *DescriptorSize
= Size
;
1325 if (DescriptorVersion
!= NULL
) {
1326 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1329 CoreAcquireMemoryLock ();
1332 // Compute the buffer size needed to fit the entire map
1334 BufferSize
= Size
* NumberOfRuntimeEntries
;
1335 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1339 if (*MemoryMapSize
< BufferSize
) {
1340 Status
= EFI_BUFFER_TOO_SMALL
;
1344 if (MemoryMap
== NULL
) {
1345 Status
= EFI_INVALID_PARAMETER
;
1352 ZeroMem (MemoryMap
, BufferSize
);
1353 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1354 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1355 ASSERT (Entry
->VirtualStart
== 0);
1358 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1360 MemoryMap
->Type
= Entry
->Type
;
1361 MemoryMap
->PhysicalStart
= Entry
->Start
;
1362 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1363 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1365 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1366 // memory type bin and needs to be converted to the same memory type as the rest of the
1367 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1368 // improves the chances for a successful S4 resume in the presence of minor page allocation
1369 // differences across reboots.
1371 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1372 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
1373 if (mMemoryTypeStatistics
[Type
].Special
&&
1374 mMemoryTypeStatistics
[Type
].NumberOfPages
> 0 &&
1375 Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
&&
1376 Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
) {
1377 MemoryMap
->Type
= Type
;
1381 MemoryMap
->Attribute
= Entry
->Attribute
;
1382 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1383 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1386 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1389 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1390 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1391 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1392 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1393 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1395 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1396 MemoryMap
->VirtualStart
= 0;
1397 MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1398 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
& ~EFI_MEMORY_PORT_IO
;
1400 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1401 MemoryMap
->Type
= EfiReservedMemoryType
;
1402 } else if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1403 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1404 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1406 MemoryMap
->Type
= EfiMemoryMappedIO
;
1410 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1415 Status
= EFI_SUCCESS
;
1419 CoreReleaseMemoryLock ();
1421 CoreReleaseGcdMemoryLock ();
1424 // Update the map key finally
1426 if (MapKey
!= NULL
) {
1427 *MapKey
= mMemoryMapKey
;
1430 *MemoryMapSize
= BufferSize
;
1437 Internal function. Used by the pool functions to allocate pages
1438 to back pool allocation requests.
1440 @param PoolType The type of memory for the new pool pages
1441 @param NumberOfPages No of pages to allocate
1442 @param Alignment Bits to align.
1444 @return The allocated memory, or NULL
1448 CoreAllocatePoolPages (
1449 IN EFI_MEMORY_TYPE PoolType
,
1450 IN UINTN NumberOfPages
,
1457 // Find the pages to convert
1459 Start
= FindFreePages (EFI_MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
);
1462 // Convert it to boot services data
1465 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages
));
1467 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1470 return (VOID
*)(UINTN
)Start
;
1475 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1477 @param Memory The base address to free
1478 @param NumberOfPages The number of pages to free
1483 IN EFI_PHYSICAL_ADDRESS Memory
,
1484 IN UINTN NumberOfPages
1487 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1493 Make sure the memory map is following all the construction rules,
1494 it is the last time to check memory map error before exit boot services.
1496 @param MapKey Memory map key
1498 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1500 @retval EFI_SUCCESS Valid memory map.
1504 CoreTerminateMemoryMap (
1512 Status
= EFI_SUCCESS
;
1514 CoreAcquireMemoryLock ();
1516 if (MapKey
== mMemoryMapKey
) {
1519 // Make sure the memory map is following all the construction rules
1520 // This is the last chance we will be able to display any messages on
1521 // the console devices.
1524 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1525 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1526 if (Entry
->Attribute
& EFI_MEMORY_RUNTIME
) {
1527 if (Entry
->Type
== EfiACPIReclaimMemory
|| Entry
->Type
== EfiACPIMemoryNVS
) {
1528 DEBUG((DEBUG_ERROR
, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1529 CoreReleaseMemoryLock ();
1530 return EFI_INVALID_PARAMETER
;
1532 if (Entry
->Start
& (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1533 DEBUG((DEBUG_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1534 CoreReleaseMemoryLock ();
1535 return EFI_INVALID_PARAMETER
;
1537 if ((Entry
->End
+ 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1538 DEBUG((DEBUG_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1539 CoreReleaseMemoryLock ();
1540 return EFI_INVALID_PARAMETER
;
1546 // The map key they gave us matches what we expect. Fall through and
1547 // return success. In an ideal world we would clear out all of
1548 // EfiBootServicesCode and EfiBootServicesData. However this function
1549 // is not the last one called by ExitBootServices(), so we have to
1550 // preserve the memory contents.
1553 Status
= EFI_INVALID_PARAMETER
;
1556 CoreReleaseMemoryLock ();