2 UEFI Memory page management functions.
4 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "HeapGuard.h"
12 #include <Pi/PrePiDxeCis.h>
15 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
18 EFI_PHYSICAL_ADDRESS BaseAddress
;
19 EFI_PHYSICAL_ADDRESS MaximumAddress
;
20 UINT64 CurrentNumberOfPages
;
22 UINTN InformationIndex
;
25 } EFI_MEMORY_TYPE_STATISTICS
;
28 // MemoryMap - The current memory map
30 UINTN mMemoryMapKey
= 0;
32 #define MAX_MAP_DEPTH 6
35 /// mMapDepth - depth of new descriptor stack
39 /// mMapStack - space to use as temp storage to build new map descriptors
41 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
42 UINTN mFreeMapStack
= 0;
44 /// This list maintain the free memory map list
46 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
47 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
49 EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
50 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
51 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
52 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
53 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
54 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
55 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
56 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
57 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
58 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
59 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
60 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
61 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
62 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
63 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
64 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiPersistentMemory
65 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiUnacceptedMemoryType
66 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
69 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= MAX_ALLOC_ADDRESS
;
70 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress
= MAX_ALLOC_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 { EfiPersistentMemory
, 0 },
88 { EFI_GCD_MEMORY_TYPE_UNACCEPTED
, 0 },
89 { EfiMaxMemoryType
, 0 }
92 // Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
93 // and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
94 // address assigned by DXE core.
96 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady
= FALSE
;
99 Enter critical section by gaining lock on gMemoryLock.
103 CoreAcquireMemoryLock (
107 CoreAcquireLock (&gMemoryLock
);
111 Exit critical section by releasing lock on gMemoryLock.
115 CoreReleaseMemoryLock (
119 CoreReleaseLock (&gMemoryLock
);
123 Internal function. Removes a descriptor entry.
125 @param Entry The entry to remove
129 RemoveMemoryMapEntry (
130 IN OUT MEMORY_MAP
*Entry
133 RemoveEntryList (&Entry
->Link
);
134 Entry
->Link
.ForwardLink
= NULL
;
136 if (Entry
->FromPages
) {
138 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
140 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
145 Internal function. Adds a ranges to the memory map.
146 The range must not already exist in the map.
148 @param Type The type of memory range to add
149 @param Start The starting address in the memory range Must be
151 @param End The last address in the range Must be the last
153 @param Attribute The attributes of the memory range to add
158 IN EFI_MEMORY_TYPE Type
,
159 IN EFI_PHYSICAL_ADDRESS Start
,
160 IN EFI_PHYSICAL_ADDRESS End
,
167 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
168 ASSERT (End
> Start
);
170 ASSERT_LOCKED (&gMemoryLock
);
172 DEBUG ((DEBUG_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
175 // If memory of type EfiConventionalMemory is being added that includes the page
176 // starting at address 0, then zero the page starting at address 0. This has
177 // two benifits. It helps find NULL pointer bugs and it also maximizes
178 // compatibility with operating systems that may evaluate memory in this page
179 // for legacy data structures. If memory of any other type is added starting
180 // at address 0, then do not zero the page at address 0 because the page is being
181 // used for other purposes.
183 if ((Type
== EfiConventionalMemory
) && (Start
== 0) && (End
>= EFI_PAGE_SIZE
- 1)) {
184 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask
) & BIT0
) == 0) {
185 SetMem ((VOID
*)(UINTN
)Start
, EFI_PAGE_SIZE
, 0);
190 // Memory map being altered so updated key
195 // UEFI 2.0 added an event group for notificaiton on memory map changes.
196 // So we need to signal this Event Group every time the memory map changes.
197 // If we are in EFI 1.10 compatability mode no event groups will be
198 // found and nothing will happen we we call this function. These events
199 // will get signaled but since a lock is held around the call to this
200 // function the notificaiton events will only be called after this function
201 // returns and the lock is released.
203 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
206 // Look for adjoining memory descriptor
209 // Two memory descriptors can only be merged if they have the same Type
210 // and the same Attribute
213 Link
= gMemoryMap
.ForwardLink
;
214 while (Link
!= &gMemoryMap
) {
215 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
216 Link
= Link
->ForwardLink
;
218 if (Entry
->Type
!= Type
) {
222 if (Entry
->Attribute
!= Attribute
) {
226 if (Entry
->End
+ 1 == Start
) {
227 Start
= Entry
->Start
;
228 RemoveMemoryMapEntry (Entry
);
229 } else if (Entry
->Start
== End
+ 1) {
231 RemoveMemoryMapEntry (Entry
);
239 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
240 mMapStack
[mMapDepth
].FromPages
= FALSE
;
241 mMapStack
[mMapDepth
].Type
= Type
;
242 mMapStack
[mMapDepth
].Start
= Start
;
243 mMapStack
[mMapDepth
].End
= End
;
244 mMapStack
[mMapDepth
].VirtualStart
= 0;
245 mMapStack
[mMapDepth
].Attribute
= Attribute
;
246 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
249 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
255 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
256 If the list is emtry, then allocate a new page to refuel the list.
257 Please Note this algorithm to allocate the memory map descriptor has a property
258 that the memory allocated for memory entries always grows, and will never really be freed
259 For example, if the current boot uses 2000 memory map entries at the maximum point, but
260 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
261 memory map entries is still allocated from EfiBootServicesMemory.
264 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
268 AllocateMemoryMapEntry (
272 MEMORY_MAP
*FreeDescriptorEntries
;
276 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
278 // The list is empty, to allocate one page to refuel the list
280 FreeDescriptorEntries
= CoreAllocatePoolPages (
282 EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY
),
283 DEFAULT_PAGE_ALLOCATION_GRANULARITY
,
286 if (FreeDescriptorEntries
!= NULL
) {
288 // Enque the free memmory map entries into the list
290 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION_GRANULARITY
/ sizeof (MEMORY_MAP
); Index
++) {
291 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
292 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
300 // dequeue the first descriptor from the list
302 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
303 RemoveEntryList (&Entry
->Link
);
309 Internal function. Moves any memory descriptors that are on the
310 temporary descriptor stack to heap.
314 CoreFreeMemoryMapStack (
322 ASSERT_LOCKED (&gMemoryLock
);
325 // If already freeing the map stack, then return
327 if (mFreeMapStack
!= 0) {
332 // Move the temporary memory descriptor stack into pool
336 while (mMapDepth
!= 0) {
338 // Deque an memory map entry from mFreeMemoryMapEntryList
340 Entry
= AllocateMemoryMapEntry ();
345 // Update to proper entry
349 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
351 // Move this entry to general memory
353 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
354 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
356 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
357 Entry
->FromPages
= TRUE
;
360 // Find insertion location
362 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
363 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
364 if (Entry2
->FromPages
&& (Entry2
->Start
> Entry
->Start
)) {
369 InsertTailList (Link2
, &Entry
->Link
);
372 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
373 // so here no need to move it to memory.
375 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
383 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
387 PromoteMemoryResource (
392 EFI_GCD_MAP_ENTRY
*Entry
;
394 EFI_PHYSICAL_ADDRESS StartAddress
;
395 EFI_PHYSICAL_ADDRESS EndAddress
;
396 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
398 DEBUG ((DEBUG_PAGE
, "Promote the memory resource\n"));
400 CoreAcquireGcdMemoryLock ();
403 Link
= mGcdMemorySpaceMap
.ForwardLink
;
404 while (Link
!= &mGcdMemorySpaceMap
) {
405 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
407 if ((Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) &&
408 (Entry
->EndAddress
< MAX_ALLOC_ADDRESS
) &&
409 ((Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
410 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)))
413 // Update the GCD map
415 if ((Entry
->Capabilities
& EFI_MEMORY_MORE_RELIABLE
) == EFI_MEMORY_MORE_RELIABLE
) {
416 Entry
->GcdMemoryType
= EfiGcdMemoryTypeMoreReliable
;
418 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
421 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
422 Entry
->ImageHandle
= gDxeCoreImageHandle
;
423 Entry
->DeviceHandle
= NULL
;
426 // Add to allocable system memory resource
430 EfiConventionalMemory
,
433 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
435 CoreFreeMemoryMapStack ();
440 Link
= Link
->ForwardLink
;
443 CoreReleaseGcdMemoryLock ();
447 // If freed-memory guard is enabled, we could promote pages from
448 // guarded free pages.
450 Promoted
= PromoteGuardedFreePages (&StartAddress
, &EndAddress
);
452 CoreGetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
454 EfiConventionalMemory
,
457 Descriptor
.Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
|
458 EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
467 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
468 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
469 size of boot time and runtime code.
473 CoreLoadingFixedAddressHook (
477 UINT32 RuntimeCodePageNumber
;
478 UINT32 BootTimeCodePageNumber
;
479 EFI_PHYSICAL_ADDRESS RuntimeCodeBase
;
480 EFI_PHYSICAL_ADDRESS BootTimeCodeBase
;
484 // Make sure these 2 areas are not initialzied.
486 if (!gLoadFixedAddressCodeMemoryReady
) {
487 RuntimeCodePageNumber
= PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber
);
488 BootTimeCodePageNumber
= PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber
);
489 RuntimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(gLoadModuleAtFixAddressConfigurationTable
.DxeCodeTopAddress
- EFI_PAGES_TO_SIZE (RuntimeCodePageNumber
));
490 BootTimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(RuntimeCodeBase
- EFI_PAGES_TO_SIZE (BootTimeCodePageNumber
));
492 // Try to allocate runtime memory.
494 Status
= CoreAllocatePages (
496 EfiRuntimeServicesCode
,
497 RuntimeCodePageNumber
,
500 if (EFI_ERROR (Status
)) {
502 // Runtime memory allocation failed
508 // Try to allocate boot memory.
510 Status
= CoreAllocatePages (
513 BootTimeCodePageNumber
,
516 if (EFI_ERROR (Status
)) {
518 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
519 // new memory range is installed.
523 RuntimeCodePageNumber
528 gLoadFixedAddressCodeMemoryReady
= TRUE
;
535 Called to initialize the memory map and add descriptors to
536 the current descriptor list.
537 The first descriptor that is added must be general usable
538 memory as the addition allocates heap.
540 @param Type The type of memory to add
541 @param Start The starting address in the memory range Must be
543 @param NumberOfPages The number of pages in the range
544 @param Attribute Attributes of the memory to add
546 @return None. The range is added to the memory map
550 CoreAddMemoryDescriptor (
551 IN EFI_MEMORY_TYPE Type
,
552 IN EFI_PHYSICAL_ADDRESS Start
,
553 IN UINT64 NumberOfPages
,
557 EFI_PHYSICAL_ADDRESS End
;
562 if ((Start
& EFI_PAGE_MASK
) != 0) {
566 if ((Type
>= EfiMaxMemoryType
) && (Type
< MEMORY_TYPE_OEM_RESERVED_MIN
)) {
570 CoreAcquireMemoryLock ();
571 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
572 CoreAddRange (Type
, Start
, End
, Attribute
);
573 CoreFreeMemoryMapStack ();
574 CoreReleaseMemoryLock ();
576 ApplyMemoryProtectionPolicy (
580 LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
)
584 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
586 if (PcdGet64 (PcdLoadModuleAtFixAddressEnable
) != 0) {
587 CoreLoadingFixedAddressHook ();
591 // Check to see if the statistics for the different memory types have already been established
593 if (mMemoryTypeInformationInitialized
) {
598 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
600 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
602 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
604 Type
= (EFI_MEMORY_TYPE
)(gMemoryTypeInformation
[Index
].Type
);
605 if ((UINT32
)Type
> EfiMaxMemoryType
) {
609 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
611 // Allocate pages for the current memory type from the top of available memory
613 Status
= CoreAllocatePages (
616 gMemoryTypeInformation
[Index
].NumberOfPages
,
617 &mMemoryTypeStatistics
[Type
].BaseAddress
619 if (EFI_ERROR (Status
)) {
621 // If an error occurs allocating the pages for the current memory type, then
622 // free all the pages allocates for the previous memory types and return. This
623 // operation with be retied when/if more memory is added to the system
625 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
627 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
629 Type
= (EFI_MEMORY_TYPE
)(gMemoryTypeInformation
[FreeIndex
].Type
);
630 if ((UINT32
)Type
> EfiMaxMemoryType
) {
634 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
636 mMemoryTypeStatistics
[Type
].BaseAddress
,
637 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
639 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
640 mMemoryTypeStatistics
[Type
].MaximumAddress
= MAX_ALLOC_ADDRESS
;
648 // Compute the address at the top of the current statistics
650 mMemoryTypeStatistics
[Type
].MaximumAddress
=
651 mMemoryTypeStatistics
[Type
].BaseAddress
+
652 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
655 // If the current base address is the lowest address so far, then update the default
658 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
659 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
665 // There was enough system memory for all the the memory types were allocated. So,
666 // those memory areas can be freed for future allocations, and all future memory
667 // allocations can occur within their respective bins
669 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
671 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
673 Type
= (EFI_MEMORY_TYPE
)(gMemoryTypeInformation
[Index
].Type
);
674 if ((UINT32
)Type
> EfiMaxMemoryType
) {
678 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
680 mMemoryTypeStatistics
[Type
].BaseAddress
,
681 gMemoryTypeInformation
[Index
].NumberOfPages
683 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
684 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
689 // If the number of pages reserved for a memory type is 0, then all allocations for that type
690 // should be in the default range.
692 for (Type
= (EFI_MEMORY_TYPE
)0; Type
< EfiMaxMemoryType
; Type
++) {
693 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
694 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
695 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
699 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
700 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== MAX_ALLOC_ADDRESS
) {
701 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
705 mMemoryTypeInformationInitialized
= TRUE
;
709 Internal function. Converts a memory range to the specified type or attributes.
710 The range must exist in the memory map. Either ChangingType or
711 ChangingAttributes must be set, but not both.
713 @param Start The first address of the range Must be page
715 @param NumberOfPages The number of pages to convert
716 @param ChangingType Boolean indicating that type value should be changed
717 @param NewType The new type for the memory range
718 @param ChangingAttributes Boolean indicating that attributes value should be changed
719 @param NewAttributes The new attributes for the memory range
721 @retval EFI_INVALID_PARAMETER Invalid parameter
722 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
723 range or convertion not allowed.
724 @retval EFI_SUCCESS Successfully converts the memory range to the
731 IN UINT64 NumberOfPages
,
732 IN BOOLEAN ChangingType
,
733 IN EFI_MEMORY_TYPE NewType
,
734 IN BOOLEAN ChangingAttributes
,
735 IN UINT64 NewAttributes
738 UINT64 NumberOfBytes
;
742 EFI_MEMORY_TYPE MemType
;
747 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
748 End
= Start
+ NumberOfBytes
- 1;
750 ASSERT (NumberOfPages
);
751 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
752 ASSERT (End
> Start
);
753 ASSERT_LOCKED (&gMemoryLock
);
754 ASSERT ((ChangingType
== FALSE
) || (ChangingAttributes
== FALSE
));
756 if ((NumberOfPages
== 0) || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
>= End
)) {
757 return EFI_INVALID_PARAMETER
;
761 // Convert the entire range
764 while (Start
< End
) {
766 // Find the entry that the covers the range
768 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
769 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
771 if ((Entry
->Start
<= Start
) && (Entry
->End
> Start
)) {
776 if (Link
== &gMemoryMap
) {
777 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
778 return EFI_NOT_FOUND
;
782 // If we are converting the type of the range from EfiConventionalMemory to
783 // another type, we have to ensure that the entire range is covered by a
786 if (ChangingType
&& (NewType
!= EfiConventionalMemory
)) {
787 if (Entry
->End
< End
) {
788 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: range %lx - %lx covers multiple entries\n", Start
, End
));
789 return EFI_NOT_FOUND
;
794 // Convert range to the end, or to the end of the descriptor
795 // if that's all we've got
799 ASSERT (Entry
!= NULL
);
800 if (Entry
->End
< End
) {
801 RangeEnd
= Entry
->End
;
805 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to type %d\n", Start
, RangeEnd
, NewType
));
808 if (ChangingAttributes
) {
809 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to attr %lx\n", Start
, RangeEnd
, NewAttributes
));
814 // Debug code - verify conversion is allowed
816 if (!((NewType
== EfiConventionalMemory
) ? 1 : 0) ^ ((Entry
->Type
== EfiConventionalMemory
) ? 1 : 0)) {
817 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: Incompatible memory types, "));
818 if (Entry
->Type
== EfiConventionalMemory
) {
819 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to free have been freed\n"));
821 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to allocate have been allocated\n"));
824 return EFI_NOT_FOUND
;
828 // Update counters for the number of pages allocated to each memory type
830 if ((UINT32
)Entry
->Type
< EfiMaxMemoryType
) {
831 if (((Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
) && (Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
)) ||
832 ((Start
>= mDefaultBaseAddress
) && (Start
<= mDefaultMaximumAddress
)))
834 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
835 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
837 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
842 if ((UINT32
)NewType
< EfiMaxMemoryType
) {
843 if (((Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
) && (Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
)) ||
844 ((Start
>= mDefaultBaseAddress
) && (Start
<= mDefaultMaximumAddress
)))
846 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
847 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
> gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
848 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
855 // Pull range out of descriptor
857 if (Entry
->Start
== Start
) {
861 Entry
->Start
= RangeEnd
+ 1;
862 } else if (Entry
->End
== RangeEnd
) {
866 Entry
->End
= Start
- 1;
869 // Pull it out of the center, clip current
875 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
876 mMapStack
[mMapDepth
].FromPages
= FALSE
;
877 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
878 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
879 mMapStack
[mMapDepth
].End
= Entry
->End
;
882 // Inherit Attribute from the Memory Descriptor that is being clipped
884 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
886 Entry
->End
= Start
- 1;
887 ASSERT (Entry
->Start
< Entry
->End
);
889 Entry
= &mMapStack
[mMapDepth
];
890 InsertTailList (&gMemoryMap
, &Entry
->Link
);
893 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
897 // The new range inherits the same Attribute as the Entry
898 // it is being cut out of unless attributes are being changed
901 Attribute
= Entry
->Attribute
;
904 Attribute
= NewAttributes
;
905 MemType
= Entry
->Type
;
909 // If the descriptor is empty, then remove it from the map
911 if (Entry
->Start
== Entry
->End
+ 1) {
912 RemoveMemoryMapEntry (Entry
);
917 // Add our new range in. Don't do this for freed pages if freed-memory
920 if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED
) ||
922 (MemType
!= EfiConventionalMemory
))
924 CoreAddRange (MemType
, Start
, RangeEnd
, Attribute
);
927 if (ChangingType
&& (MemType
== EfiConventionalMemory
)) {
929 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
930 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
931 // that the page starting at address 0 is always filled with zeros.
934 if (RangeEnd
> EFI_PAGE_SIZE
) {
935 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)EFI_PAGE_SIZE
, (UINTN
)(RangeEnd
- EFI_PAGE_SIZE
+ 1));
938 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Start
, (UINTN
)(RangeEnd
- Start
+ 1));
943 // Move any map descriptor stack to general pool
945 CoreFreeMemoryMapStack ();
948 // Bump the starting address, and convert the next range
950 Start
= RangeEnd
+ 1;
954 // Converted the whole range, done
961 Internal function. Converts a memory range to the specified type.
962 The range must exist in the memory map.
964 @param Start The first address of the range Must be page
966 @param NumberOfPages The number of pages to convert
967 @param NewType The new type for the memory range
969 @retval EFI_INVALID_PARAMETER Invalid parameter
970 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
971 range or convertion not allowed.
972 @retval EFI_SUCCESS Successfully converts the memory range to the
979 IN UINT64 NumberOfPages
,
980 IN EFI_MEMORY_TYPE NewType
983 return CoreConvertPagesEx (Start
, NumberOfPages
, TRUE
, NewType
, FALSE
, 0);
987 Internal function. Converts a memory range to use new attributes.
989 @param Start The first address of the range Must be page
991 @param NumberOfPages The number of pages to convert
992 @param NewAttributes The new attributes value for the range.
996 CoreUpdateMemoryAttributes (
997 IN EFI_PHYSICAL_ADDRESS Start
,
998 IN UINT64 NumberOfPages
,
999 IN UINT64 NewAttributes
1002 CoreAcquireMemoryLock ();
1005 // Update the attributes to the new value
1007 CoreConvertPagesEx (Start
, NumberOfPages
, FALSE
, (EFI_MEMORY_TYPE
)0, TRUE
, NewAttributes
);
1009 CoreReleaseMemoryLock ();
1013 Internal function. Finds a consecutive free page range below
1014 the requested address.
1016 @param MaxAddress The address that the range must be below
1017 @param MinAddress The address that the range must be above
1018 @param NumberOfPages Number of pages needed
1019 @param NewType The type of memory the range is going to be
1021 @param Alignment Bits to align with
1022 @param NeedGuard Flag to indicate Guard page is needed or not
1024 @return The base address of the range, or 0 if the range was not found
1028 CoreFindFreePagesI (
1029 IN UINT64 MaxAddress
,
1030 IN UINT64 MinAddress
,
1031 IN UINT64 NumberOfPages
,
1032 IN EFI_MEMORY_TYPE NewType
,
1034 IN BOOLEAN NeedGuard
1037 UINT64 NumberOfBytes
;
1041 UINT64 DescNumberOfBytes
;
1045 if ((MaxAddress
< EFI_PAGE_MASK
) || (NumberOfPages
== 0)) {
1049 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
1051 // If MaxAddress is not aligned to the end of a page
1055 // Change MaxAddress to be 1 page lower
1057 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
1060 // Set MaxAddress to a page boundary
1062 MaxAddress
&= ~(UINT64
)EFI_PAGE_MASK
;
1065 // Set MaxAddress to end of the page
1067 MaxAddress
|= EFI_PAGE_MASK
;
1070 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1073 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1074 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1077 // If it's not a free entry, don't bother with it
1079 if (Entry
->Type
!= EfiConventionalMemory
) {
1083 DescStart
= Entry
->Start
;
1084 DescEnd
= Entry
->End
;
1087 // If desc is past max allowed address or below min allowed address, skip it
1089 if ((DescStart
>= MaxAddress
) || (DescEnd
< MinAddress
)) {
1094 // If desc ends past max allowed address, clip the end
1096 if (DescEnd
>= MaxAddress
) {
1097 DescEnd
= MaxAddress
;
1100 DescEnd
= ((DescEnd
+ 1) & (~((UINT64
)Alignment
- 1))) - 1;
1102 // Skip if DescEnd is less than DescStart after alignment clipping
1103 if (DescEnd
< DescStart
) {
1108 // Compute the number of bytes we can used from this
1109 // descriptor, and see it's enough to satisfy the request
1111 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
1113 if (DescNumberOfBytes
>= NumberOfBytes
) {
1115 // If the start of the allocated range is below the min address allowed, skip it
1117 if ((DescEnd
- NumberOfBytes
+ 1) < MinAddress
) {
1122 // If this is the best match so far remember it
1124 if (DescEnd
> Target
) {
1126 DescEnd
= AdjustMemoryS (
1127 DescEnd
+ 1 - DescNumberOfBytes
,
1142 // If this is a grow down, adjust target to be the allocation base
1144 Target
-= NumberOfBytes
- 1;
1147 // If we didn't find a match, return 0
1149 if ((Target
& EFI_PAGE_MASK
) != 0) {
1157 Internal function. Finds a consecutive free page range below
1158 the requested address
1160 @param MaxAddress The address that the range must be below
1161 @param NoPages Number of pages needed
1162 @param NewType The type of memory the range is going to be
1164 @param Alignment Bits to align with
1165 @param NeedGuard Flag to indicate Guard page is needed or not
1167 @return The base address of the range, or 0 if the range was not found.
1172 IN UINT64 MaxAddress
,
1174 IN EFI_MEMORY_TYPE NewType
,
1176 IN BOOLEAN NeedGuard
1182 // Attempt to find free pages in the preferred bin based on the requested memory type
1184 if (((UINT32
)NewType
< EfiMaxMemoryType
) && (MaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
)) {
1185 Start
= CoreFindFreePagesI (
1186 mMemoryTypeStatistics
[NewType
].MaximumAddress
,
1187 mMemoryTypeStatistics
[NewType
].BaseAddress
,
1199 // Attempt to find free pages in the default allocation bin
1201 if (MaxAddress
>= mDefaultMaximumAddress
) {
1202 Start
= CoreFindFreePagesI (
1203 mDefaultMaximumAddress
,
1211 if (Start
< mDefaultBaseAddress
) {
1212 mDefaultBaseAddress
= Start
;
1220 // The allocation did not succeed in any of the prefered bins even after
1221 // promoting resources. Attempt to find free pages anywhere is the requested
1222 // address range. If this allocation fails, then there are not enough
1223 // resources anywhere to satisfy the request.
1225 Start
= CoreFindFreePagesI (
1238 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1240 if (!PromoteMemoryResource ()) {
1245 // If any memory resources were promoted, then re-attempt the allocation
1247 return FindFreePages (MaxAddress
, NoPages
, NewType
, Alignment
, NeedGuard
);
1251 Allocates pages from the memory map.
1253 @param Type The type of allocation to perform
1254 @param MemoryType The type of memory to turn the allocated pages
1256 @param NumberOfPages The number of pages to allocate
1257 @param Memory A pointer to receive the base allocated memory
1259 @param NeedGuard Flag to indicate Guard page is needed or not
1261 @return Status. On success, Memory is filled in with the base address allocated
1262 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1264 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1265 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1266 @retval EFI_SUCCESS Pages successfully allocated.
1271 CoreInternalAllocatePages (
1272 IN EFI_ALLOCATE_TYPE Type
,
1273 IN EFI_MEMORY_TYPE MemoryType
,
1274 IN UINTN NumberOfPages
,
1275 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
1276 IN BOOLEAN NeedGuard
1281 UINT64 NumberOfBytes
;
1285 EFI_MEMORY_TYPE CheckType
;
1287 if ((UINT32
)Type
>= MaxAllocateType
) {
1288 return EFI_INVALID_PARAMETER
;
1291 if (((MemoryType
>= EfiMaxMemoryType
) && (MemoryType
< MEMORY_TYPE_OEM_RESERVED_MIN
)) ||
1292 (MemoryType
== EfiConventionalMemory
) || (MemoryType
== EfiPersistentMemory
) || (MemoryType
== EfiUnacceptedMemoryType
))
1294 return EFI_INVALID_PARAMETER
;
1297 if (Memory
== NULL
) {
1298 return EFI_INVALID_PARAMETER
;
1301 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1303 if ((MemoryType
== EfiACPIReclaimMemory
) ||
1304 (MemoryType
== EfiACPIMemoryNVS
) ||
1305 (MemoryType
== EfiRuntimeServicesCode
) ||
1306 (MemoryType
== EfiRuntimeServicesData
))
1308 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1311 if (Type
== AllocateAddress
) {
1312 if ((*Memory
& (Alignment
- 1)) != 0) {
1313 return EFI_NOT_FOUND
;
1317 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1318 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1321 // If this is for below a particular address, then
1326 // The max address is the max natively addressable address for the processor
1328 MaxAddress
= MAX_ALLOC_ADDRESS
;
1331 // Check for Type AllocateAddress,
1332 // if NumberOfPages is 0 or
1333 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
1334 // if (Start + NumberOfBytes) rolls over 0 or
1335 // if Start is above MAX_ALLOC_ADDRESS or
1336 // if End is above MAX_ALLOC_ADDRESS,
1337 // if Start..End overlaps any tracked MemoryTypeStatistics range
1338 // return EFI_NOT_FOUND.
1340 if (Type
== AllocateAddress
) {
1341 if ((NumberOfPages
== 0) ||
1342 (NumberOfPages
> RShiftU64 (MaxAddress
, EFI_PAGE_SHIFT
)))
1344 return EFI_NOT_FOUND
;
1347 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1348 End
= Start
+ NumberOfBytes
- 1;
1350 if ((Start
>= End
) ||
1351 (Start
> MaxAddress
) ||
1354 return EFI_NOT_FOUND
;
1358 // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of
1359 // AllocatePage request the exact physical address if it is not used. The existing code
1360 // will allow this request even in 'special' pages. The problem with this is that the
1361 // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
1365 for (CheckType
= (EFI_MEMORY_TYPE
)0; CheckType
< EfiMaxMemoryType
; CheckType
++) {
1366 if ((MemoryType
!= CheckType
) &&
1367 mMemoryTypeStatistics
[CheckType
].Special
&&
1368 (mMemoryTypeStatistics
[CheckType
].NumberOfPages
> 0))
1370 if ((Start
>= mMemoryTypeStatistics
[CheckType
].BaseAddress
) &&
1371 (Start
<= mMemoryTypeStatistics
[CheckType
].MaximumAddress
))
1373 return EFI_NOT_FOUND
;
1376 if ((End
>= mMemoryTypeStatistics
[CheckType
].BaseAddress
) &&
1377 (End
<= mMemoryTypeStatistics
[CheckType
].MaximumAddress
))
1379 return EFI_NOT_FOUND
;
1382 if ((Start
< mMemoryTypeStatistics
[CheckType
].BaseAddress
) &&
1383 (End
> mMemoryTypeStatistics
[CheckType
].MaximumAddress
))
1385 return EFI_NOT_FOUND
;
1391 if (Type
== AllocateMaxAddress
) {
1395 CoreAcquireMemoryLock ();
1398 // If not a specific address, then find an address to allocate
1400 if (Type
!= AllocateAddress
) {
1401 Start
= FindFreePages (
1409 Status
= EFI_OUT_OF_RESOURCES
;
1415 // Convert pages from FreeMemory to the requested type
1418 Status
= CoreConvertPagesWithGuard (Start
, NumberOfPages
, MemoryType
);
1420 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1423 if (EFI_ERROR (Status
)) {
1425 // If requested memory region is unavailable it may be untested memory
1426 // Attempt to promote memory resources, then re-attempt the allocation
1428 if (PromoteMemoryResource ()) {
1430 Status
= CoreConvertPagesWithGuard (Start
, NumberOfPages
, MemoryType
);
1432 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1438 CoreReleaseMemoryLock ();
1440 if (!EFI_ERROR (Status
)) {
1442 SetGuardForMemory (Start
, NumberOfPages
);
1452 Allocates pages from the memory map.
1454 @param Type The type of allocation to perform
1455 @param MemoryType The type of memory to turn the allocated pages
1457 @param NumberOfPages The number of pages to allocate
1458 @param Memory A pointer to receive the base allocated memory
1461 @return Status. On success, Memory is filled in with the base address allocated
1462 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1464 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1465 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1466 @retval EFI_SUCCESS Pages successfully allocated.
1472 IN EFI_ALLOCATE_TYPE Type
,
1473 IN EFI_MEMORY_TYPE MemoryType
,
1474 IN UINTN NumberOfPages
,
1475 OUT EFI_PHYSICAL_ADDRESS
*Memory
1481 NeedGuard
= IsPageTypeToGuard (MemoryType
, Type
) && !mOnGuarding
;
1482 Status
= CoreInternalAllocatePages (
1489 if (!EFI_ERROR (Status
)) {
1491 (EFI_PHYSICAL_ADDRESS
)(UINTN
)RETURN_ADDRESS (0),
1492 MemoryProfileActionAllocatePages
,
1494 EFI_PAGES_TO_SIZE (NumberOfPages
),
1495 (VOID
*)(UINTN
)*Memory
,
1498 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1499 ApplyMemoryProtectionPolicy (
1500 EfiConventionalMemory
,
1503 EFI_PAGES_TO_SIZE (NumberOfPages
)
1511 Frees previous allocated pages.
1513 @param Memory Base address of memory being freed
1514 @param NumberOfPages The number of pages to free
1515 @param MemoryType Pointer to memory type
1517 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1518 @retval EFI_INVALID_PARAMETER Address not aligned
1519 @return EFI_SUCCESS -Pages successfully freed.
1524 CoreInternalFreePages (
1525 IN EFI_PHYSICAL_ADDRESS Memory
,
1526 IN UINTN NumberOfPages
,
1527 OUT EFI_MEMORY_TYPE
*MemoryType OPTIONAL
1539 CoreAcquireMemoryLock ();
1542 // Find the entry that the covers the range
1546 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1547 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1548 if ((Entry
->Start
<= Memory
) && (Entry
->End
> Memory
)) {
1553 if (Link
== &gMemoryMap
) {
1554 Status
= EFI_NOT_FOUND
;
1558 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1560 ASSERT (Entry
!= NULL
);
1561 if ((Entry
->Type
== EfiACPIReclaimMemory
) ||
1562 (Entry
->Type
== EfiACPIMemoryNVS
) ||
1563 (Entry
->Type
== EfiRuntimeServicesCode
) ||
1564 (Entry
->Type
== EfiRuntimeServicesData
))
1566 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1569 if ((Memory
& (Alignment
- 1)) != 0) {
1570 Status
= EFI_INVALID_PARAMETER
;
1574 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1575 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1577 if (MemoryType
!= NULL
) {
1578 *MemoryType
= Entry
->Type
;
1581 IsGuarded
= IsPageTypeToGuard (Entry
->Type
, AllocateAnyPages
) &&
1582 IsMemoryGuarded (Memory
);
1584 Status
= CoreConvertPagesWithGuard (
1587 EfiConventionalMemory
1590 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1594 CoreReleaseMemoryLock ();
1599 Frees previous allocated pages.
1601 @param Memory Base address of memory being freed
1602 @param NumberOfPages The number of pages to free
1604 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1605 @retval EFI_INVALID_PARAMETER Address not aligned
1606 @return EFI_SUCCESS -Pages successfully freed.
1612 IN EFI_PHYSICAL_ADDRESS Memory
,
1613 IN UINTN NumberOfPages
1617 EFI_MEMORY_TYPE MemoryType
;
1619 Status
= CoreInternalFreePages (Memory
, NumberOfPages
, &MemoryType
);
1620 if (!EFI_ERROR (Status
)) {
1621 GuardFreedPagesChecked (Memory
, NumberOfPages
);
1623 (EFI_PHYSICAL_ADDRESS
)(UINTN
)RETURN_ADDRESS (0),
1624 MemoryProfileActionFreePages
,
1626 EFI_PAGES_TO_SIZE (NumberOfPages
),
1627 (VOID
*)(UINTN
)Memory
,
1630 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1631 ApplyMemoryProtectionPolicy (
1633 EfiConventionalMemory
,
1635 EFI_PAGES_TO_SIZE (NumberOfPages
)
1643 This function checks to see if the last memory map descriptor in a memory map
1644 can be merged with any of the other memory map descriptors in a memorymap.
1645 Memory descriptors may be merged if they are adjacent and have the same type
1648 @param MemoryMap A pointer to the start of the memory map.
1649 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1650 @param DescriptorSize The size, in bytes, of an individual
1651 EFI_MEMORY_DESCRIPTOR.
1653 @return A pointer to the next available descriptor in MemoryMap
1656 EFI_MEMORY_DESCRIPTOR
*
1657 MergeMemoryMapDescriptor (
1658 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1659 IN EFI_MEMORY_DESCRIPTOR
*MemoryMapDescriptor
,
1660 IN UINTN DescriptorSize
1664 // Traverse the array of descriptors in MemoryMap
1666 for ( ; MemoryMap
!= MemoryMapDescriptor
; MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
)) {
1668 // Check to see if the Type fields are identical.
1670 if (MemoryMap
->Type
!= MemoryMapDescriptor
->Type
) {
1675 // Check to see if the Attribute fields are identical.
1677 if (MemoryMap
->Attribute
!= MemoryMapDescriptor
->Attribute
) {
1682 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1684 if (MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1686 // Merge MemoryMapDescriptor into MemoryMap
1688 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1691 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1693 return MemoryMapDescriptor
;
1697 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1699 if (MemoryMap
->PhysicalStart
- EFI_PAGES_TO_SIZE ((UINTN
)MemoryMapDescriptor
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1701 // Merge MemoryMapDescriptor into MemoryMap
1703 MemoryMap
->PhysicalStart
= MemoryMapDescriptor
->PhysicalStart
;
1704 MemoryMap
->VirtualStart
= MemoryMapDescriptor
->VirtualStart
;
1705 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1708 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1710 return MemoryMapDescriptor
;
1715 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1717 // Return the slot immediately after MemoryMapDescriptor as the next available
1718 // slot in the MemoryMap array
1720 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor
, DescriptorSize
);
1724 This function returns a copy of the current memory map. The map is an array of
1725 memory descriptors, each of which describes a contiguous block of memory.
1727 @param MemoryMapSize A pointer to the size, in bytes, of the
1728 MemoryMap buffer. On input, this is the size of
1729 the buffer allocated by the caller. On output,
1730 it is the size of the buffer returned by the
1731 firmware if the buffer was large enough, or the
1732 size of the buffer needed to contain the map if
1733 the buffer was too small.
1734 @param MemoryMap A pointer to the buffer in which firmware places
1735 the current memory map.
1736 @param MapKey A pointer to the location in which firmware
1737 returns the key for the current memory map.
1738 @param DescriptorSize A pointer to the location in which firmware
1739 returns the size, in bytes, of an individual
1740 EFI_MEMORY_DESCRIPTOR.
1741 @param DescriptorVersion A pointer to the location in which firmware
1742 returns the version number associated with the
1743 EFI_MEMORY_DESCRIPTOR.
1745 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1747 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1748 buffer size needed to hold the memory map is
1749 returned in MemoryMapSize.
1750 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1756 IN OUT UINTN
*MemoryMapSize
,
1757 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1759 OUT UINTN
*DescriptorSize
,
1760 OUT UINT32
*DescriptorVersion
1766 UINTN NumberOfEntries
;
1769 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1770 EFI_GCD_MAP_ENTRY MergeGcdMapEntry
;
1771 EFI_MEMORY_TYPE Type
;
1772 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
1773 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1776 // Make sure the parameters are valid
1778 if (MemoryMapSize
== NULL
) {
1779 return EFI_INVALID_PARAMETER
;
1782 CoreAcquireGcdMemoryLock ();
1785 // Count the number of Reserved and runtime MMIO entries
1786 // And, count the number of Persistent entries.
1788 NumberOfEntries
= 0;
1789 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1790 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1791 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypePersistent
) ||
1792 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1793 ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1794 ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
)))
1800 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1803 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1804 // prevent people from having pointer math bugs in their code.
1805 // now you have to use *DescriptorSize to make things work.
1807 Size
+= sizeof (UINT64
) - (Size
% sizeof (UINT64
));
1809 if (DescriptorSize
!= NULL
) {
1810 *DescriptorSize
= Size
;
1813 if (DescriptorVersion
!= NULL
) {
1814 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1817 CoreAcquireMemoryLock ();
1820 // Compute the buffer size needed to fit the entire map
1822 BufferSize
= Size
* NumberOfEntries
;
1823 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1827 if (*MemoryMapSize
< BufferSize
) {
1828 Status
= EFI_BUFFER_TOO_SMALL
;
1832 if (MemoryMap
== NULL
) {
1833 Status
= EFI_INVALID_PARAMETER
;
1840 ZeroMem (MemoryMap
, BufferSize
);
1841 MemoryMapStart
= MemoryMap
;
1842 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1843 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1844 ASSERT (Entry
->VirtualStart
== 0);
1847 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1849 MemoryMap
->Type
= Entry
->Type
;
1850 MemoryMap
->PhysicalStart
= Entry
->Start
;
1851 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1852 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1854 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1855 // memory type bin and needs to be converted to the same memory type as the rest of the
1856 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1857 // improves the chances for a successful S4 resume in the presence of minor page allocation
1858 // differences across reboots.
1860 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1861 for (Type
= (EFI_MEMORY_TYPE
)0; Type
< EfiMaxMemoryType
; Type
++) {
1862 if (mMemoryTypeStatistics
[Type
].Special
&&
1863 (mMemoryTypeStatistics
[Type
].NumberOfPages
> 0) &&
1864 (Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
) &&
1865 (Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
))
1867 MemoryMap
->Type
= Type
;
1872 MemoryMap
->Attribute
= Entry
->Attribute
;
1873 if (MemoryMap
->Type
< EfiMaxMemoryType
) {
1874 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1875 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1880 // Check to see if the new Memory Map Descriptor can be merged with an
1881 // existing descriptor if they are adjacent and have the same attributes
1883 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1886 ZeroMem (&MergeGcdMapEntry
, sizeof (MergeGcdMapEntry
));
1888 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; ; Link
= Link
->ForwardLink
) {
1889 if (Link
!= &mGcdMemorySpaceMap
) {
1891 // Merge adjacent same type and attribute GCD memory range
1893 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1895 if ((MergeGcdMapEntry
.Capabilities
== GcdMapEntry
->Capabilities
) &&
1896 (MergeGcdMapEntry
.Attributes
== GcdMapEntry
->Attributes
) &&
1897 (MergeGcdMapEntry
.GcdMemoryType
== GcdMapEntry
->GcdMemoryType
) &&
1898 (MergeGcdMapEntry
.GcdIoType
== GcdMapEntry
->GcdIoType
))
1900 MergeGcdMapEntry
.EndAddress
= GcdMapEntry
->EndAddress
;
1905 if ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1906 ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1907 ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
)))
1910 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1911 // it will be recorded as page PhysicalStart and NumberOfPages.
1913 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1914 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1917 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1919 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1920 MemoryMap
->VirtualStart
= 0;
1921 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1922 MemoryMap
->Attribute
= (MergeGcdMapEntry
.Attributes
& ~EFI_MEMORY_PORT_IO
) |
1923 (MergeGcdMapEntry
.Capabilities
& (EFI_CACHE_ATTRIBUTE_MASK
| EFI_MEMORY_ATTRIBUTE_MASK
));
1925 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1926 MemoryMap
->Type
= EfiReservedMemoryType
;
1927 } else if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1928 if ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1929 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1931 MemoryMap
->Type
= EfiMemoryMappedIO
;
1936 // Check to see if the new Memory Map Descriptor can be merged with an
1937 // existing descriptor if they are adjacent and have the same attributes
1939 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1942 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypePersistent
) {
1944 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1945 // it will be recorded as page PhysicalStart and NumberOfPages.
1947 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1948 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1951 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1953 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1954 MemoryMap
->VirtualStart
= 0;
1955 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1956 MemoryMap
->Attribute
= MergeGcdMapEntry
.Attributes
| EFI_MEMORY_NV
|
1957 (MergeGcdMapEntry
.Capabilities
& (EFI_CACHE_ATTRIBUTE_MASK
| EFI_MEMORY_ATTRIBUTE_MASK
));
1958 MemoryMap
->Type
= EfiPersistentMemory
;
1961 // Check to see if the new Memory Map Descriptor can be merged with an
1962 // existing descriptor if they are adjacent and have the same attributes
1964 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1967 if (MergeGcdMapEntry
.GcdMemoryType
== EFI_GCD_MEMORY_TYPE_UNACCEPTED
) {
1969 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1970 // it will be recorded as page PhysicalStart and NumberOfPages.
1972 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1973 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1976 // Create EFI_MEMORY_DESCRIPTOR for every Unaccepted GCD entries
1978 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1979 MemoryMap
->VirtualStart
= 0;
1980 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1981 MemoryMap
->Attribute
= MergeGcdMapEntry
.Attributes
|
1982 (MergeGcdMapEntry
.Capabilities
& (EFI_MEMORY_RP
| EFI_MEMORY_WP
| EFI_MEMORY_XP
| EFI_MEMORY_RO
|
1983 EFI_MEMORY_UC
| EFI_MEMORY_UCE
| EFI_MEMORY_WC
| EFI_MEMORY_WT
| EFI_MEMORY_WB
));
1984 MemoryMap
->Type
= EfiUnacceptedMemoryType
;
1987 // Check to see if the new Memory Map Descriptor can be merged with an
1988 // existing descriptor if they are adjacent and have the same attributes
1990 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1993 if (Link
== &mGcdMemorySpaceMap
) {
1995 // break loop when arrive at head.
2000 if (GcdMapEntry
!= NULL
) {
2002 // Copy new GCD map entry for the following GCD range merge
2004 CopyMem (&MergeGcdMapEntry
, GcdMapEntry
, sizeof (MergeGcdMapEntry
));
2009 // Compute the size of the buffer actually used after all memory map descriptor merge operations
2011 BufferSize
= ((UINT8
*)MemoryMap
- (UINT8
*)MemoryMapStart
);
2014 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
2015 // set attributes and change memory paging attribute accordingly.
2016 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
2017 // value from Capabilities in GCD memory map. This might cause
2018 // boot problems. Clearing all page-access permission related
2019 // capabilities can workaround it. Following code is supposed to
2020 // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute
2021 // is clarified in UEFI spec and adopted by both EDK-II Core and
2022 // all supported OSs.
2024 MemoryMapEnd
= MemoryMap
;
2025 MemoryMap
= MemoryMapStart
;
2026 while (MemoryMap
< MemoryMapEnd
) {
2027 MemoryMap
->Attribute
&= ~(UINT64
)EFI_MEMORY_ACCESS_MASK
;
2028 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, Size
);
2031 MergeMemoryMap (MemoryMapStart
, &BufferSize
, Size
);
2032 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MemoryMapStart
+ BufferSize
);
2034 Status
= EFI_SUCCESS
;
2038 // Update the map key finally
2040 if (MapKey
!= NULL
) {
2041 *MapKey
= mMemoryMapKey
;
2044 CoreReleaseMemoryLock ();
2046 CoreReleaseGcdMemoryLock ();
2048 *MemoryMapSize
= BufferSize
;
2051 DumpGuardedMemoryBitmap ();
2058 Internal function. Used by the pool functions to allocate pages
2059 to back pool allocation requests.
2061 @param PoolType The type of memory for the new pool pages
2062 @param NumberOfPages No of pages to allocate
2063 @param Alignment Bits to align.
2064 @param NeedGuard Flag to indicate Guard page is needed or not
2066 @return The allocated memory, or NULL
2070 CoreAllocatePoolPages (
2071 IN EFI_MEMORY_TYPE PoolType
,
2072 IN UINTN NumberOfPages
,
2074 IN BOOLEAN NeedGuard
2080 // Find the pages to convert
2082 Start
= FindFreePages (
2091 // Convert it to boot services data
2094 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32
)NumberOfPages
));
2097 CoreConvertPagesWithGuard (Start
, NumberOfPages
, PoolType
);
2099 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
2103 return (VOID
*)(UINTN
)Start
;
2107 Internal function. Frees pool pages allocated via AllocatePoolPages ()
2109 @param Memory The base address to free
2110 @param NumberOfPages The number of pages to free
2115 IN EFI_PHYSICAL_ADDRESS Memory
,
2116 IN UINTN NumberOfPages
2119 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
2123 Make sure the memory map is following all the construction rules,
2124 it is the last time to check memory map error before exit boot services.
2126 @param MapKey Memory map key
2128 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2130 @retval EFI_SUCCESS Valid memory map.
2134 CoreTerminateMemoryMap (
2142 Status
= EFI_SUCCESS
;
2144 CoreAcquireMemoryLock ();
2146 if (MapKey
== mMemoryMapKey
) {
2148 // Make sure the memory map is following all the construction rules
2149 // This is the last chance we will be able to display any messages on
2150 // the console devices.
2153 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
2154 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
2155 if (Entry
->Type
< EfiMaxMemoryType
) {
2156 if (mMemoryTypeStatistics
[Entry
->Type
].Runtime
) {
2157 ASSERT (Entry
->Type
!= EfiACPIReclaimMemory
);
2158 ASSERT (Entry
->Type
!= EfiACPIMemoryNVS
);
2159 if ((Entry
->Start
& (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2160 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2161 Status
= EFI_INVALID_PARAMETER
;
2165 if (((Entry
->End
+ 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2166 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2167 Status
= EFI_INVALID_PARAMETER
;
2175 // The map key they gave us matches what we expect. Fall through and
2176 // return success. In an ideal world we would clear out all of
2177 // EfiBootServicesCode and EfiBootServicesData. However this function
2178 // is not the last one called by ExitBootServices(), so we have to
2179 // preserve the memory contents.
2182 Status
= EFI_INVALID_PARAMETER
;
2186 CoreReleaseMemoryLock ();