3 UEFI Memory page management functions.
5 Copyright (c) 2007 - 2008, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
21 // Entry for tracking the memory regions for each memory type to help cooalese like memory types
24 EFI_PHYSICAL_ADDRESS BaseAddress
;
25 EFI_PHYSICAL_ADDRESS MaximumAddress
;
26 UINT64 CurrentNumberOfPages
;
28 UINTN InformationIndex
;
31 } EFI_MEMORY_TYPE_STAISTICS
;
34 // MemoryMap - The current memory map
36 UINTN mMemoryMapKey
= 0;
39 // mMapStack - space to use as temp storage to build new map descriptors
40 // mMapDepth - depth of new descriptor stack
43 #define MAX_MAP_DEPTH 6
45 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
46 UINTN mFreeMapStack
= 0;
48 // This list maintain the free memory map list
50 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
51 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
53 EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
54 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
55 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
56 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
57 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
58 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
59 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
60 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
61 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
62 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
63 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
64 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
65 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
66 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
67 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
68 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
71 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= EFI_MAX_ADDRESS
;
73 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
74 { EfiReservedMemoryType
, 0 },
77 { EfiBootServicesCode
, 0 },
78 { EfiBootServicesData
, 0 },
79 { EfiRuntimeServicesCode
, 0 },
80 { EfiRuntimeServicesData
, 0 },
81 { EfiConventionalMemory
, 0 },
82 { EfiUnusableMemory
, 0 },
83 { EfiACPIReclaimMemory
, 0 },
84 { EfiACPIMemoryNVS
, 0 },
85 { EfiMemoryMappedIO
, 0 },
86 { EfiMemoryMappedIOPortSpace
, 0 },
88 { EfiMaxMemoryType
, 0 }
92 // Internal prototypes
95 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
100 PromoteMemoryResource (
105 Internal function. Adds a ranges to the memory map.
106 The range must not already exist in the map.
108 @param Type The type of memory range to add
109 @param Start The starting address in the memory range Must be
111 @param End The last address in the range Must be the last
113 @param Attribute The attributes of the memory range to add
115 @return None. The range is added to the memory map
121 IN EFI_MEMORY_TYPE Type
,
122 IN EFI_PHYSICAL_ADDRESS Start
,
123 IN EFI_PHYSICAL_ADDRESS End
,
128 Internal function. Moves any memory descriptors that are on the
129 temporary descriptor stack to heap.
134 CoreFreeMemoryMapStack (
139 Internal function. Converts a memory range to the specified type.
140 The range must exist in the memory map.
142 @param Start The first address of the range Must be page
144 @param NumberOfPages The number of pages to convert
145 @param NewType The new type for the memory range
147 @retval EFI_INVALID_PARAMETER Invalid parameter
148 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
149 range or convertion not allowed.
150 @retval EFI_SUCCESS Successfully converts the memory range to the
158 IN UINT64 NumberOfPages
,
159 IN EFI_MEMORY_TYPE NewType
163 Internal function. Removes a descriptor entry.
165 @param Entry The entry to remove
170 RemoveMemoryMapEntry (
175 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
176 If the list is emtry, then allocate a new page to refuel the list.
177 Please Note this algorithm to allocate the memory map descriptor has a property
178 that the memory allocated for memory entries always grows, and will never really be freed
179 For example, if the current boot uses 2000 memory map entries at the maximum point, but
180 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
181 memory map entries is still allocated from EfiBootServicesMemory.
184 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
189 AllocateMemoryMapEntry (
195 Enter critical section by gaining lock on gMemoryLock.
199 CoreAcquireMemoryLock (
203 CoreAcquireLock (&gMemoryLock
);
209 Exit critical section by releasing lock on gMemoryLock.
213 CoreReleaseMemoryLock (
217 CoreReleaseLock (&gMemoryLock
);
222 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
227 PromoteMemoryResource (
232 EFI_GCD_MAP_ENTRY
*Entry
;
234 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "Promote the memory resource\n"));
236 CoreAcquireGcdMemoryLock ();
238 Link
= mGcdMemorySpaceMap
.ForwardLink
;
239 while (Link
!= &mGcdMemorySpaceMap
) {
241 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
243 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
244 Entry
->EndAddress
< EFI_MAX_ADDRESS
&&
245 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
246 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
248 // Update the GCD map
250 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
251 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
252 Entry
->ImageHandle
= gDxeCoreImageHandle
;
253 Entry
->DeviceHandle
= NULL
;
256 // Add to allocable system memory resource
260 EfiConventionalMemory
,
263 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
265 CoreFreeMemoryMapStack ();
269 Link
= Link
->ForwardLink
;
272 CoreReleaseGcdMemoryLock ();
279 Called to initialize the memory map and add descriptors to
280 the current descriptor list.
281 The first descriptor that is added must be general usable
282 memory as the addition allocates heap.
284 @param Type The type of memory to add
285 @param Start The starting address in the memory range Must be
287 @param NumberOfPages The number of pages in the range
288 @param Attribute Attributes of the memory to add
290 @return None. The range is added to the memory map
294 CoreAddMemoryDescriptor (
295 IN EFI_MEMORY_TYPE Type
,
296 IN EFI_PHYSICAL_ADDRESS Start
,
297 IN UINT64 NumberOfPages
,
301 EFI_PHYSICAL_ADDRESS End
;
306 if ((Start
& EFI_PAGE_MASK
) != 0) {
310 if (Type
>= EfiMaxMemoryType
&& Type
<= 0x7fffffff) {
314 CoreAcquireMemoryLock ();
315 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
316 CoreAddRange (Type
, Start
, End
, Attribute
);
317 CoreFreeMemoryMapStack ();
318 CoreReleaseMemoryLock ();
321 // Check to see if the statistics for the different memory types have already been established
323 if (mMemoryTypeInformationInitialized
) {
328 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
330 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
332 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
334 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
335 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
339 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
341 // Allocate pages for the current memory type from the top of available memory
343 Status
= CoreAllocatePages (
346 gMemoryTypeInformation
[Index
].NumberOfPages
,
347 &mMemoryTypeStatistics
[Type
].BaseAddress
349 if (EFI_ERROR (Status
)) {
351 // If an error occurs allocating the pages for the current memory type, then
352 // free all the pages allocates for the previous memory types and return. This
353 // operation with be retied when/if more memory is added to the system
355 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
357 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
359 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
360 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
364 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
366 mMemoryTypeStatistics
[Type
].BaseAddress
,
367 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
369 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
370 mMemoryTypeStatistics
[Type
].MaximumAddress
= EFI_MAX_ADDRESS
;
377 // Compute the address at the top of the current statistics
379 mMemoryTypeStatistics
[Type
].MaximumAddress
=
380 mMemoryTypeStatistics
[Type
].BaseAddress
+
381 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
384 // If the current base address is the lowest address so far, then update the default
387 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
388 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
394 // There was enough system memory for all the the memory types were allocated. So,
395 // those memory areas can be freed for future allocations, and all future memory
396 // allocations can occur within their respective bins
398 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
400 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
402 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
403 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
407 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
409 mMemoryTypeStatistics
[Type
].BaseAddress
,
410 gMemoryTypeInformation
[Index
].NumberOfPages
412 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
413 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
418 // If the number of pages reserved for a memory type is 0, then all allocations for that type
419 // should be in the default range.
421 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
422 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
423 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
424 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
427 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
428 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== EFI_MAX_ADDRESS
) {
429 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
433 mMemoryTypeInformationInitialized
= TRUE
;
439 Internal function. Adds a ranges to the memory map.
440 The range must not already exist in the map.
442 @param Type The type of memory range to add
443 @param Start The starting address in the memory range Must be
445 @param End The last address in the range Must be the last
447 @param Attribute The attributes of the memory range to add
449 @return None. The range is added to the memory map
455 IN EFI_MEMORY_TYPE Type
,
456 IN EFI_PHYSICAL_ADDRESS Start
,
457 IN EFI_PHYSICAL_ADDRESS End
,
464 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
465 ASSERT (End
> Start
) ;
467 ASSERT_LOCKED (&gMemoryLock
);
469 DEBUG ((DEBUG_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
472 // Memory map being altered so updated key
477 // UEFI 2.0 added an event group for notificaiton on memory map changes.
478 // So we need to signal this Event Group every time the memory map changes.
479 // If we are in EFI 1.10 compatability mode no event groups will be
480 // found and nothing will happen we we call this function. These events
481 // will get signaled but since a lock is held around the call to this
482 // function the notificaiton events will only be called after this funciton
483 // returns and the lock is released.
485 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
488 // Look for adjoining memory descriptor
491 // Two memory descriptors can only be merged if they have the same Type
492 // and the same Attribute
495 Link
= gMemoryMap
.ForwardLink
;
496 while (Link
!= &gMemoryMap
) {
497 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
498 Link
= Link
->ForwardLink
;
500 if (Entry
->Type
!= Type
) {
504 if (Entry
->Attribute
!= Attribute
) {
508 if (Entry
->End
+ 1 == Start
) {
510 Start
= Entry
->Start
;
511 RemoveMemoryMapEntry (Entry
);
513 } else if (Entry
->Start
== End
+ 1) {
516 RemoveMemoryMapEntry (Entry
);
524 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
525 mMapStack
[mMapDepth
].FromPages
= FALSE
;
526 mMapStack
[mMapDepth
].Type
= Type
;
527 mMapStack
[mMapDepth
].Start
= Start
;
528 mMapStack
[mMapDepth
].End
= End
;
529 mMapStack
[mMapDepth
].VirtualStart
= 0;
530 mMapStack
[mMapDepth
].Attribute
= Attribute
;
531 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
534 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
541 Internal function. Moves any memory descriptors that are on the
542 temporary descriptor stack to heap.
547 CoreFreeMemoryMapStack (
555 ASSERT_LOCKED (&gMemoryLock
);
558 // If already freeing the map stack, then return
565 // Move the temporary memory descriptor stack into pool
571 // Deque an memory map entry from mFreeMemoryMapEntryList
573 Entry
= AllocateMemoryMapEntry ();
578 // Update to proper entry
582 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
585 // Move this entry to general memory
587 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
588 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
590 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
591 Entry
->FromPages
= TRUE
;
594 // Find insertion location
596 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
597 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
598 if (Entry2
->FromPages
&& Entry2
->Start
> Entry
->Start
) {
603 InsertTailList (Link2
, &Entry
->Link
);
607 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
608 // so here no need to move it to memory.
610 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
619 Internal function. Removes a descriptor entry.
621 @param Entry The entry to remove
626 RemoveMemoryMapEntry (
630 RemoveEntryList (&Entry
->Link
);
631 Entry
->Link
.ForwardLink
= NULL
;
633 if (Entry
->FromPages
) {
635 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
637 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
643 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
644 If the list is emtry, then allocate a new page to refuel the list.
645 Please Note this algorithm to allocate the memory map descriptor has a property
646 that the memory allocated for memory entries always grows, and will never really be freed
647 For example, if the current boot uses 2000 memory map entries at the maximum point, but
648 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
649 memory map entries is still allocated from EfiBootServicesMemory.
652 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
657 AllocateMemoryMapEntry (
661 MEMORY_MAP
* FreeDescriptorEntries
;
665 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
667 // The list is empty, to allocate one page to refuel the list
669 FreeDescriptorEntries
= CoreAllocatePoolPages (EfiBootServicesData
, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
670 if(FreeDescriptorEntries
!= NULL
) {
672 // Enque the free memmory map entries into the list
674 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION
/ sizeof(MEMORY_MAP
); Index
++) {
675 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
676 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
683 // dequeue the first descriptor from the list
685 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
686 RemoveEntryList (&Entry
->Link
);
693 Internal function. Converts a memory range to the specified type.
694 The range must exist in the memory map.
696 @param Start The first address of the range Must be page
698 @param NumberOfPages The number of pages to convert
699 @param NewType The new type for the memory range
701 @retval EFI_INVALID_PARAMETER Invalid parameter
702 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
703 range or convertion not allowed.
704 @retval EFI_SUCCESS Successfully converts the memory range to the
712 IN UINT64 NumberOfPages
,
713 IN EFI_MEMORY_TYPE NewType
717 UINT64 NumberOfBytes
;
725 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
726 End
= Start
+ NumberOfBytes
- 1;
728 ASSERT (NumberOfPages
);
729 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
730 ASSERT (End
> Start
) ;
731 ASSERT_LOCKED (&gMemoryLock
);
733 if (NumberOfPages
== 0 || (Start
& EFI_PAGE_MASK
) || (Start
> (Start
+ NumberOfBytes
))) {
734 return EFI_INVALID_PARAMETER
;
738 // Convert the entire range
741 while (Start
< End
) {
744 // Find the entry that the covers the range
746 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
747 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
749 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
754 if (Link
== &gMemoryMap
) {
755 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
756 return EFI_NOT_FOUND
;
760 // Convert range to the end, or to the end of the descriptor
761 // if that's all we've got
764 if (Entry
->End
< End
) {
765 RangeEnd
= Entry
->End
;
768 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to %d\n", Start
, RangeEnd
, NewType
));
771 // Debug code - verify conversion is allowed
773 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
774 DEBUG ((DEBUG_ERROR
, "ConvertPages: Incompatible memory types\n"));
775 return EFI_NOT_FOUND
;
779 // Update counters for the number of pages allocated to each memory type
781 if (Entry
->Type
>= 0 && Entry
->Type
< EfiMaxMemoryType
) {
782 if (Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&&
783 Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) {
784 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
785 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
787 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
792 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
) {
793 if (Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
794 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
795 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
>
796 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
797 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
803 // Pull range out of descriptor
805 if (Entry
->Start
== Start
) {
810 Entry
->Start
= RangeEnd
+ 1;
812 } else if (Entry
->End
== RangeEnd
) {
817 Entry
->End
= Start
- 1;
822 // Pull it out of the center, clip current
828 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
829 mMapStack
[mMapDepth
].FromPages
= FALSE
;
830 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
831 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
832 mMapStack
[mMapDepth
].End
= Entry
->End
;
835 // Inherit Attribute from the Memory Descriptor that is being clipped
837 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
839 Entry
->End
= Start
- 1;
840 ASSERT (Entry
->Start
< Entry
->End
);
842 Entry
= &mMapStack
[mMapDepth
];
843 InsertTailList (&gMemoryMap
, &Entry
->Link
);
846 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
850 // The new range inherits the same Attribute as the Entry
851 //it is being cut out of
853 Attribute
= Entry
->Attribute
;
856 // If the descriptor is empty, then remove it from the map
858 if (Entry
->Start
== Entry
->End
+ 1) {
859 RemoveMemoryMapEntry (Entry
);
864 // Add our new range in
866 CoreAddRange (NewType
, Start
, RangeEnd
, Attribute
);
869 // Move any map descriptor stack to general pool
871 CoreFreeMemoryMapStack ();
874 // Bump the starting address, and convert the next range
876 Start
= RangeEnd
+ 1;
880 // Converted the whole range, done
889 Internal function. Finds a consecutive free page range below
890 the requested address.
892 @param MaxAddress The address that the range must be below
893 @param NumberOfPages Number of pages needed
894 @param NewType The type of memory the range is going to be
896 @param Alignment Bits to align with
898 @return The base address of the range, or 0 if the range was not found
904 IN UINT64 MaxAddress
,
905 IN UINT64 NumberOfPages
,
906 IN EFI_MEMORY_TYPE NewType
,
910 UINT64 NumberOfBytes
;
914 UINT64 DescNumberOfBytes
;
918 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
922 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
925 // If MaxAddress is not aligned to the end of a page
929 // Change MaxAddress to be 1 page lower
931 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
934 // Set MaxAddress to a page boundary
936 MaxAddress
&= ~EFI_PAGE_MASK
;
939 // Set MaxAddress to end of the page
941 MaxAddress
|= EFI_PAGE_MASK
;
944 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
947 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
948 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
951 // If it's not a free entry, don't bother with it
953 if (Entry
->Type
!= EfiConventionalMemory
) {
957 DescStart
= Entry
->Start
;
958 DescEnd
= Entry
->End
;
961 // If desc is past max allowed address, skip it
963 if (DescStart
>= MaxAddress
) {
968 // If desc ends past max allowed address, clip the end
970 if (DescEnd
>= MaxAddress
) {
971 DescEnd
= MaxAddress
;
974 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
977 // Compute the number of bytes we can used from this
978 // descriptor, and see it's enough to satisfy the request
980 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
982 if (DescNumberOfBytes
>= NumberOfBytes
) {
985 // If this is the best match so far remember it
987 if (DescEnd
> Target
) {
994 // If this is a grow down, adjust target to be the allocation base
996 Target
-= NumberOfBytes
- 1;
999 // If we didn't find a match, return 0
1001 if ((Target
& EFI_PAGE_MASK
) != 0) {
1010 Internal function. Finds a consecutive free page range below
1011 the requested address
1013 @param MaxAddress The address that the range must be below
1014 @param NoPages Number of pages needed
1015 @param NewType The type of memory the range is going to be
1017 @param Alignment Bits to align with
1019 @return The base address of the range, or 0 if the range was not found.
1025 IN UINT64 MaxAddress
,
1027 IN EFI_MEMORY_TYPE NewType
,
1031 UINT64 NewMaxAddress
;
1034 NewMaxAddress
= MaxAddress
;
1036 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
&& NewMaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1037 NewMaxAddress
= mMemoryTypeStatistics
[NewType
].MaximumAddress
;
1039 if (NewMaxAddress
> mDefaultMaximumAddress
) {
1040 NewMaxAddress
= mDefaultMaximumAddress
;
1044 Start
= CoreFindFreePagesI (NewMaxAddress
, NoPages
, NewType
, Alignment
);
1046 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1049 // Here means there may be no enough memory to use, so try to go through
1050 // all the memory descript to promote the untested memory directly
1052 PromoteMemoryResource ();
1055 // Allocate memory again after the memory resource re-arranged
1057 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1067 Allocates pages from the memory map.
1069 @param Type The type of allocation to perform
1070 @param MemoryType The type of memory to turn the allocated pages
1072 @param NumberOfPages The number of pages to allocate
1073 @param Memory A pointer to receive the base allocated memory
1076 @return Status. On success, Memory is filled in with the base address allocated
1077 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1079 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1080 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1081 @retval EFI_SUCCESS Pages successfully allocated.
1087 IN EFI_ALLOCATE_TYPE Type
,
1088 IN EFI_MEMORY_TYPE MemoryType
,
1089 IN UINTN NumberOfPages
,
1090 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
1098 if (Type
< AllocateAnyPages
|| Type
>= (UINTN
) MaxAllocateType
) {
1099 return EFI_INVALID_PARAMETER
;
1102 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
<= 0x7fffffff) ||
1103 MemoryType
== EfiConventionalMemory
) {
1104 return EFI_INVALID_PARAMETER
;
1107 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1109 if (MemoryType
== EfiACPIReclaimMemory
||
1110 MemoryType
== EfiACPIMemoryNVS
||
1111 MemoryType
== EfiRuntimeServicesCode
||
1112 MemoryType
== EfiRuntimeServicesData
) {
1114 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1117 if (Type
== AllocateAddress
) {
1118 if ((*Memory
& (Alignment
- 1)) != 0) {
1119 return EFI_NOT_FOUND
;
1123 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1124 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1127 // If this is for below a particular address, then
1132 // The max address is the max natively addressable address for the processor
1134 MaxAddress
= EFI_MAX_ADDRESS
;
1136 if (Type
== AllocateMaxAddress
) {
1140 CoreAcquireMemoryLock ();
1143 // If not a specific address, then find an address to allocate
1145 if (Type
!= AllocateAddress
) {
1146 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
);
1148 Status
= EFI_OUT_OF_RESOURCES
;
1154 // Convert pages from FreeMemory to the requested type
1156 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1159 CoreReleaseMemoryLock ();
1161 if (!EFI_ERROR (Status
)) {
1173 Frees previous allocated pages.
1175 @param Memory Base address of memory being freed
1176 @param NumberOfPages The number of pages to free
1178 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1179 @retval EFI_INVALID_PARAMETER Address not aligned
1180 @return EFI_SUCCESS -Pages successfully freed.
1186 IN EFI_PHYSICAL_ADDRESS Memory
,
1187 IN UINTN NumberOfPages
1198 CoreAcquireMemoryLock ();
1201 // Find the entry that the covers the range
1204 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1205 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1206 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1210 if (Link
== &gMemoryMap
) {
1211 CoreReleaseMemoryLock ();
1212 return EFI_NOT_FOUND
;
1215 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1217 if (Entry
->Type
== EfiACPIReclaimMemory
||
1218 Entry
->Type
== EfiACPIMemoryNVS
||
1219 Entry
->Type
== EfiRuntimeServicesCode
||
1220 Entry
->Type
== EfiRuntimeServicesData
) {
1222 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1226 if ((Memory
& (Alignment
- 1)) != 0) {
1227 CoreReleaseMemoryLock ();
1228 return EFI_INVALID_PARAMETER
;
1231 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1232 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1234 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1236 CoreReleaseMemoryLock ();
1238 if (EFI_ERROR (Status
)) {
1243 // Destroy the contents
1245 if (Memory
< EFI_MAX_ADDRESS
) {
1246 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Memory
, NumberOfPages
<< EFI_PAGE_SHIFT
);
1256 This function returns a copy of the current memory map. The map is an array of
1257 memory descriptors, each of which describes a contiguous block of memory.
1259 @param MemoryMapSize A pointer to the size, in bytes, of the
1260 MemoryMap buffer. On input, this is the size of
1261 the buffer allocated by the caller. On output,
1262 it is the size of the buffer returned by the
1263 firmware if the buffer was large enough, or the
1264 size of the buffer needed to contain the map if
1265 the buffer was too small.
1266 @param MemoryMap A pointer to the buffer in which firmware places
1267 the current memory map.
1268 @param MapKey A pointer to the location in which firmware
1269 returns the key for the current memory map.
1270 @param DescriptorSize A pointer to the location in which firmware
1271 returns the size, in bytes, of an individual
1272 EFI_MEMORY_DESCRIPTOR.
1273 @param DescriptorVersion A pointer to the location in which firmware
1274 returns the version number associated with the
1275 EFI_MEMORY_DESCRIPTOR.
1277 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1279 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1280 buffer size needed to hold the memory map is
1281 returned in MemoryMapSize.
1282 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1288 IN OUT UINTN
*MemoryMapSize
,
1289 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1291 OUT UINTN
*DescriptorSize
,
1292 OUT UINT32
*DescriptorVersion
1298 UINTN NumberOfRuntimeEntries
;
1301 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1302 EFI_MEMORY_TYPE Type
;
1305 // Make sure the parameters are valid
1307 if (MemoryMapSize
== NULL
) {
1308 return EFI_INVALID_PARAMETER
;
1311 CoreAcquireGcdMemoryLock ();
1314 // Count the number of Reserved and MMIO entries that are marked for runtime use
1316 NumberOfRuntimeEntries
= 0;
1317 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1318 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1319 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1320 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1321 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1322 NumberOfRuntimeEntries
++;
1327 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1330 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1331 // prevent people from having pointer math bugs in their code.
1332 // now you have to use *DescriptorSize to make things work.
1334 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1336 if (DescriptorSize
!= NULL
) {
1337 *DescriptorSize
= Size
;
1340 if (DescriptorVersion
!= NULL
) {
1341 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1344 CoreAcquireMemoryLock ();
1347 // Compute the buffer size needed to fit the entire map
1349 BufferSize
= Size
* NumberOfRuntimeEntries
;
1350 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1354 if (*MemoryMapSize
< BufferSize
) {
1355 Status
= EFI_BUFFER_TOO_SMALL
;
1359 if (MemoryMap
== NULL
) {
1360 Status
= EFI_INVALID_PARAMETER
;
1367 ZeroMem (MemoryMap
, BufferSize
);
1368 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1369 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1370 ASSERT (Entry
->VirtualStart
== 0);
1373 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1375 MemoryMap
->Type
= Entry
->Type
;
1376 MemoryMap
->PhysicalStart
= Entry
->Start
;
1377 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1378 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1380 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1381 // memory type bin and needs to be converted to the same memory type as the rest of the
1382 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1383 // improves the chances for a successful S4 resume in the presence of minor page allocation
1384 // differences across reboots.
1386 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1387 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
1388 if (mMemoryTypeStatistics
[Type
].Special
&&
1389 mMemoryTypeStatistics
[Type
].NumberOfPages
> 0 &&
1390 Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
&&
1391 Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
) {
1392 MemoryMap
->Type
= Type
;
1396 MemoryMap
->Attribute
= Entry
->Attribute
;
1397 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1398 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1401 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1404 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1405 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1406 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1407 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1408 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1410 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1411 MemoryMap
->VirtualStart
= 0;
1412 MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1413 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
& ~EFI_MEMORY_PORT_IO
;
1415 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1416 MemoryMap
->Type
= EfiReservedMemoryType
;
1417 } else if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1418 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1419 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1421 MemoryMap
->Type
= EfiMemoryMappedIO
;
1425 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1430 Status
= EFI_SUCCESS
;
1434 CoreReleaseMemoryLock ();
1436 CoreReleaseGcdMemoryLock ();
1439 // Update the map key finally
1441 if (MapKey
!= NULL
) {
1442 *MapKey
= mMemoryMapKey
;
1445 *MemoryMapSize
= BufferSize
;
1452 Internal function. Used by the pool functions to allocate pages
1453 to back pool allocation requests.
1455 @param PoolType The type of memory for the new pool pages
1456 @param NumberOfPages No of pages to allocate
1457 @param Alignment Bits to align.
1459 @return The allocated memory, or NULL
1463 CoreAllocatePoolPages (
1464 IN EFI_MEMORY_TYPE PoolType
,
1465 IN UINTN NumberOfPages
,
1472 // Find the pages to convert
1474 Start
= FindFreePages (EFI_MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
);
1477 // Convert it to boot services data
1480 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages
));
1482 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1485 return (VOID
*)(UINTN
)Start
;
1490 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1492 @param Memory The base address to free
1493 @param NumberOfPages The number of pages to free
1498 IN EFI_PHYSICAL_ADDRESS Memory
,
1499 IN UINTN NumberOfPages
1502 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1508 Make sure the memory map is following all the construction rules,
1509 it is the last time to check memory map error before exit boot services.
1511 @param MapKey Memory map key
1513 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1515 @retval EFI_SUCCESS Valid memory map.
1519 CoreTerminateMemoryMap (
1527 Status
= EFI_SUCCESS
;
1529 CoreAcquireMemoryLock ();
1531 if (MapKey
== mMemoryMapKey
) {
1534 // Make sure the memory map is following all the construction rules
1535 // This is the last chance we will be able to display any messages on
1536 // the console devices.
1539 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1540 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1541 if (Entry
->Attribute
& EFI_MEMORY_RUNTIME
) {
1542 if (Entry
->Type
== EfiACPIReclaimMemory
|| Entry
->Type
== EfiACPIMemoryNVS
) {
1543 DEBUG((DEBUG_ERROR
, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1544 CoreReleaseMemoryLock ();
1545 return EFI_INVALID_PARAMETER
;
1547 if (Entry
->Start
& (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1548 DEBUG((DEBUG_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1549 CoreReleaseMemoryLock ();
1550 return EFI_INVALID_PARAMETER
;
1552 if ((Entry
->End
+ 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1553 DEBUG((DEBUG_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1554 CoreReleaseMemoryLock ();
1555 return EFI_INVALID_PARAMETER
;
1561 // The map key they gave us matches what we expect. Fall through and
1562 // return success. In an ideal world we would clear out all of
1563 // EfiBootServicesCode and EfiBootServicesData. However this function
1564 // is not the last one called by ExitBootServices(), so we have to
1565 // preserve the memory contents.
1568 Status
= EFI_INVALID_PARAMETER
;
1571 CoreReleaseMemoryLock ();