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
);
1420 if (EFI_ERROR (Status
)) {
1422 // If requested memory region is unavailable it may be untested memory
1423 // Attempt to promote memory resources, then re-attempt the allocation
1425 if (PromoteMemoryResource ()) {
1427 Status
= CoreConvertPagesWithGuard (Start
, NumberOfPages
, MemoryType
);
1429 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1435 CoreReleaseMemoryLock ();
1437 if (!EFI_ERROR (Status
)) {
1439 SetGuardForMemory (Start
, NumberOfPages
);
1449 Allocates pages from the memory map.
1451 @param Type The type of allocation to perform
1452 @param MemoryType The type of memory to turn the allocated pages
1454 @param NumberOfPages The number of pages to allocate
1455 @param Memory A pointer to receive the base allocated memory
1458 @return Status. On success, Memory is filled in with the base address allocated
1459 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1461 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1462 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1463 @retval EFI_SUCCESS Pages successfully allocated.
1469 IN EFI_ALLOCATE_TYPE Type
,
1470 IN EFI_MEMORY_TYPE MemoryType
,
1471 IN UINTN NumberOfPages
,
1472 OUT EFI_PHYSICAL_ADDRESS
*Memory
1478 NeedGuard
= IsPageTypeToGuard (MemoryType
, Type
) && !mOnGuarding
;
1479 Status
= CoreInternalAllocatePages (
1486 if (!EFI_ERROR (Status
)) {
1488 (EFI_PHYSICAL_ADDRESS
)(UINTN
)RETURN_ADDRESS (0),
1489 MemoryProfileActionAllocatePages
,
1491 EFI_PAGES_TO_SIZE (NumberOfPages
),
1492 (VOID
*)(UINTN
)*Memory
,
1495 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1496 ApplyMemoryProtectionPolicy (
1497 EfiConventionalMemory
,
1500 EFI_PAGES_TO_SIZE (NumberOfPages
)
1508 Frees previous allocated pages.
1510 @param Memory Base address of memory being freed
1511 @param NumberOfPages The number of pages to free
1512 @param MemoryType Pointer to memory type
1514 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1515 @retval EFI_INVALID_PARAMETER Address not aligned
1516 @return EFI_SUCCESS -Pages successfully freed.
1521 CoreInternalFreePages (
1522 IN EFI_PHYSICAL_ADDRESS Memory
,
1523 IN UINTN NumberOfPages
,
1524 OUT EFI_MEMORY_TYPE
*MemoryType OPTIONAL
1536 CoreAcquireMemoryLock ();
1539 // Find the entry that the covers the range
1543 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1544 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1545 if ((Entry
->Start
<= Memory
) && (Entry
->End
> Memory
)) {
1550 if (Link
== &gMemoryMap
) {
1551 Status
= EFI_NOT_FOUND
;
1555 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1557 ASSERT (Entry
!= NULL
);
1558 if ((Entry
->Type
== EfiACPIReclaimMemory
) ||
1559 (Entry
->Type
== EfiACPIMemoryNVS
) ||
1560 (Entry
->Type
== EfiRuntimeServicesCode
) ||
1561 (Entry
->Type
== EfiRuntimeServicesData
))
1563 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1566 if ((Memory
& (Alignment
- 1)) != 0) {
1567 Status
= EFI_INVALID_PARAMETER
;
1571 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1572 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1574 if (MemoryType
!= NULL
) {
1575 *MemoryType
= Entry
->Type
;
1578 IsGuarded
= IsPageTypeToGuard (Entry
->Type
, AllocateAnyPages
) &&
1579 IsMemoryGuarded (Memory
);
1581 Status
= CoreConvertPagesWithGuard (
1584 EfiConventionalMemory
1587 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1591 CoreReleaseMemoryLock ();
1596 Frees previous allocated pages.
1598 @param Memory Base address of memory being freed
1599 @param NumberOfPages The number of pages to free
1601 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1602 @retval EFI_INVALID_PARAMETER Address not aligned
1603 @return EFI_SUCCESS -Pages successfully freed.
1609 IN EFI_PHYSICAL_ADDRESS Memory
,
1610 IN UINTN NumberOfPages
1614 EFI_MEMORY_TYPE MemoryType
;
1616 Status
= CoreInternalFreePages (Memory
, NumberOfPages
, &MemoryType
);
1617 if (!EFI_ERROR (Status
)) {
1618 GuardFreedPagesChecked (Memory
, NumberOfPages
);
1620 (EFI_PHYSICAL_ADDRESS
)(UINTN
)RETURN_ADDRESS (0),
1621 MemoryProfileActionFreePages
,
1623 EFI_PAGES_TO_SIZE (NumberOfPages
),
1624 (VOID
*)(UINTN
)Memory
,
1627 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1628 ApplyMemoryProtectionPolicy (
1630 EfiConventionalMemory
,
1632 EFI_PAGES_TO_SIZE (NumberOfPages
)
1640 This function checks to see if the last memory map descriptor in a memory map
1641 can be merged with any of the other memory map descriptors in a memorymap.
1642 Memory descriptors may be merged if they are adjacent and have the same type
1645 @param MemoryMap A pointer to the start of the memory map.
1646 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1647 @param DescriptorSize The size, in bytes, of an individual
1648 EFI_MEMORY_DESCRIPTOR.
1650 @return A pointer to the next available descriptor in MemoryMap
1653 EFI_MEMORY_DESCRIPTOR
*
1654 MergeMemoryMapDescriptor (
1655 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1656 IN EFI_MEMORY_DESCRIPTOR
*MemoryMapDescriptor
,
1657 IN UINTN DescriptorSize
1661 // Traverse the array of descriptors in MemoryMap
1663 for ( ; MemoryMap
!= MemoryMapDescriptor
; MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
)) {
1665 // Check to see if the Type fields are identical.
1667 if (MemoryMap
->Type
!= MemoryMapDescriptor
->Type
) {
1672 // Check to see if the Attribute fields are identical.
1674 if (MemoryMap
->Attribute
!= MemoryMapDescriptor
->Attribute
) {
1679 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1681 if (MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1683 // Merge MemoryMapDescriptor into MemoryMap
1685 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1688 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1690 return MemoryMapDescriptor
;
1694 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1696 if (MemoryMap
->PhysicalStart
- EFI_PAGES_TO_SIZE ((UINTN
)MemoryMapDescriptor
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1698 // Merge MemoryMapDescriptor into MemoryMap
1700 MemoryMap
->PhysicalStart
= MemoryMapDescriptor
->PhysicalStart
;
1701 MemoryMap
->VirtualStart
= MemoryMapDescriptor
->VirtualStart
;
1702 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1705 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1707 return MemoryMapDescriptor
;
1712 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1714 // Return the slot immediately after MemoryMapDescriptor as the next available
1715 // slot in the MemoryMap array
1717 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor
, DescriptorSize
);
1721 This function returns a copy of the current memory map. The map is an array of
1722 memory descriptors, each of which describes a contiguous block of memory.
1724 @param MemoryMapSize A pointer to the size, in bytes, of the
1725 MemoryMap buffer. On input, this is the size of
1726 the buffer allocated by the caller. On output,
1727 it is the size of the buffer returned by the
1728 firmware if the buffer was large enough, or the
1729 size of the buffer needed to contain the map if
1730 the buffer was too small.
1731 @param MemoryMap A pointer to the buffer in which firmware places
1732 the current memory map.
1733 @param MapKey A pointer to the location in which firmware
1734 returns the key for the current memory map.
1735 @param DescriptorSize A pointer to the location in which firmware
1736 returns the size, in bytes, of an individual
1737 EFI_MEMORY_DESCRIPTOR.
1738 @param DescriptorVersion A pointer to the location in which firmware
1739 returns the version number associated with the
1740 EFI_MEMORY_DESCRIPTOR.
1742 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1744 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1745 buffer size needed to hold the memory map is
1746 returned in MemoryMapSize.
1747 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1753 IN OUT UINTN
*MemoryMapSize
,
1754 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1756 OUT UINTN
*DescriptorSize
,
1757 OUT UINT32
*DescriptorVersion
1763 UINTN NumberOfEntries
;
1766 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1767 EFI_GCD_MAP_ENTRY MergeGcdMapEntry
;
1768 EFI_MEMORY_TYPE Type
;
1769 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
1770 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1773 // Make sure the parameters are valid
1775 if (MemoryMapSize
== NULL
) {
1776 return EFI_INVALID_PARAMETER
;
1779 CoreAcquireGcdMemoryLock ();
1782 // Count the number of Reserved and runtime MMIO entries
1783 // And, count the number of Persistent entries.
1785 NumberOfEntries
= 0;
1786 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1787 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1788 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypePersistent
) ||
1789 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1790 ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1791 ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
)))
1797 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1800 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1801 // prevent people from having pointer math bugs in their code.
1802 // now you have to use *DescriptorSize to make things work.
1804 Size
+= sizeof (UINT64
) - (Size
% sizeof (UINT64
));
1806 if (DescriptorSize
!= NULL
) {
1807 *DescriptorSize
= Size
;
1810 if (DescriptorVersion
!= NULL
) {
1811 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1814 CoreAcquireMemoryLock ();
1817 // Compute the buffer size needed to fit the entire map
1819 BufferSize
= Size
* NumberOfEntries
;
1820 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1824 if (*MemoryMapSize
< BufferSize
) {
1825 Status
= EFI_BUFFER_TOO_SMALL
;
1829 if (MemoryMap
== NULL
) {
1830 Status
= EFI_INVALID_PARAMETER
;
1837 ZeroMem (MemoryMap
, BufferSize
);
1838 MemoryMapStart
= MemoryMap
;
1839 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1840 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1841 ASSERT (Entry
->VirtualStart
== 0);
1844 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1846 MemoryMap
->Type
= Entry
->Type
;
1847 MemoryMap
->PhysicalStart
= Entry
->Start
;
1848 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1849 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1851 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1852 // memory type bin and needs to be converted to the same memory type as the rest of the
1853 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1854 // improves the chances for a successful S4 resume in the presence of minor page allocation
1855 // differences across reboots.
1857 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1858 for (Type
= (EFI_MEMORY_TYPE
)0; Type
< EfiMaxMemoryType
; Type
++) {
1859 if (mMemoryTypeStatistics
[Type
].Special
&&
1860 (mMemoryTypeStatistics
[Type
].NumberOfPages
> 0) &&
1861 (Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
) &&
1862 (Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
))
1864 MemoryMap
->Type
= Type
;
1869 MemoryMap
->Attribute
= Entry
->Attribute
;
1870 if (MemoryMap
->Type
< EfiMaxMemoryType
) {
1871 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1872 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1877 // Check to see if the new Memory Map Descriptor can be merged with an
1878 // existing descriptor if they are adjacent and have the same attributes
1880 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1883 ZeroMem (&MergeGcdMapEntry
, sizeof (MergeGcdMapEntry
));
1885 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; ; Link
= Link
->ForwardLink
) {
1886 if (Link
!= &mGcdMemorySpaceMap
) {
1888 // Merge adjacent same type and attribute GCD memory range
1890 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1892 if ((MergeGcdMapEntry
.Capabilities
== GcdMapEntry
->Capabilities
) &&
1893 (MergeGcdMapEntry
.Attributes
== GcdMapEntry
->Attributes
) &&
1894 (MergeGcdMapEntry
.GcdMemoryType
== GcdMapEntry
->GcdMemoryType
) &&
1895 (MergeGcdMapEntry
.GcdIoType
== GcdMapEntry
->GcdIoType
))
1897 MergeGcdMapEntry
.EndAddress
= GcdMapEntry
->EndAddress
;
1902 if ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1903 ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1904 ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
)))
1907 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1908 // it will be recorded as page PhysicalStart and NumberOfPages.
1910 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1911 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1914 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1916 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1917 MemoryMap
->VirtualStart
= 0;
1918 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1919 MemoryMap
->Attribute
= (MergeGcdMapEntry
.Attributes
& ~EFI_MEMORY_PORT_IO
) |
1920 (MergeGcdMapEntry
.Capabilities
& (EFI_CACHE_ATTRIBUTE_MASK
| EFI_MEMORY_ATTRIBUTE_MASK
));
1922 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1923 MemoryMap
->Type
= EfiReservedMemoryType
;
1924 } else if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1925 if ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1926 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1928 MemoryMap
->Type
= EfiMemoryMappedIO
;
1933 // Check to see if the new Memory Map Descriptor can be merged with an
1934 // existing descriptor if they are adjacent and have the same attributes
1936 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1939 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypePersistent
) {
1941 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1942 // it will be recorded as page PhysicalStart and NumberOfPages.
1944 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1945 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1948 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1950 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1951 MemoryMap
->VirtualStart
= 0;
1952 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1953 MemoryMap
->Attribute
= MergeGcdMapEntry
.Attributes
| EFI_MEMORY_NV
|
1954 (MergeGcdMapEntry
.Capabilities
& (EFI_CACHE_ATTRIBUTE_MASK
| EFI_MEMORY_ATTRIBUTE_MASK
));
1955 MemoryMap
->Type
= EfiPersistentMemory
;
1958 // Check to see if the new Memory Map Descriptor can be merged with an
1959 // existing descriptor if they are adjacent and have the same attributes
1961 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1964 if (Link
== &mGcdMemorySpaceMap
) {
1966 // break loop when arrive at head.
1971 if (GcdMapEntry
!= NULL
) {
1973 // Copy new GCD map entry for the following GCD range merge
1975 CopyMem (&MergeGcdMapEntry
, GcdMapEntry
, sizeof (MergeGcdMapEntry
));
1980 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1982 BufferSize
= ((UINT8
*)MemoryMap
- (UINT8
*)MemoryMapStart
);
1985 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1986 // set attributes and change memory paging attribute accordingly.
1987 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1988 // value from Capabilities in GCD memory map. This might cause
1989 // boot problems. Clearing all page-access permission related
1990 // capabilities can workaround it. Following code is supposed to
1991 // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute
1992 // is clarified in UEFI spec and adopted by both EDK-II Core and
1993 // all supported OSs.
1995 MemoryMapEnd
= MemoryMap
;
1996 MemoryMap
= MemoryMapStart
;
1997 while (MemoryMap
< MemoryMapEnd
) {
1998 MemoryMap
->Attribute
&= ~(UINT64
)EFI_MEMORY_ACCESS_MASK
;
1999 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, Size
);
2002 MergeMemoryMap (MemoryMapStart
, &BufferSize
, Size
);
2003 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MemoryMapStart
+ BufferSize
);
2005 Status
= EFI_SUCCESS
;
2009 // Update the map key finally
2011 if (MapKey
!= NULL
) {
2012 *MapKey
= mMemoryMapKey
;
2015 CoreReleaseMemoryLock ();
2017 CoreReleaseGcdMemoryLock ();
2019 *MemoryMapSize
= BufferSize
;
2022 DumpGuardedMemoryBitmap ();
2029 Internal function. Used by the pool functions to allocate pages
2030 to back pool allocation requests.
2032 @param PoolType The type of memory for the new pool pages
2033 @param NumberOfPages No of pages to allocate
2034 @param Alignment Bits to align.
2035 @param NeedGuard Flag to indicate Guard page is needed or not
2037 @return The allocated memory, or NULL
2041 CoreAllocatePoolPages (
2042 IN EFI_MEMORY_TYPE PoolType
,
2043 IN UINTN NumberOfPages
,
2045 IN BOOLEAN NeedGuard
2051 // Find the pages to convert
2053 Start
= FindFreePages (
2062 // Convert it to boot services data
2065 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32
)NumberOfPages
));
2068 CoreConvertPagesWithGuard (Start
, NumberOfPages
, PoolType
);
2070 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
2074 return (VOID
*)(UINTN
)Start
;
2078 Internal function. Frees pool pages allocated via AllocatePoolPages ()
2080 @param Memory The base address to free
2081 @param NumberOfPages The number of pages to free
2086 IN EFI_PHYSICAL_ADDRESS Memory
,
2087 IN UINTN NumberOfPages
2090 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
2094 Make sure the memory map is following all the construction rules,
2095 it is the last time to check memory map error before exit boot services.
2097 @param MapKey Memory map key
2099 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2101 @retval EFI_SUCCESS Valid memory map.
2105 CoreTerminateMemoryMap (
2113 Status
= EFI_SUCCESS
;
2115 CoreAcquireMemoryLock ();
2117 if (MapKey
== mMemoryMapKey
) {
2119 // Make sure the memory map is following all the construction rules
2120 // This is the last chance we will be able to display any messages on
2121 // the console devices.
2124 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
2125 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
2126 if (Entry
->Type
< EfiMaxMemoryType
) {
2127 if (mMemoryTypeStatistics
[Entry
->Type
].Runtime
) {
2128 ASSERT (Entry
->Type
!= EfiACPIReclaimMemory
);
2129 ASSERT (Entry
->Type
!= EfiACPIMemoryNVS
);
2130 if ((Entry
->Start
& (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2131 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2132 Status
= EFI_INVALID_PARAMETER
;
2136 if (((Entry
->End
+ 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2137 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2138 Status
= EFI_INVALID_PARAMETER
;
2146 // The map key they gave us matches what we expect. Fall through and
2147 // return success. In an ideal world we would clear out all of
2148 // EfiBootServicesCode and EfiBootServicesData. However this function
2149 // is not the last one called by ExitBootServices(), so we have to
2150 // preserve the memory contents.
2153 Status
= EFI_INVALID_PARAMETER
;
2157 CoreReleaseMemoryLock ();