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"
14 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
17 EFI_PHYSICAL_ADDRESS BaseAddress
;
18 EFI_PHYSICAL_ADDRESS MaximumAddress
;
19 UINT64 CurrentNumberOfPages
;
21 UINTN InformationIndex
;
24 } EFI_MEMORY_TYPE_STATISTICS
;
27 // MemoryMap - The current memory map
29 UINTN mMemoryMapKey
= 0;
31 #define MAX_MAP_DEPTH 6
34 /// mMapDepth - depth of new descriptor stack
38 /// mMapStack - space to use as temp storage to build new map descriptors
40 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
41 UINTN mFreeMapStack
= 0;
43 /// This list maintain the free memory map list
45 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
46 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
48 EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
49 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
50 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
51 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
52 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
53 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
54 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
55 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
56 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
57 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
58 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
59 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
60 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
61 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
62 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
63 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiPersistentMemory
64 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
67 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= MAX_ALLOC_ADDRESS
;
68 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress
= MAX_ALLOC_ADDRESS
;
70 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
71 { EfiReservedMemoryType
, 0 },
74 { EfiBootServicesCode
, 0 },
75 { EfiBootServicesData
, 0 },
76 { EfiRuntimeServicesCode
, 0 },
77 { EfiRuntimeServicesData
, 0 },
78 { EfiConventionalMemory
, 0 },
79 { EfiUnusableMemory
, 0 },
80 { EfiACPIReclaimMemory
, 0 },
81 { EfiACPIMemoryNVS
, 0 },
82 { EfiMemoryMappedIO
, 0 },
83 { EfiMemoryMappedIOPortSpace
, 0 },
85 { EfiPersistentMemory
, 0 },
86 { EfiMaxMemoryType
, 0 }
89 // Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
90 // and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
91 // address assigned by DXE core.
93 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady
= FALSE
;
96 Enter critical section by gaining lock on gMemoryLock.
100 CoreAcquireMemoryLock (
104 CoreAcquireLock (&gMemoryLock
);
108 Exit critical section by releasing lock on gMemoryLock.
112 CoreReleaseMemoryLock (
116 CoreReleaseLock (&gMemoryLock
);
120 Internal function. Removes a descriptor entry.
122 @param Entry The entry to remove
126 RemoveMemoryMapEntry (
127 IN OUT MEMORY_MAP
*Entry
130 RemoveEntryList (&Entry
->Link
);
131 Entry
->Link
.ForwardLink
= NULL
;
133 if (Entry
->FromPages
) {
135 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
137 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
142 Internal function. Adds a ranges to the memory map.
143 The range must not already exist in the map.
145 @param Type The type of memory range to add
146 @param Start The starting address in the memory range Must be
148 @param End The last address in the range Must be the last
150 @param Attribute The attributes of the memory range to add
155 IN EFI_MEMORY_TYPE Type
,
156 IN EFI_PHYSICAL_ADDRESS Start
,
157 IN EFI_PHYSICAL_ADDRESS End
,
164 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
165 ASSERT (End
> Start
);
167 ASSERT_LOCKED (&gMemoryLock
);
169 DEBUG ((DEBUG_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
172 // If memory of type EfiConventionalMemory is being added that includes the page
173 // starting at address 0, then zero the page starting at address 0. This has
174 // two benifits. It helps find NULL pointer bugs and it also maximizes
175 // compatibility with operating systems that may evaluate memory in this page
176 // for legacy data structures. If memory of any other type is added starting
177 // at address 0, then do not zero the page at address 0 because the page is being
178 // used for other purposes.
180 if ((Type
== EfiConventionalMemory
) && (Start
== 0) && (End
>= EFI_PAGE_SIZE
- 1)) {
181 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask
) & BIT0
) == 0) {
182 SetMem ((VOID
*)(UINTN
)Start
, EFI_PAGE_SIZE
, 0);
187 // Memory map being altered so updated key
192 // UEFI 2.0 added an event group for notificaiton on memory map changes.
193 // So we need to signal this Event Group every time the memory map changes.
194 // If we are in EFI 1.10 compatability mode no event groups will be
195 // found and nothing will happen we we call this function. These events
196 // will get signaled but since a lock is held around the call to this
197 // function the notificaiton events will only be called after this function
198 // returns and the lock is released.
200 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
203 // Look for adjoining memory descriptor
206 // Two memory descriptors can only be merged if they have the same Type
207 // and the same Attribute
210 Link
= gMemoryMap
.ForwardLink
;
211 while (Link
!= &gMemoryMap
) {
212 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
213 Link
= Link
->ForwardLink
;
215 if (Entry
->Type
!= Type
) {
219 if (Entry
->Attribute
!= Attribute
) {
223 if (Entry
->End
+ 1 == Start
) {
224 Start
= Entry
->Start
;
225 RemoveMemoryMapEntry (Entry
);
226 } else if (Entry
->Start
== End
+ 1) {
228 RemoveMemoryMapEntry (Entry
);
236 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
237 mMapStack
[mMapDepth
].FromPages
= FALSE
;
238 mMapStack
[mMapDepth
].Type
= Type
;
239 mMapStack
[mMapDepth
].Start
= Start
;
240 mMapStack
[mMapDepth
].End
= End
;
241 mMapStack
[mMapDepth
].VirtualStart
= 0;
242 mMapStack
[mMapDepth
].Attribute
= Attribute
;
243 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
246 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
252 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
253 If the list is emtry, then allocate a new page to refuel the list.
254 Please Note this algorithm to allocate the memory map descriptor has a property
255 that the memory allocated for memory entries always grows, and will never really be freed
256 For example, if the current boot uses 2000 memory map entries at the maximum point, but
257 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
258 memory map entries is still allocated from EfiBootServicesMemory.
261 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
265 AllocateMemoryMapEntry (
269 MEMORY_MAP
*FreeDescriptorEntries
;
273 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
275 // The list is empty, to allocate one page to refuel the list
277 FreeDescriptorEntries
= CoreAllocatePoolPages (
279 EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY
),
280 DEFAULT_PAGE_ALLOCATION_GRANULARITY
,
283 if (FreeDescriptorEntries
!= NULL
) {
285 // Enque the free memmory map entries into the list
287 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION_GRANULARITY
/ sizeof (MEMORY_MAP
); Index
++) {
288 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
289 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
297 // dequeue the first descriptor from the list
299 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
300 RemoveEntryList (&Entry
->Link
);
306 Internal function. Moves any memory descriptors that are on the
307 temporary descriptor stack to heap.
311 CoreFreeMemoryMapStack (
319 ASSERT_LOCKED (&gMemoryLock
);
322 // If already freeing the map stack, then return
324 if (mFreeMapStack
!= 0) {
329 // Move the temporary memory descriptor stack into pool
333 while (mMapDepth
!= 0) {
335 // Deque an memory map entry from mFreeMemoryMapEntryList
337 Entry
= AllocateMemoryMapEntry ();
342 // Update to proper entry
346 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
348 // Move this entry to general memory
350 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
351 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
353 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
354 Entry
->FromPages
= TRUE
;
357 // Find insertion location
359 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
360 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
361 if (Entry2
->FromPages
&& (Entry2
->Start
> Entry
->Start
)) {
366 InsertTailList (Link2
, &Entry
->Link
);
369 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
370 // so here no need to move it to memory.
372 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
380 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
384 PromoteMemoryResource (
389 EFI_GCD_MAP_ENTRY
*Entry
;
391 EFI_PHYSICAL_ADDRESS StartAddress
;
392 EFI_PHYSICAL_ADDRESS EndAddress
;
393 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
395 DEBUG ((DEBUG_PAGE
, "Promote the memory resource\n"));
397 CoreAcquireGcdMemoryLock ();
400 Link
= mGcdMemorySpaceMap
.ForwardLink
;
401 while (Link
!= &mGcdMemorySpaceMap
) {
402 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
404 if ((Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) &&
405 (Entry
->EndAddress
< MAX_ALLOC_ADDRESS
) &&
406 ((Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
407 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)))
410 // Update the GCD map
412 if ((Entry
->Capabilities
& EFI_MEMORY_MORE_RELIABLE
) == EFI_MEMORY_MORE_RELIABLE
) {
413 Entry
->GcdMemoryType
= EfiGcdMemoryTypeMoreReliable
;
415 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
418 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
419 Entry
->ImageHandle
= gDxeCoreImageHandle
;
420 Entry
->DeviceHandle
= NULL
;
423 // Add to allocable system memory resource
427 EfiConventionalMemory
,
430 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
432 CoreFreeMemoryMapStack ();
437 Link
= Link
->ForwardLink
;
440 CoreReleaseGcdMemoryLock ();
444 // If freed-memory guard is enabled, we could promote pages from
445 // guarded free pages.
447 Promoted
= PromoteGuardedFreePages (&StartAddress
, &EndAddress
);
449 CoreGetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
451 EfiConventionalMemory
,
454 Descriptor
.Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
|
455 EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
464 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
465 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
466 size of boot time and runtime code.
470 CoreLoadingFixedAddressHook (
474 UINT32 RuntimeCodePageNumber
;
475 UINT32 BootTimeCodePageNumber
;
476 EFI_PHYSICAL_ADDRESS RuntimeCodeBase
;
477 EFI_PHYSICAL_ADDRESS BootTimeCodeBase
;
481 // Make sure these 2 areas are not initialzied.
483 if (!gLoadFixedAddressCodeMemoryReady
) {
484 RuntimeCodePageNumber
= PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber
);
485 BootTimeCodePageNumber
= PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber
);
486 RuntimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(gLoadModuleAtFixAddressConfigurationTable
.DxeCodeTopAddress
- EFI_PAGES_TO_SIZE (RuntimeCodePageNumber
));
487 BootTimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(RuntimeCodeBase
- EFI_PAGES_TO_SIZE (BootTimeCodePageNumber
));
489 // Try to allocate runtime memory.
491 Status
= CoreAllocatePages (
493 EfiRuntimeServicesCode
,
494 RuntimeCodePageNumber
,
497 if (EFI_ERROR (Status
)) {
499 // Runtime memory allocation failed
505 // Try to allocate boot memory.
507 Status
= CoreAllocatePages (
510 BootTimeCodePageNumber
,
513 if (EFI_ERROR (Status
)) {
515 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
516 // new memory range is installed.
520 RuntimeCodePageNumber
525 gLoadFixedAddressCodeMemoryReady
= TRUE
;
532 Called to initialize the memory map and add descriptors to
533 the current descriptor list.
534 The first descriptor that is added must be general usable
535 memory as the addition allocates heap.
537 @param Type The type of memory to add
538 @param Start The starting address in the memory range Must be
540 @param NumberOfPages The number of pages in the range
541 @param Attribute Attributes of the memory to add
543 @return None. The range is added to the memory map
547 CoreAddMemoryDescriptor (
548 IN EFI_MEMORY_TYPE Type
,
549 IN EFI_PHYSICAL_ADDRESS Start
,
550 IN UINT64 NumberOfPages
,
554 EFI_PHYSICAL_ADDRESS End
;
559 if ((Start
& EFI_PAGE_MASK
) != 0) {
563 if ((Type
>= EfiMaxMemoryType
) && (Type
< MEMORY_TYPE_OEM_RESERVED_MIN
)) {
567 CoreAcquireMemoryLock ();
568 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
569 CoreAddRange (Type
, Start
, End
, Attribute
);
570 CoreFreeMemoryMapStack ();
571 CoreReleaseMemoryLock ();
573 ApplyMemoryProtectionPolicy (
577 LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
)
581 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
583 if (PcdGet64 (PcdLoadModuleAtFixAddressEnable
) != 0) {
584 CoreLoadingFixedAddressHook ();
588 // Check to see if the statistics for the different memory types have already been established
590 if (mMemoryTypeInformationInitialized
) {
595 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
597 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
599 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
601 Type
= (EFI_MEMORY_TYPE
)(gMemoryTypeInformation
[Index
].Type
);
602 if ((UINT32
)Type
> EfiMaxMemoryType
) {
606 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
608 // Allocate pages for the current memory type from the top of available memory
610 Status
= CoreAllocatePages (
613 gMemoryTypeInformation
[Index
].NumberOfPages
,
614 &mMemoryTypeStatistics
[Type
].BaseAddress
616 if (EFI_ERROR (Status
)) {
618 // If an error occurs allocating the pages for the current memory type, then
619 // free all the pages allocates for the previous memory types and return. This
620 // operation with be retied when/if more memory is added to the system
622 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
624 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
626 Type
= (EFI_MEMORY_TYPE
)(gMemoryTypeInformation
[FreeIndex
].Type
);
627 if ((UINT32
)Type
> EfiMaxMemoryType
) {
631 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
633 mMemoryTypeStatistics
[Type
].BaseAddress
,
634 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
636 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
637 mMemoryTypeStatistics
[Type
].MaximumAddress
= MAX_ALLOC_ADDRESS
;
645 // Compute the address at the top of the current statistics
647 mMemoryTypeStatistics
[Type
].MaximumAddress
=
648 mMemoryTypeStatistics
[Type
].BaseAddress
+
649 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
652 // If the current base address is the lowest address so far, then update the default
655 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
656 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
662 // There was enough system memory for all the the memory types were allocated. So,
663 // those memory areas can be freed for future allocations, and all future memory
664 // allocations can occur within their respective bins
666 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
668 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
670 Type
= (EFI_MEMORY_TYPE
)(gMemoryTypeInformation
[Index
].Type
);
671 if ((UINT32
)Type
> EfiMaxMemoryType
) {
675 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
677 mMemoryTypeStatistics
[Type
].BaseAddress
,
678 gMemoryTypeInformation
[Index
].NumberOfPages
680 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
681 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
686 // If the number of pages reserved for a memory type is 0, then all allocations for that type
687 // should be in the default range.
689 for (Type
= (EFI_MEMORY_TYPE
)0; Type
< EfiMaxMemoryType
; Type
++) {
690 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
691 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
692 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
696 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
697 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== MAX_ALLOC_ADDRESS
) {
698 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
702 mMemoryTypeInformationInitialized
= TRUE
;
706 Internal function. Converts a memory range to the specified type or attributes.
707 The range must exist in the memory map. Either ChangingType or
708 ChangingAttributes must be set, but not both.
710 @param Start The first address of the range Must be page
712 @param NumberOfPages The number of pages to convert
713 @param ChangingType Boolean indicating that type value should be changed
714 @param NewType The new type for the memory range
715 @param ChangingAttributes Boolean indicating that attributes value should be changed
716 @param NewAttributes The new attributes for the memory range
718 @retval EFI_INVALID_PARAMETER Invalid parameter
719 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
720 range or convertion not allowed.
721 @retval EFI_SUCCESS Successfully converts the memory range to the
728 IN UINT64 NumberOfPages
,
729 IN BOOLEAN ChangingType
,
730 IN EFI_MEMORY_TYPE NewType
,
731 IN BOOLEAN ChangingAttributes
,
732 IN UINT64 NewAttributes
735 UINT64 NumberOfBytes
;
739 EFI_MEMORY_TYPE MemType
;
744 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
745 End
= Start
+ NumberOfBytes
- 1;
747 ASSERT (NumberOfPages
);
748 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
749 ASSERT (End
> Start
);
750 ASSERT_LOCKED (&gMemoryLock
);
751 ASSERT ((ChangingType
== FALSE
) || (ChangingAttributes
== FALSE
));
753 if ((NumberOfPages
== 0) || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
>= End
)) {
754 return EFI_INVALID_PARAMETER
;
758 // Convert the entire range
761 while (Start
< End
) {
763 // Find the entry that the covers the range
765 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
766 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
768 if ((Entry
->Start
<= Start
) && (Entry
->End
> Start
)) {
773 if (Link
== &gMemoryMap
) {
774 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
775 return EFI_NOT_FOUND
;
779 // If we are converting the type of the range from EfiConventionalMemory to
780 // another type, we have to ensure that the entire range is covered by a
783 if (ChangingType
&& (NewType
!= EfiConventionalMemory
)) {
784 if (Entry
->End
< End
) {
785 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: range %lx - %lx covers multiple entries\n", Start
, End
));
786 return EFI_NOT_FOUND
;
791 // Convert range to the end, or to the end of the descriptor
792 // if that's all we've got
796 ASSERT (Entry
!= NULL
);
797 if (Entry
->End
< End
) {
798 RangeEnd
= Entry
->End
;
802 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to type %d\n", Start
, RangeEnd
, NewType
));
805 if (ChangingAttributes
) {
806 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to attr %lx\n", Start
, RangeEnd
, NewAttributes
));
811 // Debug code - verify conversion is allowed
813 if (!((NewType
== EfiConventionalMemory
) ? 1 : 0) ^ ((Entry
->Type
== EfiConventionalMemory
) ? 1 : 0)) {
814 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: Incompatible memory types, "));
815 if (Entry
->Type
== EfiConventionalMemory
) {
816 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to free have been freed\n"));
818 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to allocate have been allocated\n"));
821 return EFI_NOT_FOUND
;
825 // Update counters for the number of pages allocated to each memory type
827 if ((UINT32
)Entry
->Type
< EfiMaxMemoryType
) {
828 if (((Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
) && (Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
)) ||
829 ((Start
>= mDefaultBaseAddress
) && (Start
<= mDefaultMaximumAddress
)))
831 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
832 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
834 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
839 if ((UINT32
)NewType
< EfiMaxMemoryType
) {
840 if (((Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
) && (Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
)) ||
841 ((Start
>= mDefaultBaseAddress
) && (Start
<= mDefaultMaximumAddress
)))
843 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
844 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
> gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
845 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
852 // Pull range out of descriptor
854 if (Entry
->Start
== Start
) {
858 Entry
->Start
= RangeEnd
+ 1;
859 } else if (Entry
->End
== RangeEnd
) {
863 Entry
->End
= Start
- 1;
866 // Pull it out of the center, clip current
872 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
873 mMapStack
[mMapDepth
].FromPages
= FALSE
;
874 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
875 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
876 mMapStack
[mMapDepth
].End
= Entry
->End
;
879 // Inherit Attribute from the Memory Descriptor that is being clipped
881 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
883 Entry
->End
= Start
- 1;
884 ASSERT (Entry
->Start
< Entry
->End
);
886 Entry
= &mMapStack
[mMapDepth
];
887 InsertTailList (&gMemoryMap
, &Entry
->Link
);
890 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
894 // The new range inherits the same Attribute as the Entry
895 // it is being cut out of unless attributes are being changed
898 Attribute
= Entry
->Attribute
;
901 Attribute
= NewAttributes
;
902 MemType
= Entry
->Type
;
906 // If the descriptor is empty, then remove it from the map
908 if (Entry
->Start
== Entry
->End
+ 1) {
909 RemoveMemoryMapEntry (Entry
);
914 // Add our new range in. Don't do this for freed pages if freed-memory
917 if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED
) ||
919 (MemType
!= EfiConventionalMemory
))
921 CoreAddRange (MemType
, Start
, RangeEnd
, Attribute
);
924 if (ChangingType
&& (MemType
== EfiConventionalMemory
)) {
926 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
927 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
928 // that the page starting at address 0 is always filled with zeros.
931 if (RangeEnd
> EFI_PAGE_SIZE
) {
932 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)EFI_PAGE_SIZE
, (UINTN
)(RangeEnd
- EFI_PAGE_SIZE
+ 1));
935 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Start
, (UINTN
)(RangeEnd
- Start
+ 1));
940 // Move any map descriptor stack to general pool
942 CoreFreeMemoryMapStack ();
945 // Bump the starting address, and convert the next range
947 Start
= RangeEnd
+ 1;
951 // Converted the whole range, done
958 Internal function. Converts a memory range to the specified type.
959 The range must exist in the memory map.
961 @param Start The first address of the range Must be page
963 @param NumberOfPages The number of pages to convert
964 @param NewType The new type for the memory range
966 @retval EFI_INVALID_PARAMETER Invalid parameter
967 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
968 range or convertion not allowed.
969 @retval EFI_SUCCESS Successfully converts the memory range to the
976 IN UINT64 NumberOfPages
,
977 IN EFI_MEMORY_TYPE NewType
980 return CoreConvertPagesEx (Start
, NumberOfPages
, TRUE
, NewType
, FALSE
, 0);
984 Internal function. Converts a memory range to use new attributes.
986 @param Start The first address of the range Must be page
988 @param NumberOfPages The number of pages to convert
989 @param NewAttributes The new attributes value for the range.
993 CoreUpdateMemoryAttributes (
994 IN EFI_PHYSICAL_ADDRESS Start
,
995 IN UINT64 NumberOfPages
,
996 IN UINT64 NewAttributes
999 CoreAcquireMemoryLock ();
1002 // Update the attributes to the new value
1004 CoreConvertPagesEx (Start
, NumberOfPages
, FALSE
, (EFI_MEMORY_TYPE
)0, TRUE
, NewAttributes
);
1006 CoreReleaseMemoryLock ();
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 MinAddress The address that the range must be above
1015 @param NumberOfPages Number of pages needed
1016 @param NewType The type of memory the range is going to be
1018 @param Alignment Bits to align with
1019 @param NeedGuard Flag to indicate Guard page is needed or not
1021 @return The base address of the range, or 0 if the range was not found
1025 CoreFindFreePagesI (
1026 IN UINT64 MaxAddress
,
1027 IN UINT64 MinAddress
,
1028 IN UINT64 NumberOfPages
,
1029 IN EFI_MEMORY_TYPE NewType
,
1031 IN BOOLEAN NeedGuard
1034 UINT64 NumberOfBytes
;
1038 UINT64 DescNumberOfBytes
;
1042 if ((MaxAddress
< EFI_PAGE_MASK
) || (NumberOfPages
== 0)) {
1046 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
1048 // If MaxAddress is not aligned to the end of a page
1052 // Change MaxAddress to be 1 page lower
1054 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
1057 // Set MaxAddress to a page boundary
1059 MaxAddress
&= ~(UINT64
)EFI_PAGE_MASK
;
1062 // Set MaxAddress to end of the page
1064 MaxAddress
|= EFI_PAGE_MASK
;
1067 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1070 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1071 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1074 // If it's not a free entry, don't bother with it
1076 if (Entry
->Type
!= EfiConventionalMemory
) {
1080 DescStart
= Entry
->Start
;
1081 DescEnd
= Entry
->End
;
1084 // If desc is past max allowed address or below min allowed address, skip it
1086 if ((DescStart
>= MaxAddress
) || (DescEnd
< MinAddress
)) {
1091 // If desc ends past max allowed address, clip the end
1093 if (DescEnd
>= MaxAddress
) {
1094 DescEnd
= MaxAddress
;
1097 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
1099 // Skip if DescEnd is less than DescStart after alignment clipping
1100 if (DescEnd
< DescStart
) {
1105 // Compute the number of bytes we can used from this
1106 // descriptor, and see it's enough to satisfy the request
1108 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
1110 if (DescNumberOfBytes
>= NumberOfBytes
) {
1112 // If the start of the allocated range is below the min address allowed, skip it
1114 if ((DescEnd
- NumberOfBytes
+ 1) < MinAddress
) {
1119 // If this is the best match so far remember it
1121 if (DescEnd
> Target
) {
1123 DescEnd
= AdjustMemoryS (
1124 DescEnd
+ 1 - DescNumberOfBytes
,
1139 // If this is a grow down, adjust target to be the allocation base
1141 Target
-= NumberOfBytes
- 1;
1144 // If we didn't find a match, return 0
1146 if ((Target
& EFI_PAGE_MASK
) != 0) {
1154 Internal function. Finds a consecutive free page range below
1155 the requested address
1157 @param MaxAddress The address that the range must be below
1158 @param NoPages Number of pages needed
1159 @param NewType The type of memory the range is going to be
1161 @param Alignment Bits to align with
1162 @param NeedGuard Flag to indicate Guard page is needed or not
1164 @return The base address of the range, or 0 if the range was not found.
1169 IN UINT64 MaxAddress
,
1171 IN EFI_MEMORY_TYPE NewType
,
1173 IN BOOLEAN NeedGuard
1179 // Attempt to find free pages in the preferred bin based on the requested memory type
1181 if (((UINT32
)NewType
< EfiMaxMemoryType
) && (MaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
)) {
1182 Start
= CoreFindFreePagesI (
1183 mMemoryTypeStatistics
[NewType
].MaximumAddress
,
1184 mMemoryTypeStatistics
[NewType
].BaseAddress
,
1196 // Attempt to find free pages in the default allocation bin
1198 if (MaxAddress
>= mDefaultMaximumAddress
) {
1199 Start
= CoreFindFreePagesI (
1200 mDefaultMaximumAddress
,
1208 if (Start
< mDefaultBaseAddress
) {
1209 mDefaultBaseAddress
= Start
;
1217 // The allocation did not succeed in any of the prefered bins even after
1218 // promoting resources. Attempt to find free pages anywhere is the requested
1219 // address range. If this allocation fails, then there are not enough
1220 // resources anywhere to satisfy the request.
1222 Start
= CoreFindFreePagesI (
1235 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1237 if (!PromoteMemoryResource ()) {
1242 // If any memory resources were promoted, then re-attempt the allocation
1244 return FindFreePages (MaxAddress
, NoPages
, NewType
, Alignment
, NeedGuard
);
1248 Allocates pages from the memory map.
1250 @param Type The type of allocation to perform
1251 @param MemoryType The type of memory to turn the allocated pages
1253 @param NumberOfPages The number of pages to allocate
1254 @param Memory A pointer to receive the base allocated memory
1256 @param NeedGuard Flag to indicate Guard page is needed or not
1258 @return Status. On success, Memory is filled in with the base address allocated
1259 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1261 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1262 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1263 @retval EFI_SUCCESS Pages successfully allocated.
1268 CoreInternalAllocatePages (
1269 IN EFI_ALLOCATE_TYPE Type
,
1270 IN EFI_MEMORY_TYPE MemoryType
,
1271 IN UINTN NumberOfPages
,
1272 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
1273 IN BOOLEAN NeedGuard
1278 UINT64 NumberOfBytes
;
1282 EFI_MEMORY_TYPE CheckType
;
1284 if ((UINT32
)Type
>= MaxAllocateType
) {
1285 return EFI_INVALID_PARAMETER
;
1288 if (((MemoryType
>= EfiMaxMemoryType
) && (MemoryType
< MEMORY_TYPE_OEM_RESERVED_MIN
)) ||
1289 (MemoryType
== EfiConventionalMemory
) || (MemoryType
== EfiPersistentMemory
))
1291 return EFI_INVALID_PARAMETER
;
1294 if (Memory
== NULL
) {
1295 return EFI_INVALID_PARAMETER
;
1298 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1300 if ((MemoryType
== EfiACPIReclaimMemory
) ||
1301 (MemoryType
== EfiACPIMemoryNVS
) ||
1302 (MemoryType
== EfiRuntimeServicesCode
) ||
1303 (MemoryType
== EfiRuntimeServicesData
))
1305 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1308 if (Type
== AllocateAddress
) {
1309 if ((*Memory
& (Alignment
- 1)) != 0) {
1310 return EFI_NOT_FOUND
;
1314 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1315 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1318 // If this is for below a particular address, then
1323 // The max address is the max natively addressable address for the processor
1325 MaxAddress
= MAX_ALLOC_ADDRESS
;
1328 // Check for Type AllocateAddress,
1329 // if NumberOfPages is 0 or
1330 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
1331 // if (Start + NumberOfBytes) rolls over 0 or
1332 // if Start is above MAX_ALLOC_ADDRESS or
1333 // if End is above MAX_ALLOC_ADDRESS,
1334 // if Start..End overlaps any tracked MemoryTypeStatistics range
1335 // return EFI_NOT_FOUND.
1337 if (Type
== AllocateAddress
) {
1338 if ((NumberOfPages
== 0) ||
1339 (NumberOfPages
> RShiftU64 (MaxAddress
, EFI_PAGE_SHIFT
)))
1341 return EFI_NOT_FOUND
;
1344 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1345 End
= Start
+ NumberOfBytes
- 1;
1347 if ((Start
>= End
) ||
1348 (Start
> MaxAddress
) ||
1351 return EFI_NOT_FOUND
;
1355 // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of
1356 // AllocatePage request the exact physical address if it is not used. The existing code
1357 // will allow this request even in 'special' pages. The problem with this is that the
1358 // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
1362 for (CheckType
= (EFI_MEMORY_TYPE
)0; CheckType
< EfiMaxMemoryType
; CheckType
++) {
1363 if ((MemoryType
!= CheckType
) &&
1364 mMemoryTypeStatistics
[CheckType
].Special
&&
1365 (mMemoryTypeStatistics
[CheckType
].NumberOfPages
> 0))
1367 if ((Start
>= mMemoryTypeStatistics
[CheckType
].BaseAddress
) &&
1368 (Start
<= mMemoryTypeStatistics
[CheckType
].MaximumAddress
))
1370 return EFI_NOT_FOUND
;
1373 if ((End
>= mMemoryTypeStatistics
[CheckType
].BaseAddress
) &&
1374 (End
<= mMemoryTypeStatistics
[CheckType
].MaximumAddress
))
1376 return EFI_NOT_FOUND
;
1379 if ((Start
< mMemoryTypeStatistics
[CheckType
].BaseAddress
) &&
1380 (End
> mMemoryTypeStatistics
[CheckType
].MaximumAddress
))
1382 return EFI_NOT_FOUND
;
1388 if (Type
== AllocateMaxAddress
) {
1392 CoreAcquireMemoryLock ();
1395 // If not a specific address, then find an address to allocate
1397 if (Type
!= AllocateAddress
) {
1398 Start
= FindFreePages (
1406 Status
= EFI_OUT_OF_RESOURCES
;
1412 // Convert pages from FreeMemory to the requested type
1415 Status
= CoreConvertPagesWithGuard (Start
, NumberOfPages
, MemoryType
);
1417 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1421 CoreReleaseMemoryLock ();
1423 if (!EFI_ERROR (Status
)) {
1425 SetGuardForMemory (Start
, NumberOfPages
);
1435 Allocates pages from the memory map.
1437 @param Type The type of allocation to perform
1438 @param MemoryType The type of memory to turn the allocated pages
1440 @param NumberOfPages The number of pages to allocate
1441 @param Memory A pointer to receive the base allocated memory
1444 @return Status. On success, Memory is filled in with the base address allocated
1445 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1447 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1448 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1449 @retval EFI_SUCCESS Pages successfully allocated.
1455 IN EFI_ALLOCATE_TYPE Type
,
1456 IN EFI_MEMORY_TYPE MemoryType
,
1457 IN UINTN NumberOfPages
,
1458 OUT EFI_PHYSICAL_ADDRESS
*Memory
1464 NeedGuard
= IsPageTypeToGuard (MemoryType
, Type
) && !mOnGuarding
;
1465 Status
= CoreInternalAllocatePages (
1472 if (!EFI_ERROR (Status
)) {
1474 (EFI_PHYSICAL_ADDRESS
)(UINTN
)RETURN_ADDRESS (0),
1475 MemoryProfileActionAllocatePages
,
1477 EFI_PAGES_TO_SIZE (NumberOfPages
),
1478 (VOID
*)(UINTN
)*Memory
,
1481 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1482 ApplyMemoryProtectionPolicy (
1483 EfiConventionalMemory
,
1486 EFI_PAGES_TO_SIZE (NumberOfPages
)
1494 Frees previous allocated pages.
1496 @param Memory Base address of memory being freed
1497 @param NumberOfPages The number of pages to free
1498 @param MemoryType Pointer to memory type
1500 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1501 @retval EFI_INVALID_PARAMETER Address not aligned
1502 @return EFI_SUCCESS -Pages successfully freed.
1507 CoreInternalFreePages (
1508 IN EFI_PHYSICAL_ADDRESS Memory
,
1509 IN UINTN NumberOfPages
,
1510 OUT EFI_MEMORY_TYPE
*MemoryType OPTIONAL
1522 CoreAcquireMemoryLock ();
1525 // Find the entry that the covers the range
1529 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1530 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1531 if ((Entry
->Start
<= Memory
) && (Entry
->End
> Memory
)) {
1536 if (Link
== &gMemoryMap
) {
1537 Status
= EFI_NOT_FOUND
;
1541 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1543 ASSERT (Entry
!= NULL
);
1544 if ((Entry
->Type
== EfiACPIReclaimMemory
) ||
1545 (Entry
->Type
== EfiACPIMemoryNVS
) ||
1546 (Entry
->Type
== EfiRuntimeServicesCode
) ||
1547 (Entry
->Type
== EfiRuntimeServicesData
))
1549 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1552 if ((Memory
& (Alignment
- 1)) != 0) {
1553 Status
= EFI_INVALID_PARAMETER
;
1557 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1558 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1560 if (MemoryType
!= NULL
) {
1561 *MemoryType
= Entry
->Type
;
1564 IsGuarded
= IsPageTypeToGuard (Entry
->Type
, AllocateAnyPages
) &&
1565 IsMemoryGuarded (Memory
);
1567 Status
= CoreConvertPagesWithGuard (
1570 EfiConventionalMemory
1573 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1577 CoreReleaseMemoryLock ();
1582 Frees previous allocated pages.
1584 @param Memory Base address of memory being freed
1585 @param NumberOfPages The number of pages to free
1587 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1588 @retval EFI_INVALID_PARAMETER Address not aligned
1589 @return EFI_SUCCESS -Pages successfully freed.
1595 IN EFI_PHYSICAL_ADDRESS Memory
,
1596 IN UINTN NumberOfPages
1600 EFI_MEMORY_TYPE MemoryType
;
1602 Status
= CoreInternalFreePages (Memory
, NumberOfPages
, &MemoryType
);
1603 if (!EFI_ERROR (Status
)) {
1604 GuardFreedPagesChecked (Memory
, NumberOfPages
);
1606 (EFI_PHYSICAL_ADDRESS
)(UINTN
)RETURN_ADDRESS (0),
1607 MemoryProfileActionFreePages
,
1609 EFI_PAGES_TO_SIZE (NumberOfPages
),
1610 (VOID
*)(UINTN
)Memory
,
1613 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1614 ApplyMemoryProtectionPolicy (
1616 EfiConventionalMemory
,
1618 EFI_PAGES_TO_SIZE (NumberOfPages
)
1626 This function checks to see if the last memory map descriptor in a memory map
1627 can be merged with any of the other memory map descriptors in a memorymap.
1628 Memory descriptors may be merged if they are adjacent and have the same type
1631 @param MemoryMap A pointer to the start of the memory map.
1632 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1633 @param DescriptorSize The size, in bytes, of an individual
1634 EFI_MEMORY_DESCRIPTOR.
1636 @return A pointer to the next available descriptor in MemoryMap
1639 EFI_MEMORY_DESCRIPTOR
*
1640 MergeMemoryMapDescriptor (
1641 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1642 IN EFI_MEMORY_DESCRIPTOR
*MemoryMapDescriptor
,
1643 IN UINTN DescriptorSize
1647 // Traverse the array of descriptors in MemoryMap
1649 for ( ; MemoryMap
!= MemoryMapDescriptor
; MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
)) {
1651 // Check to see if the Type fields are identical.
1653 if (MemoryMap
->Type
!= MemoryMapDescriptor
->Type
) {
1658 // Check to see if the Attribute fields are identical.
1660 if (MemoryMap
->Attribute
!= MemoryMapDescriptor
->Attribute
) {
1665 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1667 if (MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1669 // Merge MemoryMapDescriptor into MemoryMap
1671 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1674 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1676 return MemoryMapDescriptor
;
1680 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1682 if (MemoryMap
->PhysicalStart
- EFI_PAGES_TO_SIZE ((UINTN
)MemoryMapDescriptor
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1684 // Merge MemoryMapDescriptor into MemoryMap
1686 MemoryMap
->PhysicalStart
= MemoryMapDescriptor
->PhysicalStart
;
1687 MemoryMap
->VirtualStart
= MemoryMapDescriptor
->VirtualStart
;
1688 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1691 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1693 return MemoryMapDescriptor
;
1698 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1700 // Return the slot immediately after MemoryMapDescriptor as the next available
1701 // slot in the MemoryMap array
1703 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor
, DescriptorSize
);
1707 This function returns a copy of the current memory map. The map is an array of
1708 memory descriptors, each of which describes a contiguous block of memory.
1710 @param MemoryMapSize A pointer to the size, in bytes, of the
1711 MemoryMap buffer. On input, this is the size of
1712 the buffer allocated by the caller. On output,
1713 it is the size of the buffer returned by the
1714 firmware if the buffer was large enough, or the
1715 size of the buffer needed to contain the map if
1716 the buffer was too small.
1717 @param MemoryMap A pointer to the buffer in which firmware places
1718 the current memory map.
1719 @param MapKey A pointer to the location in which firmware
1720 returns the key for the current memory map.
1721 @param DescriptorSize A pointer to the location in which firmware
1722 returns the size, in bytes, of an individual
1723 EFI_MEMORY_DESCRIPTOR.
1724 @param DescriptorVersion A pointer to the location in which firmware
1725 returns the version number associated with the
1726 EFI_MEMORY_DESCRIPTOR.
1728 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1730 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1731 buffer size needed to hold the memory map is
1732 returned in MemoryMapSize.
1733 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1739 IN OUT UINTN
*MemoryMapSize
,
1740 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1742 OUT UINTN
*DescriptorSize
,
1743 OUT UINT32
*DescriptorVersion
1749 UINTN NumberOfEntries
;
1752 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1753 EFI_GCD_MAP_ENTRY MergeGcdMapEntry
;
1754 EFI_MEMORY_TYPE Type
;
1755 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
1756 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1759 // Make sure the parameters are valid
1761 if (MemoryMapSize
== NULL
) {
1762 return EFI_INVALID_PARAMETER
;
1765 CoreAcquireGcdMemoryLock ();
1768 // Count the number of Reserved and runtime MMIO entries
1769 // And, count the number of Persistent entries.
1771 NumberOfEntries
= 0;
1772 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1773 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1774 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypePersistent
) ||
1775 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1776 ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1777 ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
)))
1783 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1786 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1787 // prevent people from having pointer math bugs in their code.
1788 // now you have to use *DescriptorSize to make things work.
1790 Size
+= sizeof (UINT64
) - (Size
% sizeof (UINT64
));
1792 if (DescriptorSize
!= NULL
) {
1793 *DescriptorSize
= Size
;
1796 if (DescriptorVersion
!= NULL
) {
1797 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1800 CoreAcquireMemoryLock ();
1803 // Compute the buffer size needed to fit the entire map
1805 BufferSize
= Size
* NumberOfEntries
;
1806 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1810 if (*MemoryMapSize
< BufferSize
) {
1811 Status
= EFI_BUFFER_TOO_SMALL
;
1815 if (MemoryMap
== NULL
) {
1816 Status
= EFI_INVALID_PARAMETER
;
1823 ZeroMem (MemoryMap
, BufferSize
);
1824 MemoryMapStart
= MemoryMap
;
1825 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1826 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1827 ASSERT (Entry
->VirtualStart
== 0);
1830 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1832 MemoryMap
->Type
= Entry
->Type
;
1833 MemoryMap
->PhysicalStart
= Entry
->Start
;
1834 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1835 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1837 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1838 // memory type bin and needs to be converted to the same memory type as the rest of the
1839 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1840 // improves the chances for a successful S4 resume in the presence of minor page allocation
1841 // differences across reboots.
1843 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1844 for (Type
= (EFI_MEMORY_TYPE
)0; Type
< EfiMaxMemoryType
; Type
++) {
1845 if (mMemoryTypeStatistics
[Type
].Special
&&
1846 (mMemoryTypeStatistics
[Type
].NumberOfPages
> 0) &&
1847 (Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
) &&
1848 (Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
))
1850 MemoryMap
->Type
= Type
;
1855 MemoryMap
->Attribute
= Entry
->Attribute
;
1856 if (MemoryMap
->Type
< EfiMaxMemoryType
) {
1857 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1858 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1863 // Check to see if the new Memory Map Descriptor can be merged with an
1864 // existing descriptor if they are adjacent and have the same attributes
1866 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1869 ZeroMem (&MergeGcdMapEntry
, sizeof (MergeGcdMapEntry
));
1871 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; ; Link
= Link
->ForwardLink
) {
1872 if (Link
!= &mGcdMemorySpaceMap
) {
1874 // Merge adjacent same type and attribute GCD memory range
1876 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1878 if ((MergeGcdMapEntry
.Capabilities
== GcdMapEntry
->Capabilities
) &&
1879 (MergeGcdMapEntry
.Attributes
== GcdMapEntry
->Attributes
) &&
1880 (MergeGcdMapEntry
.GcdMemoryType
== GcdMapEntry
->GcdMemoryType
) &&
1881 (MergeGcdMapEntry
.GcdIoType
== GcdMapEntry
->GcdIoType
))
1883 MergeGcdMapEntry
.EndAddress
= GcdMapEntry
->EndAddress
;
1888 if ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1889 ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1890 ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
)))
1893 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1894 // it will be recorded as page PhysicalStart and NumberOfPages.
1896 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1897 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1900 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1902 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1903 MemoryMap
->VirtualStart
= 0;
1904 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1905 MemoryMap
->Attribute
= (MergeGcdMapEntry
.Attributes
& ~EFI_MEMORY_PORT_IO
) |
1906 (MergeGcdMapEntry
.Capabilities
& (EFI_CACHE_ATTRIBUTE_MASK
| EFI_MEMORY_ATTRIBUTE_MASK
));
1908 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1909 MemoryMap
->Type
= EfiReservedMemoryType
;
1910 } else if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1911 if ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1912 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1914 MemoryMap
->Type
= EfiMemoryMappedIO
;
1919 // Check to see if the new Memory Map Descriptor can be merged with an
1920 // existing descriptor if they are adjacent and have the same attributes
1922 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1925 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypePersistent
) {
1927 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1928 // it will be recorded as page PhysicalStart and NumberOfPages.
1930 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1931 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1934 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1936 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1937 MemoryMap
->VirtualStart
= 0;
1938 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1939 MemoryMap
->Attribute
= MergeGcdMapEntry
.Attributes
| EFI_MEMORY_NV
|
1940 (MergeGcdMapEntry
.Capabilities
& (EFI_CACHE_ATTRIBUTE_MASK
| EFI_MEMORY_ATTRIBUTE_MASK
));
1941 MemoryMap
->Type
= EfiPersistentMemory
;
1944 // Check to see if the new Memory Map Descriptor can be merged with an
1945 // existing descriptor if they are adjacent and have the same attributes
1947 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1950 if (Link
== &mGcdMemorySpaceMap
) {
1952 // break loop when arrive at head.
1957 if (GcdMapEntry
!= NULL
) {
1959 // Copy new GCD map entry for the following GCD range merge
1961 CopyMem (&MergeGcdMapEntry
, GcdMapEntry
, sizeof (MergeGcdMapEntry
));
1966 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1968 BufferSize
= ((UINT8
*)MemoryMap
- (UINT8
*)MemoryMapStart
);
1971 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1972 // set attributes and change memory paging attribute accordingly.
1973 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1974 // value from Capabilities in GCD memory map. This might cause
1975 // boot problems. Clearing all page-access permission related
1976 // capabilities can workaround it. Following code is supposed to
1977 // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute
1978 // is clarified in UEFI spec and adopted by both EDK-II Core and
1979 // all supported OSs.
1981 MemoryMapEnd
= MemoryMap
;
1982 MemoryMap
= MemoryMapStart
;
1983 while (MemoryMap
< MemoryMapEnd
) {
1984 MemoryMap
->Attribute
&= ~(UINT64
)EFI_MEMORY_ACCESS_MASK
;
1985 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, Size
);
1988 MergeMemoryMap (MemoryMapStart
, &BufferSize
, Size
);
1989 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MemoryMapStart
+ BufferSize
);
1991 Status
= EFI_SUCCESS
;
1995 // Update the map key finally
1997 if (MapKey
!= NULL
) {
1998 *MapKey
= mMemoryMapKey
;
2001 CoreReleaseMemoryLock ();
2003 CoreReleaseGcdMemoryLock ();
2005 *MemoryMapSize
= BufferSize
;
2008 DumpGuardedMemoryBitmap ();
2015 Internal function. Used by the pool functions to allocate pages
2016 to back pool allocation requests.
2018 @param PoolType The type of memory for the new pool pages
2019 @param NumberOfPages No of pages to allocate
2020 @param Alignment Bits to align.
2021 @param NeedGuard Flag to indicate Guard page is needed or not
2023 @return The allocated memory, or NULL
2027 CoreAllocatePoolPages (
2028 IN EFI_MEMORY_TYPE PoolType
,
2029 IN UINTN NumberOfPages
,
2031 IN BOOLEAN NeedGuard
2037 // Find the pages to convert
2039 Start
= FindFreePages (
2048 // Convert it to boot services data
2051 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32
)NumberOfPages
));
2054 CoreConvertPagesWithGuard (Start
, NumberOfPages
, PoolType
);
2056 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
2060 return (VOID
*)(UINTN
)Start
;
2064 Internal function. Frees pool pages allocated via AllocatePoolPages ()
2066 @param Memory The base address to free
2067 @param NumberOfPages The number of pages to free
2072 IN EFI_PHYSICAL_ADDRESS Memory
,
2073 IN UINTN NumberOfPages
2076 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
2080 Make sure the memory map is following all the construction rules,
2081 it is the last time to check memory map error before exit boot services.
2083 @param MapKey Memory map key
2085 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2087 @retval EFI_SUCCESS Valid memory map.
2091 CoreTerminateMemoryMap (
2099 Status
= EFI_SUCCESS
;
2101 CoreAcquireMemoryLock ();
2103 if (MapKey
== mMemoryMapKey
) {
2105 // Make sure the memory map is following all the construction rules
2106 // This is the last chance we will be able to display any messages on
2107 // the console devices.
2110 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
2111 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
2112 if (Entry
->Type
< EfiMaxMemoryType
) {
2113 if (mMemoryTypeStatistics
[Entry
->Type
].Runtime
) {
2114 ASSERT (Entry
->Type
!= EfiACPIReclaimMemory
);
2115 ASSERT (Entry
->Type
!= EfiACPIMemoryNVS
);
2116 if ((Entry
->Start
& (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2117 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2118 Status
= EFI_INVALID_PARAMETER
;
2122 if (((Entry
->End
+ 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2123 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2124 Status
= EFI_INVALID_PARAMETER
;
2132 // The map key they gave us matches what we expect. Fall through and
2133 // return success. In an ideal world we would clear out all of
2134 // EfiBootServicesCode and EfiBootServicesData. However this function
2135 // is not the last one called by ExitBootServices(), so we have to
2136 // preserve the memory contents.
2139 Status
= EFI_INVALID_PARAMETER
;
2143 CoreReleaseMemoryLock ();