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
);
110 Exit critical section by releasing lock on gMemoryLock.
114 CoreReleaseMemoryLock (
118 CoreReleaseLock (&gMemoryLock
);
125 Internal function. Removes a descriptor entry.
127 @param Entry The entry to remove
131 RemoveMemoryMapEntry (
132 IN OUT MEMORY_MAP
*Entry
135 RemoveEntryList (&Entry
->Link
);
136 Entry
->Link
.ForwardLink
= NULL
;
138 if (Entry
->FromPages
) {
140 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
142 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
147 Internal function. Adds a ranges to the memory map.
148 The range must not already exist in the map.
150 @param Type The type of memory range to add
151 @param Start The starting address in the memory range Must be
153 @param End The last address in the range Must be the last
155 @param Attribute The attributes of the memory range to add
160 IN EFI_MEMORY_TYPE Type
,
161 IN EFI_PHYSICAL_ADDRESS Start
,
162 IN EFI_PHYSICAL_ADDRESS End
,
169 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
170 ASSERT (End
> Start
) ;
172 ASSERT_LOCKED (&gMemoryLock
);
174 DEBUG ((DEBUG_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
177 // If memory of type EfiConventionalMemory is being added that includes the page
178 // starting at address 0, then zero the page starting at address 0. This has
179 // two benifits. It helps find NULL pointer bugs and it also maximizes
180 // compatibility with operating systems that may evaluate memory in this page
181 // for legacy data structures. If memory of any other type is added starting
182 // at address 0, then do not zero the page at address 0 because the page is being
183 // used for other purposes.
185 if (Type
== EfiConventionalMemory
&& Start
== 0 && (End
>= EFI_PAGE_SIZE
- 1)) {
186 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask
) & BIT0
) == 0) {
187 SetMem ((VOID
*)(UINTN
)Start
, EFI_PAGE_SIZE
, 0);
192 // Memory map being altered so updated key
197 // UEFI 2.0 added an event group for notificaiton on memory map changes.
198 // So we need to signal this Event Group every time the memory map changes.
199 // If we are in EFI 1.10 compatability mode no event groups will be
200 // found and nothing will happen we we call this function. These events
201 // will get signaled but since a lock is held around the call to this
202 // function the notificaiton events will only be called after this function
203 // returns and the lock is released.
205 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
208 // Look for adjoining memory descriptor
211 // Two memory descriptors can only be merged if they have the same Type
212 // and the same Attribute
215 Link
= gMemoryMap
.ForwardLink
;
216 while (Link
!= &gMemoryMap
) {
217 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
218 Link
= Link
->ForwardLink
;
220 if (Entry
->Type
!= Type
) {
224 if (Entry
->Attribute
!= Attribute
) {
228 if (Entry
->End
+ 1 == Start
) {
230 Start
= Entry
->Start
;
231 RemoveMemoryMapEntry (Entry
);
233 } else if (Entry
->Start
== End
+ 1) {
236 RemoveMemoryMapEntry (Entry
);
244 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
245 mMapStack
[mMapDepth
].FromPages
= FALSE
;
246 mMapStack
[mMapDepth
].Type
= Type
;
247 mMapStack
[mMapDepth
].Start
= Start
;
248 mMapStack
[mMapDepth
].End
= End
;
249 mMapStack
[mMapDepth
].VirtualStart
= 0;
250 mMapStack
[mMapDepth
].Attribute
= Attribute
;
251 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
254 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
260 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
261 If the list is emtry, then allocate a new page to refuel the list.
262 Please Note this algorithm to allocate the memory map descriptor has a property
263 that the memory allocated for memory entries always grows, and will never really be freed
264 For example, if the current boot uses 2000 memory map entries at the maximum point, but
265 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
266 memory map entries is still allocated from EfiBootServicesMemory.
269 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
273 AllocateMemoryMapEntry (
277 MEMORY_MAP
* FreeDescriptorEntries
;
281 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
283 // The list is empty, to allocate one page to refuel the list
285 FreeDescriptorEntries
= CoreAllocatePoolPages (
287 EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY
),
288 DEFAULT_PAGE_ALLOCATION_GRANULARITY
,
291 if (FreeDescriptorEntries
!= NULL
) {
293 // Enque the free memmory map entries into the list
295 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION_GRANULARITY
/ sizeof(MEMORY_MAP
); Index
++) {
296 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
297 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
304 // dequeue the first descriptor from the list
306 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
307 RemoveEntryList (&Entry
->Link
);
314 Internal function. Moves any memory descriptors that are on the
315 temporary descriptor stack to heap.
319 CoreFreeMemoryMapStack (
327 ASSERT_LOCKED (&gMemoryLock
);
330 // If already freeing the map stack, then return
332 if (mFreeMapStack
!= 0) {
337 // Move the temporary memory descriptor stack into pool
341 while (mMapDepth
!= 0) {
343 // Deque an memory map entry from mFreeMemoryMapEntryList
345 Entry
= AllocateMemoryMapEntry ();
350 // Update to proper entry
354 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
357 // Move this entry to general memory
359 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
360 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
362 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
363 Entry
->FromPages
= TRUE
;
366 // Find insertion location
368 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
369 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
370 if (Entry2
->FromPages
&& Entry2
->Start
> Entry
->Start
) {
375 InsertTailList (Link2
, &Entry
->Link
);
379 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
380 // so here no need to move it to memory.
382 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
390 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
394 PromoteMemoryResource (
399 EFI_GCD_MAP_ENTRY
*Entry
;
401 EFI_PHYSICAL_ADDRESS StartAddress
;
402 EFI_PHYSICAL_ADDRESS EndAddress
;
403 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
405 DEBUG ((DEBUG_PAGE
, "Promote the memory resource\n"));
407 CoreAcquireGcdMemoryLock ();
410 Link
= mGcdMemorySpaceMap
.ForwardLink
;
411 while (Link
!= &mGcdMemorySpaceMap
) {
413 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
415 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
416 Entry
->EndAddress
< MAX_ALLOC_ADDRESS
&&
417 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
418 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
420 // Update the GCD map
422 if ((Entry
->Capabilities
& EFI_MEMORY_MORE_RELIABLE
) == EFI_MEMORY_MORE_RELIABLE
) {
423 Entry
->GcdMemoryType
= EfiGcdMemoryTypeMoreReliable
;
425 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
427 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
428 Entry
->ImageHandle
= gDxeCoreImageHandle
;
429 Entry
->DeviceHandle
= NULL
;
432 // Add to allocable system memory resource
436 EfiConventionalMemory
,
439 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
441 CoreFreeMemoryMapStack ();
446 Link
= Link
->ForwardLink
;
449 CoreReleaseGcdMemoryLock ();
453 // If freed-memory guard is enabled, we could promote pages from
454 // guarded free pages.
456 Promoted
= PromoteGuardedFreePages (&StartAddress
, &EndAddress
);
458 CoreGetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
460 EfiConventionalMemory
,
463 Descriptor
.Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
|
464 EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
472 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
473 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
474 size of boot time and runtime code.
478 CoreLoadingFixedAddressHook (
482 UINT32 RuntimeCodePageNumber
;
483 UINT32 BootTimeCodePageNumber
;
484 EFI_PHYSICAL_ADDRESS RuntimeCodeBase
;
485 EFI_PHYSICAL_ADDRESS BootTimeCodeBase
;
489 // Make sure these 2 areas are not initialzied.
491 if (!gLoadFixedAddressCodeMemoryReady
) {
492 RuntimeCodePageNumber
= PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber
);
493 BootTimeCodePageNumber
= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber
);
494 RuntimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(gLoadModuleAtFixAddressConfigurationTable
.DxeCodeTopAddress
- EFI_PAGES_TO_SIZE (RuntimeCodePageNumber
));
495 BootTimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(RuntimeCodeBase
- EFI_PAGES_TO_SIZE (BootTimeCodePageNumber
));
497 // Try to allocate runtime memory.
499 Status
= CoreAllocatePages (
501 EfiRuntimeServicesCode
,
502 RuntimeCodePageNumber
,
505 if (EFI_ERROR(Status
)) {
507 // Runtime memory allocation failed
512 // Try to allocate boot memory.
514 Status
= CoreAllocatePages (
517 BootTimeCodePageNumber
,
520 if (EFI_ERROR(Status
)) {
522 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
523 // new memory range is installed.
527 RuntimeCodePageNumber
531 gLoadFixedAddressCodeMemoryReady
= TRUE
;
537 Called to initialize the memory map and add descriptors to
538 the current descriptor list.
539 The first descriptor that is added must be general usable
540 memory as the addition allocates heap.
542 @param Type The type of memory to add
543 @param Start The starting address in the memory range Must be
545 @param NumberOfPages The number of pages in the range
546 @param Attribute Attributes of the memory to add
548 @return None. The range is added to the memory map
552 CoreAddMemoryDescriptor (
553 IN EFI_MEMORY_TYPE Type
,
554 IN EFI_PHYSICAL_ADDRESS Start
,
555 IN UINT64 NumberOfPages
,
559 EFI_PHYSICAL_ADDRESS End
;
564 if ((Start
& EFI_PAGE_MASK
) != 0) {
568 if (Type
>= EfiMaxMemoryType
&& Type
< MEMORY_TYPE_OEM_RESERVED_MIN
) {
571 CoreAcquireMemoryLock ();
572 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
573 CoreAddRange (Type
, Start
, End
, Attribute
);
574 CoreFreeMemoryMapStack ();
575 CoreReleaseMemoryLock ();
577 ApplyMemoryProtectionPolicy (EfiMaxMemoryType
, Type
, Start
,
578 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
) {
596 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
598 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
600 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
602 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
603 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
;
644 // Compute the address at the top of the current statistics
646 mMemoryTypeStatistics
[Type
].MaximumAddress
=
647 mMemoryTypeStatistics
[Type
].BaseAddress
+
648 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
651 // If the current base address is the lowest address so far, then update the default
654 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
655 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
661 // There was enough system memory for all the the memory types were allocated. So,
662 // those memory areas can be freed for future allocations, and all future memory
663 // allocations can occur within their respective bins
665 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
667 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
669 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
670 if ((UINT32
)Type
> EfiMaxMemoryType
) {
673 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
675 mMemoryTypeStatistics
[Type
].BaseAddress
,
676 gMemoryTypeInformation
[Index
].NumberOfPages
678 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
679 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
684 // If the number of pages reserved for a memory type is 0, then all allocations for that type
685 // should be in the default range.
687 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
688 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
689 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
690 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
693 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
694 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== MAX_ALLOC_ADDRESS
) {
695 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
699 mMemoryTypeInformationInitialized
= TRUE
;
704 Internal function. Converts a memory range to the specified type or attributes.
705 The range must exist in the memory map. Either ChangingType or
706 ChangingAttributes must be set, but not both.
708 @param Start The first address of the range Must be page
710 @param NumberOfPages The number of pages to convert
711 @param ChangingType Boolean indicating that type value should be changed
712 @param NewType The new type for the memory range
713 @param ChangingAttributes Boolean indicating that attributes value should be changed
714 @param NewAttributes The new attributes for the memory range
716 @retval EFI_INVALID_PARAMETER Invalid parameter
717 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
718 range or convertion not allowed.
719 @retval EFI_SUCCESS Successfully converts the memory range to the
726 IN UINT64 NumberOfPages
,
727 IN BOOLEAN ChangingType
,
728 IN EFI_MEMORY_TYPE NewType
,
729 IN BOOLEAN ChangingAttributes
,
730 IN UINT64 NewAttributes
734 UINT64 NumberOfBytes
;
738 EFI_MEMORY_TYPE MemType
;
743 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
744 End
= Start
+ NumberOfBytes
- 1;
746 ASSERT (NumberOfPages
);
747 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
748 ASSERT (End
> Start
) ;
749 ASSERT_LOCKED (&gMemoryLock
);
750 ASSERT ( (ChangingType
== FALSE
) || (ChangingAttributes
== FALSE
) );
752 if (NumberOfPages
== 0 || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
>= End
)) {
753 return EFI_INVALID_PARAMETER
;
757 // Convert the entire range
760 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
;
790 // Convert range to the end, or to the end of the descriptor
791 // if that's all we've got
795 ASSERT (Entry
!= NULL
);
796 if (Entry
->End
< End
) {
797 RangeEnd
= Entry
->End
;
801 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to type %d\n", Start
, RangeEnd
, NewType
));
803 if (ChangingAttributes
) {
804 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to attr %lx\n", Start
, RangeEnd
, NewAttributes
));
809 // Debug code - verify conversion is allowed
811 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
812 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: Incompatible memory types, "));
813 if (Entry
->Type
== EfiConventionalMemory
) {
814 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to free have been freed\n"));
816 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to allocate have been allocated\n"));
818 return EFI_NOT_FOUND
;
822 // Update counters for the number of pages allocated to each memory type
824 if ((UINT32
)Entry
->Type
< EfiMaxMemoryType
) {
825 if ((Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) ||
826 (Start
>= mDefaultBaseAddress
&& Start
<= mDefaultMaximumAddress
) ) {
827 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
828 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
830 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
835 if ((UINT32
)NewType
< EfiMaxMemoryType
) {
836 if ((Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) ||
837 (Start
>= mDefaultBaseAddress
&& Start
<= mDefaultMaximumAddress
) ) {
838 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
839 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
> gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
840 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
847 // Pull range out of descriptor
849 if (Entry
->Start
== Start
) {
854 Entry
->Start
= RangeEnd
+ 1;
856 } else if (Entry
->End
== RangeEnd
) {
861 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
) {
920 CoreAddRange (MemType
, Start
, RangeEnd
, Attribute
);
923 if (ChangingType
&& (MemType
== EfiConventionalMemory
)) {
925 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
926 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
927 // that the page starting at address 0 is always filled with zeros.
930 if (RangeEnd
> EFI_PAGE_SIZE
) {
931 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
) EFI_PAGE_SIZE
, (UINTN
) (RangeEnd
- EFI_PAGE_SIZE
+ 1));
934 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
) Start
, (UINTN
) (RangeEnd
- Start
+ 1));
939 // Move any map descriptor stack to general pool
941 CoreFreeMemoryMapStack ();
944 // Bump the starting address, and convert the next range
946 Start
= RangeEnd
+ 1;
950 // 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);
985 Internal function. Converts a memory range to use new attributes.
987 @param Start The first address of the range Must be page
989 @param NumberOfPages The number of pages to convert
990 @param NewAttributes The new attributes value for the range.
994 CoreUpdateMemoryAttributes (
995 IN EFI_PHYSICAL_ADDRESS Start
,
996 IN UINT64 NumberOfPages
,
997 IN UINT64 NewAttributes
1000 CoreAcquireMemoryLock ();
1003 // Update the attributes to the new value
1005 CoreConvertPagesEx(Start
, NumberOfPages
, FALSE
, (EFI_MEMORY_TYPE
)0, TRUE
, NewAttributes
);
1007 CoreReleaseMemoryLock ();
1012 Internal function. Finds a consecutive free page range below
1013 the requested address.
1015 @param MaxAddress The address that the range must be below
1016 @param MinAddress The address that the range must be above
1017 @param NumberOfPages Number of pages needed
1018 @param NewType The type of memory the range is going to be
1020 @param Alignment Bits to align with
1021 @param NeedGuard Flag to indicate Guard page is needed or not
1023 @return The base address of the range, or 0 if the range was not found
1027 CoreFindFreePagesI (
1028 IN UINT64 MaxAddress
,
1029 IN UINT64 MinAddress
,
1030 IN UINT64 NumberOfPages
,
1031 IN EFI_MEMORY_TYPE NewType
,
1033 IN BOOLEAN NeedGuard
1036 UINT64 NumberOfBytes
;
1040 UINT64 DescNumberOfBytes
;
1044 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
1048 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
1051 // If MaxAddress is not aligned to the end of a page
1055 // Change MaxAddress to be 1 page lower
1057 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
1060 // Set MaxAddress to a page boundary
1062 MaxAddress
&= ~(UINT64
)EFI_PAGE_MASK
;
1065 // Set MaxAddress to end of the page
1067 MaxAddress
|= EFI_PAGE_MASK
;
1070 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1073 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1074 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1077 // If it's not a free entry, don't bother with it
1079 if (Entry
->Type
!= EfiConventionalMemory
) {
1083 DescStart
= Entry
->Start
;
1084 DescEnd
= Entry
->End
;
1087 // If desc is past max allowed address or below min allowed address, skip it
1089 if ((DescStart
>= MaxAddress
) || (DescEnd
< MinAddress
)) {
1094 // If desc ends past max allowed address, clip the end
1096 if (DescEnd
>= MaxAddress
) {
1097 DescEnd
= MaxAddress
;
1100 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
1102 // Skip if DescEnd is less than DescStart after alignment clipping
1103 if (DescEnd
< DescStart
) {
1108 // Compute the number of bytes we can used from this
1109 // descriptor, and see it's enough to satisfy the request
1111 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
1113 if (DescNumberOfBytes
>= NumberOfBytes
) {
1115 // If the start of the allocated range is below the min address allowed, skip it
1117 if ((DescEnd
- NumberOfBytes
+ 1) < MinAddress
) {
1122 // If this is the best match so far remember it
1124 if (DescEnd
> Target
) {
1126 DescEnd
= AdjustMemoryS (
1127 DescEnd
+ 1 - DescNumberOfBytes
,
1142 // If this is a grow down, adjust target to be the allocation base
1144 Target
-= NumberOfBytes
- 1;
1147 // If we didn't find a match, return 0
1149 if ((Target
& EFI_PAGE_MASK
) != 0) {
1158 Internal function. Finds a consecutive free page range below
1159 the requested address
1161 @param MaxAddress The address that the range must be below
1162 @param NoPages Number of pages needed
1163 @param NewType The type of memory the range is going to be
1165 @param Alignment Bits to align with
1166 @param NeedGuard Flag to indicate Guard page is needed or not
1168 @return The base address of the range, or 0 if the range was not found.
1173 IN UINT64 MaxAddress
,
1175 IN EFI_MEMORY_TYPE NewType
,
1177 IN BOOLEAN NeedGuard
1183 // Attempt to find free pages in the preferred bin based on the requested memory type
1185 if ((UINT32
)NewType
< EfiMaxMemoryType
&& MaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1186 Start
= CoreFindFreePagesI (
1187 mMemoryTypeStatistics
[NewType
].MaximumAddress
,
1188 mMemoryTypeStatistics
[NewType
].BaseAddress
,
1200 // Attempt to find free pages in the default allocation bin
1202 if (MaxAddress
>= mDefaultMaximumAddress
) {
1203 Start
= CoreFindFreePagesI (mDefaultMaximumAddress
, 0, NoPages
, NewType
,
1204 Alignment
, NeedGuard
);
1206 if (Start
< mDefaultBaseAddress
) {
1207 mDefaultBaseAddress
= Start
;
1214 // The allocation did not succeed in any of the prefered bins even after
1215 // promoting resources. Attempt to find free pages anywhere is the requested
1216 // address range. If this allocation fails, then there are not enough
1217 // resources anywhere to satisfy the request.
1219 Start
= CoreFindFreePagesI (MaxAddress
, 0, NoPages
, NewType
, Alignment
,
1226 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1228 if (!PromoteMemoryResource ()) {
1233 // If any memory resources were promoted, then re-attempt the allocation
1235 return FindFreePages (MaxAddress
, NoPages
, NewType
, Alignment
, NeedGuard
);
1240 Allocates pages from the memory map.
1242 @param Type The type of allocation to perform
1243 @param MemoryType The type of memory to turn the allocated pages
1245 @param NumberOfPages The number of pages to allocate
1246 @param Memory A pointer to receive the base allocated memory
1248 @param NeedGuard Flag to indicate Guard page is needed or not
1250 @return Status. On success, Memory is filled in with the base address allocated
1251 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1253 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1254 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1255 @retval EFI_SUCCESS Pages successfully allocated.
1260 CoreInternalAllocatePages (
1261 IN EFI_ALLOCATE_TYPE Type
,
1262 IN EFI_MEMORY_TYPE MemoryType
,
1263 IN UINTN NumberOfPages
,
1264 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
1265 IN BOOLEAN NeedGuard
1270 UINT64 NumberOfBytes
;
1274 EFI_MEMORY_TYPE CheckType
;
1276 if ((UINT32
)Type
>= MaxAllocateType
) {
1277 return EFI_INVALID_PARAMETER
;
1280 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
< MEMORY_TYPE_OEM_RESERVED_MIN
) ||
1281 (MemoryType
== EfiConventionalMemory
) || (MemoryType
== EfiPersistentMemory
)) {
1282 return EFI_INVALID_PARAMETER
;
1285 if (Memory
== NULL
) {
1286 return EFI_INVALID_PARAMETER
;
1289 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1291 if (MemoryType
== EfiACPIReclaimMemory
||
1292 MemoryType
== EfiACPIMemoryNVS
||
1293 MemoryType
== EfiRuntimeServicesCode
||
1294 MemoryType
== EfiRuntimeServicesData
) {
1296 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1299 if (Type
== AllocateAddress
) {
1300 if ((*Memory
& (Alignment
- 1)) != 0) {
1301 return EFI_NOT_FOUND
;
1305 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1306 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1309 // If this is for below a particular address, then
1314 // The max address is the max natively addressable address for the processor
1316 MaxAddress
= MAX_ALLOC_ADDRESS
;
1319 // Check for Type AllocateAddress,
1320 // if NumberOfPages is 0 or
1321 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
1322 // if (Start + NumberOfBytes) rolls over 0 or
1323 // if Start is above MAX_ALLOC_ADDRESS or
1324 // if End is above MAX_ALLOC_ADDRESS,
1325 // if Start..End overlaps any tracked MemoryTypeStatistics range
1326 // return EFI_NOT_FOUND.
1328 if (Type
== AllocateAddress
) {
1329 if ((NumberOfPages
== 0) ||
1330 (NumberOfPages
> RShiftU64 (MaxAddress
, EFI_PAGE_SHIFT
))) {
1331 return EFI_NOT_FOUND
;
1333 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1334 End
= Start
+ NumberOfBytes
- 1;
1336 if ((Start
>= End
) ||
1337 (Start
> MaxAddress
) ||
1338 (End
> MaxAddress
)) {
1339 return EFI_NOT_FOUND
;
1343 // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of
1344 // AllocatePage request the exact physical address if it is not used. The existing code
1345 // will allow this request even in 'special' pages. The problem with this is that the
1346 // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
1350 for (CheckType
= (EFI_MEMORY_TYPE
) 0; CheckType
< EfiMaxMemoryType
; CheckType
++) {
1351 if (MemoryType
!= CheckType
&&
1352 mMemoryTypeStatistics
[CheckType
].Special
&&
1353 mMemoryTypeStatistics
[CheckType
].NumberOfPages
> 0) {
1354 if (Start
>= mMemoryTypeStatistics
[CheckType
].BaseAddress
&&
1355 Start
<= mMemoryTypeStatistics
[CheckType
].MaximumAddress
) {
1356 return EFI_NOT_FOUND
;
1358 if (End
>= mMemoryTypeStatistics
[CheckType
].BaseAddress
&&
1359 End
<= mMemoryTypeStatistics
[CheckType
].MaximumAddress
) {
1360 return EFI_NOT_FOUND
;
1362 if (Start
< mMemoryTypeStatistics
[CheckType
].BaseAddress
&&
1363 End
> mMemoryTypeStatistics
[CheckType
].MaximumAddress
) {
1364 return EFI_NOT_FOUND
;
1370 if (Type
== AllocateMaxAddress
) {
1374 CoreAcquireMemoryLock ();
1377 // If not a specific address, then find an address to allocate
1379 if (Type
!= AllocateAddress
) {
1380 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
,
1383 Status
= EFI_OUT_OF_RESOURCES
;
1389 // Convert pages from FreeMemory to the requested type
1392 Status
= CoreConvertPagesWithGuard(Start
, NumberOfPages
, MemoryType
);
1394 Status
= CoreConvertPages(Start
, NumberOfPages
, MemoryType
);
1398 CoreReleaseMemoryLock ();
1400 if (!EFI_ERROR (Status
)) {
1402 SetGuardForMemory (Start
, NumberOfPages
);
1411 Allocates pages from the memory map.
1413 @param Type The type of allocation to perform
1414 @param MemoryType The type of memory to turn the allocated pages
1416 @param NumberOfPages The number of pages to allocate
1417 @param Memory A pointer to receive the base allocated memory
1420 @return Status. On success, Memory is filled in with the base address allocated
1421 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1423 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1424 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1425 @retval EFI_SUCCESS Pages successfully allocated.
1431 IN EFI_ALLOCATE_TYPE Type
,
1432 IN EFI_MEMORY_TYPE MemoryType
,
1433 IN UINTN NumberOfPages
,
1434 OUT EFI_PHYSICAL_ADDRESS
*Memory
1440 NeedGuard
= IsPageTypeToGuard (MemoryType
, Type
) && !mOnGuarding
;
1441 Status
= CoreInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
,
1443 if (!EFI_ERROR (Status
)) {
1445 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
1446 MemoryProfileActionAllocatePages
,
1448 EFI_PAGES_TO_SIZE (NumberOfPages
),
1449 (VOID
*) (UINTN
) *Memory
,
1452 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1453 ApplyMemoryProtectionPolicy (EfiConventionalMemory
, MemoryType
, *Memory
,
1454 EFI_PAGES_TO_SIZE (NumberOfPages
));
1460 Frees previous allocated pages.
1462 @param Memory Base address of memory being freed
1463 @param NumberOfPages The number of pages to free
1464 @param MemoryType Pointer to memory type
1466 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1467 @retval EFI_INVALID_PARAMETER Address not aligned
1468 @return EFI_SUCCESS -Pages successfully freed.
1473 CoreInternalFreePages (
1474 IN EFI_PHYSICAL_ADDRESS Memory
,
1475 IN UINTN NumberOfPages
,
1476 OUT EFI_MEMORY_TYPE
*MemoryType OPTIONAL
1488 CoreAcquireMemoryLock ();
1491 // Find the entry that the covers the range
1495 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1496 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1497 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1501 if (Link
== &gMemoryMap
) {
1502 Status
= EFI_NOT_FOUND
;
1506 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1508 ASSERT (Entry
!= NULL
);
1509 if (Entry
->Type
== EfiACPIReclaimMemory
||
1510 Entry
->Type
== EfiACPIMemoryNVS
||
1511 Entry
->Type
== EfiRuntimeServicesCode
||
1512 Entry
->Type
== EfiRuntimeServicesData
) {
1514 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1518 if ((Memory
& (Alignment
- 1)) != 0) {
1519 Status
= EFI_INVALID_PARAMETER
;
1523 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1524 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1526 if (MemoryType
!= NULL
) {
1527 *MemoryType
= Entry
->Type
;
1530 IsGuarded
= IsPageTypeToGuard (Entry
->Type
, AllocateAnyPages
) &&
1531 IsMemoryGuarded (Memory
);
1533 Status
= CoreConvertPagesWithGuard (Memory
, NumberOfPages
,
1534 EfiConventionalMemory
);
1536 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1540 CoreReleaseMemoryLock ();
1545 Frees previous allocated pages.
1547 @param Memory Base address of memory being freed
1548 @param NumberOfPages The number of pages to free
1550 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1551 @retval EFI_INVALID_PARAMETER Address not aligned
1552 @return EFI_SUCCESS -Pages successfully freed.
1558 IN EFI_PHYSICAL_ADDRESS Memory
,
1559 IN UINTN NumberOfPages
1563 EFI_MEMORY_TYPE MemoryType
;
1565 Status
= CoreInternalFreePages (Memory
, NumberOfPages
, &MemoryType
);
1566 if (!EFI_ERROR (Status
)) {
1567 GuardFreedPagesChecked (Memory
, NumberOfPages
);
1569 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
1570 MemoryProfileActionFreePages
,
1572 EFI_PAGES_TO_SIZE (NumberOfPages
),
1573 (VOID
*) (UINTN
) Memory
,
1576 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1577 ApplyMemoryProtectionPolicy (MemoryType
, EfiConventionalMemory
, Memory
,
1578 EFI_PAGES_TO_SIZE (NumberOfPages
));
1584 This function checks to see if the last memory map descriptor in a memory map
1585 can be merged with any of the other memory map descriptors in a memorymap.
1586 Memory descriptors may be merged if they are adjacent and have the same type
1589 @param MemoryMap A pointer to the start of the memory map.
1590 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1591 @param DescriptorSize The size, in bytes, of an individual
1592 EFI_MEMORY_DESCRIPTOR.
1594 @return A pointer to the next available descriptor in MemoryMap
1597 EFI_MEMORY_DESCRIPTOR
*
1598 MergeMemoryMapDescriptor (
1599 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1600 IN EFI_MEMORY_DESCRIPTOR
*MemoryMapDescriptor
,
1601 IN UINTN DescriptorSize
1605 // Traverse the array of descriptors in MemoryMap
1607 for (; MemoryMap
!= MemoryMapDescriptor
; MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
)) {
1609 // Check to see if the Type fields are identical.
1611 if (MemoryMap
->Type
!= MemoryMapDescriptor
->Type
) {
1616 // Check to see if the Attribute fields are identical.
1618 if (MemoryMap
->Attribute
!= MemoryMapDescriptor
->Attribute
) {
1623 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1625 if (MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1627 // Merge MemoryMapDescriptor into MemoryMap
1629 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1632 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1634 return MemoryMapDescriptor
;
1638 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1640 if (MemoryMap
->PhysicalStart
- EFI_PAGES_TO_SIZE ((UINTN
)MemoryMapDescriptor
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1642 // Merge MemoryMapDescriptor into MemoryMap
1644 MemoryMap
->PhysicalStart
= MemoryMapDescriptor
->PhysicalStart
;
1645 MemoryMap
->VirtualStart
= MemoryMapDescriptor
->VirtualStart
;
1646 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1649 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1651 return MemoryMapDescriptor
;
1656 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1658 // Return the slot immediately after MemoryMapDescriptor as the next available
1659 // slot in the MemoryMap array
1661 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor
, DescriptorSize
);
1665 This function returns a copy of the current memory map. The map is an array of
1666 memory descriptors, each of which describes a contiguous block of memory.
1668 @param MemoryMapSize A pointer to the size, in bytes, of the
1669 MemoryMap buffer. On input, this is the size of
1670 the buffer allocated by the caller. On output,
1671 it is the size of the buffer returned by the
1672 firmware if the buffer was large enough, or the
1673 size of the buffer needed to contain the map if
1674 the buffer was too small.
1675 @param MemoryMap A pointer to the buffer in which firmware places
1676 the current memory map.
1677 @param MapKey A pointer to the location in which firmware
1678 returns the key for the current memory map.
1679 @param DescriptorSize A pointer to the location in which firmware
1680 returns the size, in bytes, of an individual
1681 EFI_MEMORY_DESCRIPTOR.
1682 @param DescriptorVersion A pointer to the location in which firmware
1683 returns the version number associated with the
1684 EFI_MEMORY_DESCRIPTOR.
1686 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1688 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1689 buffer size needed to hold the memory map is
1690 returned in MemoryMapSize.
1691 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1697 IN OUT UINTN
*MemoryMapSize
,
1698 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1700 OUT UINTN
*DescriptorSize
,
1701 OUT UINT32
*DescriptorVersion
1707 UINTN NumberOfEntries
;
1710 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1711 EFI_GCD_MAP_ENTRY MergeGcdMapEntry
;
1712 EFI_MEMORY_TYPE Type
;
1713 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
1714 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1717 // Make sure the parameters are valid
1719 if (MemoryMapSize
== NULL
) {
1720 return EFI_INVALID_PARAMETER
;
1723 CoreAcquireGcdMemoryLock ();
1726 // Count the number of Reserved and runtime MMIO entries
1727 // And, count the number of Persistent entries.
1729 NumberOfEntries
= 0;
1730 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1731 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1732 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypePersistent
) ||
1733 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1734 ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1735 ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
))) {
1740 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1743 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1744 // prevent people from having pointer math bugs in their code.
1745 // now you have to use *DescriptorSize to make things work.
1747 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1749 if (DescriptorSize
!= NULL
) {
1750 *DescriptorSize
= Size
;
1753 if (DescriptorVersion
!= NULL
) {
1754 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1757 CoreAcquireMemoryLock ();
1760 // Compute the buffer size needed to fit the entire map
1762 BufferSize
= Size
* NumberOfEntries
;
1763 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1767 if (*MemoryMapSize
< BufferSize
) {
1768 Status
= EFI_BUFFER_TOO_SMALL
;
1772 if (MemoryMap
== NULL
) {
1773 Status
= EFI_INVALID_PARAMETER
;
1780 ZeroMem (MemoryMap
, BufferSize
);
1781 MemoryMapStart
= MemoryMap
;
1782 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1783 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1784 ASSERT (Entry
->VirtualStart
== 0);
1787 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1789 MemoryMap
->Type
= Entry
->Type
;
1790 MemoryMap
->PhysicalStart
= Entry
->Start
;
1791 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1792 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1794 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1795 // memory type bin and needs to be converted to the same memory type as the rest of the
1796 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1797 // improves the chances for a successful S4 resume in the presence of minor page allocation
1798 // differences across reboots.
1800 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1801 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
1802 if (mMemoryTypeStatistics
[Type
].Special
&&
1803 mMemoryTypeStatistics
[Type
].NumberOfPages
> 0 &&
1804 Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
&&
1805 Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
) {
1806 MemoryMap
->Type
= Type
;
1810 MemoryMap
->Attribute
= Entry
->Attribute
;
1811 if (MemoryMap
->Type
< EfiMaxMemoryType
) {
1812 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1813 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1818 // Check to see if the new Memory Map Descriptor can be merged with an
1819 // existing descriptor if they are adjacent and have the same attributes
1821 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1825 ZeroMem (&MergeGcdMapEntry
, sizeof (MergeGcdMapEntry
));
1827 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; ; Link
= Link
->ForwardLink
) {
1828 if (Link
!= &mGcdMemorySpaceMap
) {
1830 // Merge adjacent same type and attribute GCD memory range
1832 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1834 if ((MergeGcdMapEntry
.Capabilities
== GcdMapEntry
->Capabilities
) &&
1835 (MergeGcdMapEntry
.Attributes
== GcdMapEntry
->Attributes
) &&
1836 (MergeGcdMapEntry
.GcdMemoryType
== GcdMapEntry
->GcdMemoryType
) &&
1837 (MergeGcdMapEntry
.GcdIoType
== GcdMapEntry
->GcdIoType
)) {
1838 MergeGcdMapEntry
.EndAddress
= GcdMapEntry
->EndAddress
;
1843 if ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1844 ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1845 ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
))) {
1847 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1848 // it will be recorded as page PhysicalStart and NumberOfPages.
1850 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1851 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1854 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1856 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1857 MemoryMap
->VirtualStart
= 0;
1858 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1859 MemoryMap
->Attribute
= (MergeGcdMapEntry
.Attributes
& ~EFI_MEMORY_PORT_IO
) |
1860 (MergeGcdMapEntry
.Capabilities
& (EFI_CACHE_ATTRIBUTE_MASK
| EFI_MEMORY_ATTRIBUTE_MASK
));
1862 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1863 MemoryMap
->Type
= EfiReservedMemoryType
;
1864 } else if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1865 if ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1866 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1868 MemoryMap
->Type
= EfiMemoryMappedIO
;
1873 // Check to see if the new Memory Map Descriptor can be merged with an
1874 // existing descriptor if they are adjacent and have the same attributes
1876 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1879 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypePersistent
) {
1881 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1882 // it will be recorded as page PhysicalStart and NumberOfPages.
1884 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1885 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1888 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1890 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1891 MemoryMap
->VirtualStart
= 0;
1892 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1893 MemoryMap
->Attribute
= MergeGcdMapEntry
.Attributes
| EFI_MEMORY_NV
|
1894 (MergeGcdMapEntry
.Capabilities
& (EFI_CACHE_ATTRIBUTE_MASK
| EFI_MEMORY_ATTRIBUTE_MASK
));
1895 MemoryMap
->Type
= EfiPersistentMemory
;
1898 // Check to see if the new Memory Map Descriptor can be merged with an
1899 // existing descriptor if they are adjacent and have the same attributes
1901 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1903 if (Link
== &mGcdMemorySpaceMap
) {
1905 // break loop when arrive at head.
1909 if (GcdMapEntry
!= NULL
) {
1911 // Copy new GCD map entry for the following GCD range merge
1913 CopyMem (&MergeGcdMapEntry
, GcdMapEntry
, sizeof (MergeGcdMapEntry
));
1918 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1920 BufferSize
= ((UINT8
*)MemoryMap
- (UINT8
*)MemoryMapStart
);
1923 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1924 // set attributes and change memory paging attribute accordingly.
1925 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1926 // value from Capabilities in GCD memory map. This might cause
1927 // boot problems. Clearing all paging related capabilities can
1928 // workaround it. Following code is supposed to be removed once
1929 // the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in
1930 // UEFI spec and adopted by both EDK-II Core and all supported
1933 MemoryMapEnd
= MemoryMap
;
1934 MemoryMap
= MemoryMapStart
;
1935 while (MemoryMap
< MemoryMapEnd
) {
1936 MemoryMap
->Attribute
&= ~(UINT64
)EFI_MEMORY_ATTRIBUTE_MASK
;
1937 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, Size
);
1939 MergeMemoryMap (MemoryMapStart
, &BufferSize
, Size
);
1940 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MemoryMapStart
+ BufferSize
);
1942 Status
= EFI_SUCCESS
;
1946 // Update the map key finally
1948 if (MapKey
!= NULL
) {
1949 *MapKey
= mMemoryMapKey
;
1952 CoreReleaseMemoryLock ();
1954 CoreReleaseGcdMemoryLock ();
1956 *MemoryMapSize
= BufferSize
;
1959 DumpGuardedMemoryBitmap ();
1967 Internal function. Used by the pool functions to allocate pages
1968 to back pool allocation requests.
1970 @param PoolType The type of memory for the new pool pages
1971 @param NumberOfPages No of pages to allocate
1972 @param Alignment Bits to align.
1973 @param NeedGuard Flag to indicate Guard page is needed or not
1975 @return The allocated memory, or NULL
1979 CoreAllocatePoolPages (
1980 IN EFI_MEMORY_TYPE PoolType
,
1981 IN UINTN NumberOfPages
,
1983 IN BOOLEAN NeedGuard
1989 // Find the pages to convert
1991 Start
= FindFreePages (MAX_ALLOC_ADDRESS
, NumberOfPages
, PoolType
, Alignment
,
1995 // Convert it to boot services data
1998 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32
)NumberOfPages
));
2001 CoreConvertPagesWithGuard (Start
, NumberOfPages
, PoolType
);
2003 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
2007 return (VOID
*)(UINTN
) Start
;
2012 Internal function. Frees pool pages allocated via AllocatePoolPages ()
2014 @param Memory The base address to free
2015 @param NumberOfPages The number of pages to free
2020 IN EFI_PHYSICAL_ADDRESS Memory
,
2021 IN UINTN NumberOfPages
2024 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
2030 Make sure the memory map is following all the construction rules,
2031 it is the last time to check memory map error before exit boot services.
2033 @param MapKey Memory map key
2035 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2037 @retval EFI_SUCCESS Valid memory map.
2041 CoreTerminateMemoryMap (
2049 Status
= EFI_SUCCESS
;
2051 CoreAcquireMemoryLock ();
2053 if (MapKey
== mMemoryMapKey
) {
2056 // Make sure the memory map is following all the construction rules
2057 // This is the last chance we will be able to display any messages on
2058 // the console devices.
2061 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
2062 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
2063 if (Entry
->Type
< EfiMaxMemoryType
) {
2064 if (mMemoryTypeStatistics
[Entry
->Type
].Runtime
) {
2065 ASSERT (Entry
->Type
!= EfiACPIReclaimMemory
);
2066 ASSERT (Entry
->Type
!= EfiACPIMemoryNVS
);
2067 if ((Entry
->Start
& (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2068 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2069 Status
= EFI_INVALID_PARAMETER
;
2072 if (((Entry
->End
+ 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2073 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2074 Status
= EFI_INVALID_PARAMETER
;
2082 // The map key they gave us matches what we expect. Fall through and
2083 // return success. In an ideal world we would clear out all of
2084 // EfiBootServicesCode and EfiBootServicesData. However this function
2085 // is not the last one called by ExitBootServices(), so we have to
2086 // preserve the memory contents.
2089 Status
= EFI_INVALID_PARAMETER
;
2093 CoreReleaseMemoryLock ();