2 UEFI Memory page management functions.
4 Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "HeapGuard.h"
20 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
23 EFI_PHYSICAL_ADDRESS BaseAddress
;
24 EFI_PHYSICAL_ADDRESS MaximumAddress
;
25 UINT64 CurrentNumberOfPages
;
27 UINTN InformationIndex
;
30 } EFI_MEMORY_TYPE_STATISTICS
;
33 // MemoryMap - The current memory map
35 UINTN mMemoryMapKey
= 0;
37 #define MAX_MAP_DEPTH 6
40 /// mMapDepth - depth of new descriptor stack
44 /// mMapStack - space to use as temp storage to build new map descriptors
46 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
47 UINTN mFreeMapStack
= 0;
49 /// This list maintain the free memory map list
51 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
52 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
54 EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
55 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
56 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
57 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
58 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
59 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
60 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
61 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
62 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
63 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
64 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
65 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
66 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
67 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
68 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
69 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiPersistentMemory
70 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
73 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= MAX_ADDRESS
;
74 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress
= MAX_ADDRESS
;
76 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
77 { EfiReservedMemoryType
, 0 },
80 { EfiBootServicesCode
, 0 },
81 { EfiBootServicesData
, 0 },
82 { EfiRuntimeServicesCode
, 0 },
83 { EfiRuntimeServicesData
, 0 },
84 { EfiConventionalMemory
, 0 },
85 { EfiUnusableMemory
, 0 },
86 { EfiACPIReclaimMemory
, 0 },
87 { EfiACPIMemoryNVS
, 0 },
88 { EfiMemoryMappedIO
, 0 },
89 { EfiMemoryMappedIOPortSpace
, 0 },
91 { EfiPersistentMemory
, 0 },
92 { EfiMaxMemoryType
, 0 }
95 // Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
96 // and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
97 // address assigned by DXE core.
99 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady
= FALSE
;
102 Enter critical section by gaining lock on gMemoryLock.
106 CoreAcquireMemoryLock (
110 CoreAcquireLock (&gMemoryLock
);
116 Exit critical section by releasing lock on gMemoryLock.
120 CoreReleaseMemoryLock (
124 CoreReleaseLock (&gMemoryLock
);
131 Internal function. Removes a descriptor entry.
133 @param Entry The entry to remove
137 RemoveMemoryMapEntry (
138 IN OUT MEMORY_MAP
*Entry
141 RemoveEntryList (&Entry
->Link
);
142 Entry
->Link
.ForwardLink
= NULL
;
144 if (Entry
->FromPages
) {
146 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
148 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
153 Internal function. Adds a ranges to the memory map.
154 The range must not already exist in the map.
156 @param Type The type of memory range to add
157 @param Start The starting address in the memory range Must be
159 @param End The last address in the range Must be the last
161 @param Attribute The attributes of the memory range to add
166 IN EFI_MEMORY_TYPE Type
,
167 IN EFI_PHYSICAL_ADDRESS Start
,
168 IN EFI_PHYSICAL_ADDRESS End
,
175 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
176 ASSERT (End
> Start
) ;
178 ASSERT_LOCKED (&gMemoryLock
);
180 DEBUG ((DEBUG_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
183 // If memory of type EfiConventionalMemory is being added that includes the page
184 // starting at address 0, then zero the page starting at address 0. This has
185 // two benifits. It helps find NULL pointer bugs and it also maximizes
186 // compatibility with operating systems that may evaluate memory in this page
187 // for legacy data structures. If memory of any other type is added starting
188 // at address 0, then do not zero the page at address 0 because the page is being
189 // used for other purposes.
191 if (Type
== EfiConventionalMemory
&& Start
== 0 && (End
>= EFI_PAGE_SIZE
- 1)) {
192 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask
) & BIT0
) == 0) {
193 SetMem ((VOID
*)(UINTN
)Start
, EFI_PAGE_SIZE
, 0);
198 // Memory map being altered so updated key
203 // UEFI 2.0 added an event group for notificaiton on memory map changes.
204 // So we need to signal this Event Group every time the memory map changes.
205 // If we are in EFI 1.10 compatability mode no event groups will be
206 // found and nothing will happen we we call this function. These events
207 // will get signaled but since a lock is held around the call to this
208 // function the notificaiton events will only be called after this function
209 // returns and the lock is released.
211 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
214 // Look for adjoining memory descriptor
217 // Two memory descriptors can only be merged if they have the same Type
218 // and the same Attribute
221 Link
= gMemoryMap
.ForwardLink
;
222 while (Link
!= &gMemoryMap
) {
223 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
224 Link
= Link
->ForwardLink
;
226 if (Entry
->Type
!= Type
) {
230 if (Entry
->Attribute
!= Attribute
) {
234 if (Entry
->End
+ 1 == Start
) {
236 Start
= Entry
->Start
;
237 RemoveMemoryMapEntry (Entry
);
239 } else if (Entry
->Start
== End
+ 1) {
242 RemoveMemoryMapEntry (Entry
);
250 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
251 mMapStack
[mMapDepth
].FromPages
= FALSE
;
252 mMapStack
[mMapDepth
].Type
= Type
;
253 mMapStack
[mMapDepth
].Start
= Start
;
254 mMapStack
[mMapDepth
].End
= End
;
255 mMapStack
[mMapDepth
].VirtualStart
= 0;
256 mMapStack
[mMapDepth
].Attribute
= Attribute
;
257 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
260 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
266 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
267 If the list is emtry, then allocate a new page to refuel the list.
268 Please Note this algorithm to allocate the memory map descriptor has a property
269 that the memory allocated for memory entries always grows, and will never really be freed
270 For example, if the current boot uses 2000 memory map entries at the maximum point, but
271 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
272 memory map entries is still allocated from EfiBootServicesMemory.
275 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
279 AllocateMemoryMapEntry (
283 MEMORY_MAP
* FreeDescriptorEntries
;
287 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
289 // The list is empty, to allocate one page to refuel the list
291 FreeDescriptorEntries
= CoreAllocatePoolPages (
293 EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY
),
294 DEFAULT_PAGE_ALLOCATION_GRANULARITY
,
297 if (FreeDescriptorEntries
!= NULL
) {
299 // Enque the free memmory map entries into the list
301 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION_GRANULARITY
/ sizeof(MEMORY_MAP
); Index
++) {
302 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
303 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
310 // dequeue the first descriptor from the list
312 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
313 RemoveEntryList (&Entry
->Link
);
320 Internal function. Moves any memory descriptors that are on the
321 temporary descriptor stack to heap.
325 CoreFreeMemoryMapStack (
333 ASSERT_LOCKED (&gMemoryLock
);
336 // If already freeing the map stack, then return
338 if (mFreeMapStack
!= 0) {
343 // Move the temporary memory descriptor stack into pool
347 while (mMapDepth
!= 0) {
349 // Deque an memory map entry from mFreeMemoryMapEntryList
351 Entry
= AllocateMemoryMapEntry ();
356 // Update to proper entry
360 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
363 // Move this entry to general memory
365 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
366 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
368 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
369 Entry
->FromPages
= TRUE
;
372 // Find insertion location
374 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
375 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
376 if (Entry2
->FromPages
&& Entry2
->Start
> Entry
->Start
) {
381 InsertTailList (Link2
, &Entry
->Link
);
385 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
386 // so here no need to move it to memory.
388 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
396 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
400 PromoteMemoryResource (
405 EFI_GCD_MAP_ENTRY
*Entry
;
408 DEBUG ((DEBUG_PAGE
, "Promote the memory resource\n"));
410 CoreAcquireGcdMemoryLock ();
413 Link
= mGcdMemorySpaceMap
.ForwardLink
;
414 while (Link
!= &mGcdMemorySpaceMap
) {
416 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
418 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
419 Entry
->EndAddress
< MAX_ADDRESS
&&
420 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
421 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
423 // Update the GCD map
425 if ((Entry
->Capabilities
& EFI_MEMORY_MORE_RELIABLE
) == EFI_MEMORY_MORE_RELIABLE
) {
426 Entry
->GcdMemoryType
= EfiGcdMemoryTypeMoreReliable
;
428 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
430 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
431 Entry
->ImageHandle
= gDxeCoreImageHandle
;
432 Entry
->DeviceHandle
= NULL
;
435 // Add to allocable system memory resource
439 EfiConventionalMemory
,
442 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
444 CoreFreeMemoryMapStack ();
449 Link
= Link
->ForwardLink
;
452 CoreReleaseGcdMemoryLock ();
457 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
458 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
459 size of boot time and runtime code.
463 CoreLoadingFixedAddressHook (
467 UINT32 RuntimeCodePageNumber
;
468 UINT32 BootTimeCodePageNumber
;
469 EFI_PHYSICAL_ADDRESS RuntimeCodeBase
;
470 EFI_PHYSICAL_ADDRESS BootTimeCodeBase
;
474 // Make sure these 2 areas are not initialzied.
476 if (!gLoadFixedAddressCodeMemoryReady
) {
477 RuntimeCodePageNumber
= PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber
);
478 BootTimeCodePageNumber
= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber
);
479 RuntimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(gLoadModuleAtFixAddressConfigurationTable
.DxeCodeTopAddress
- EFI_PAGES_TO_SIZE (RuntimeCodePageNumber
));
480 BootTimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(RuntimeCodeBase
- EFI_PAGES_TO_SIZE (BootTimeCodePageNumber
));
482 // Try to allocate runtime memory.
484 Status
= CoreAllocatePages (
486 EfiRuntimeServicesCode
,
487 RuntimeCodePageNumber
,
490 if (EFI_ERROR(Status
)) {
492 // Runtime memory allocation failed
497 // Try to allocate boot memory.
499 Status
= CoreAllocatePages (
502 BootTimeCodePageNumber
,
505 if (EFI_ERROR(Status
)) {
507 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
508 // new memory range is installed.
512 RuntimeCodePageNumber
516 gLoadFixedAddressCodeMemoryReady
= TRUE
;
522 Called to initialize the memory map and add descriptors to
523 the current descriptor list.
524 The first descriptor that is added must be general usable
525 memory as the addition allocates heap.
527 @param Type The type of memory to add
528 @param Start The starting address in the memory range Must be
530 @param NumberOfPages The number of pages in the range
531 @param Attribute Attributes of the memory to add
533 @return None. The range is added to the memory map
537 CoreAddMemoryDescriptor (
538 IN EFI_MEMORY_TYPE Type
,
539 IN EFI_PHYSICAL_ADDRESS Start
,
540 IN UINT64 NumberOfPages
,
544 EFI_PHYSICAL_ADDRESS End
;
549 if ((Start
& EFI_PAGE_MASK
) != 0) {
553 if (Type
>= EfiMaxMemoryType
&& Type
< MEMORY_TYPE_OEM_RESERVED_MIN
) {
556 CoreAcquireMemoryLock ();
557 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
558 CoreAddRange (Type
, Start
, End
, Attribute
);
559 CoreFreeMemoryMapStack ();
560 CoreReleaseMemoryLock ();
562 ApplyMemoryProtectionPolicy (EfiMaxMemoryType
, Type
, Start
,
563 LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
));
566 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
568 if (PcdGet64(PcdLoadModuleAtFixAddressEnable
) != 0) {
569 CoreLoadingFixedAddressHook();
573 // Check to see if the statistics for the different memory types have already been established
575 if (mMemoryTypeInformationInitialized
) {
581 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
583 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
585 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
587 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
588 if ((UINT32
)Type
> EfiMaxMemoryType
) {
591 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
593 // Allocate pages for the current memory type from the top of available memory
595 Status
= CoreAllocatePages (
598 gMemoryTypeInformation
[Index
].NumberOfPages
,
599 &mMemoryTypeStatistics
[Type
].BaseAddress
601 if (EFI_ERROR (Status
)) {
603 // If an error occurs allocating the pages for the current memory type, then
604 // free all the pages allocates for the previous memory types and return. This
605 // operation with be retied when/if more memory is added to the system
607 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
609 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
611 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
612 if ((UINT32
)Type
> EfiMaxMemoryType
) {
616 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
618 mMemoryTypeStatistics
[Type
].BaseAddress
,
619 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
621 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
622 mMemoryTypeStatistics
[Type
].MaximumAddress
= MAX_ADDRESS
;
629 // Compute the address at the top of the current statistics
631 mMemoryTypeStatistics
[Type
].MaximumAddress
=
632 mMemoryTypeStatistics
[Type
].BaseAddress
+
633 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
636 // If the current base address is the lowest address so far, then update the default
639 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
640 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
646 // There was enough system memory for all the the memory types were allocated. So,
647 // those memory areas can be freed for future allocations, and all future memory
648 // allocations can occur within their respective bins
650 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
652 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
654 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
655 if ((UINT32
)Type
> EfiMaxMemoryType
) {
658 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
660 mMemoryTypeStatistics
[Type
].BaseAddress
,
661 gMemoryTypeInformation
[Index
].NumberOfPages
663 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
664 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
669 // If the number of pages reserved for a memory type is 0, then all allocations for that type
670 // should be in the default range.
672 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
673 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
674 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
675 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
678 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
679 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== MAX_ADDRESS
) {
680 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
684 mMemoryTypeInformationInitialized
= TRUE
;
689 Internal function. Converts a memory range to the specified type or attributes.
690 The range must exist in the memory map. Either ChangingType or
691 ChangingAttributes must be set, but not both.
693 @param Start The first address of the range Must be page
695 @param NumberOfPages The number of pages to convert
696 @param ChangingType Boolean indicating that type value should be changed
697 @param NewType The new type for the memory range
698 @param ChangingAttributes Boolean indicating that attributes value should be changed
699 @param NewAttributes The new attributes for the memory range
701 @retval EFI_INVALID_PARAMETER Invalid parameter
702 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
703 range or convertion not allowed.
704 @retval EFI_SUCCESS Successfully converts the memory range to the
711 IN UINT64 NumberOfPages
,
712 IN BOOLEAN ChangingType
,
713 IN EFI_MEMORY_TYPE NewType
,
714 IN BOOLEAN ChangingAttributes
,
715 IN UINT64 NewAttributes
719 UINT64 NumberOfBytes
;
723 EFI_MEMORY_TYPE MemType
;
728 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
729 End
= Start
+ NumberOfBytes
- 1;
731 ASSERT (NumberOfPages
);
732 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
733 ASSERT (End
> Start
) ;
734 ASSERT_LOCKED (&gMemoryLock
);
735 ASSERT ( (ChangingType
== FALSE
) || (ChangingAttributes
== FALSE
) );
737 if (NumberOfPages
== 0 || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
>= End
)) {
738 return EFI_INVALID_PARAMETER
;
742 // Convert the entire range
745 while (Start
< End
) {
748 // Find the entry that the covers the range
750 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
751 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
753 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
758 if (Link
== &gMemoryMap
) {
759 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
760 return EFI_NOT_FOUND
;
764 // If we are converting the type of the range from EfiConventionalMemory to
765 // another type, we have to ensure that the entire range is covered by a
768 if (ChangingType
&& (NewType
!= EfiConventionalMemory
)) {
769 if (Entry
->End
< End
) {
770 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: range %lx - %lx covers multiple entries\n", Start
, End
));
771 return EFI_NOT_FOUND
;
775 // Convert range to the end, or to the end of the descriptor
776 // if that's all we've got
780 ASSERT (Entry
!= NULL
);
781 if (Entry
->End
< End
) {
782 RangeEnd
= Entry
->End
;
786 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to type %d\n", Start
, RangeEnd
, NewType
));
788 if (ChangingAttributes
) {
789 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to attr %lx\n", Start
, RangeEnd
, NewAttributes
));
794 // Debug code - verify conversion is allowed
796 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
797 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: Incompatible memory types, "));
798 if (Entry
->Type
== EfiConventionalMemory
) {
799 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to free have been freed\n"));
801 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to allocate have been allocated\n"));
803 return EFI_NOT_FOUND
;
807 // Update counters for the number of pages allocated to each memory type
809 if ((UINT32
)Entry
->Type
< EfiMaxMemoryType
) {
810 if ((Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) ||
811 (Start
>= mDefaultBaseAddress
&& Start
<= mDefaultMaximumAddress
) ) {
812 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
813 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
815 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
820 if ((UINT32
)NewType
< EfiMaxMemoryType
) {
821 if ((Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) ||
822 (Start
>= mDefaultBaseAddress
&& Start
<= mDefaultMaximumAddress
) ) {
823 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
824 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
> gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
825 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
832 // Pull range out of descriptor
834 if (Entry
->Start
== Start
) {
839 Entry
->Start
= RangeEnd
+ 1;
841 } else if (Entry
->End
== RangeEnd
) {
846 Entry
->End
= Start
- 1;
851 // Pull it out of the center, clip current
857 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
858 mMapStack
[mMapDepth
].FromPages
= FALSE
;
859 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
860 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
861 mMapStack
[mMapDepth
].End
= Entry
->End
;
864 // Inherit Attribute from the Memory Descriptor that is being clipped
866 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
868 Entry
->End
= Start
- 1;
869 ASSERT (Entry
->Start
< Entry
->End
);
871 Entry
= &mMapStack
[mMapDepth
];
872 InsertTailList (&gMemoryMap
, &Entry
->Link
);
875 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
879 // The new range inherits the same Attribute as the Entry
880 // it is being cut out of unless attributes are being changed
883 Attribute
= Entry
->Attribute
;
886 Attribute
= NewAttributes
;
887 MemType
= Entry
->Type
;
891 // If the descriptor is empty, then remove it from the map
893 if (Entry
->Start
== Entry
->End
+ 1) {
894 RemoveMemoryMapEntry (Entry
);
899 // Add our new range in
901 CoreAddRange (MemType
, Start
, RangeEnd
, Attribute
);
902 if (ChangingType
&& (MemType
== EfiConventionalMemory
)) {
905 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
906 // macro will ASSERT() if address is 0. Instead, CoreAddRange()
907 // guarantees that the page starting at address 0 is always filled
910 if (RangeEnd
> EFI_PAGE_SIZE
) {
911 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
) EFI_PAGE_SIZE
, (UINTN
) (RangeEnd
- EFI_PAGE_SIZE
+ 1));
915 // If Heap Guard is enabled, the page at the top and/or bottom of
916 // this memory block to free might be inaccessible. Skipping them
917 // to avoid page fault exception.
922 StartToClear
= Start
;
923 EndToClear
= RangeEnd
;
924 if (PcdGet8 (PcdHeapGuardPropertyMask
) & (BIT1
|BIT0
)) {
925 if (IsGuardPage(StartToClear
)) {
926 StartToClear
+= EFI_PAGE_SIZE
;
928 if (IsGuardPage (EndToClear
)) {
929 EndToClear
-= EFI_PAGE_SIZE
;
931 ASSERT (EndToClear
> StartToClear
);
935 (VOID
*)(UINTN
)StartToClear
,
936 (UINTN
)(EndToClear
- StartToClear
+ 1)
942 // Move any map descriptor stack to general pool
944 CoreFreeMemoryMapStack ();
947 // Bump the starting address, and convert the next range
949 Start
= RangeEnd
+ 1;
953 // Converted the whole range, done
961 Internal function. Converts a memory range to the specified type.
962 The range must exist in the memory map.
964 @param Start The first address of the range Must be page
966 @param NumberOfPages The number of pages to convert
967 @param NewType The new type for the memory range
969 @retval EFI_INVALID_PARAMETER Invalid parameter
970 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
971 range or convertion not allowed.
972 @retval EFI_SUCCESS Successfully converts the memory range to the
979 IN UINT64 NumberOfPages
,
980 IN EFI_MEMORY_TYPE NewType
983 return CoreConvertPagesEx(Start
, NumberOfPages
, TRUE
, NewType
, FALSE
, 0);
988 Internal function. Converts a memory range to use new attributes.
990 @param Start The first address of the range Must be page
992 @param NumberOfPages The number of pages to convert
993 @param NewAttributes The new attributes value for the range.
997 CoreUpdateMemoryAttributes (
998 IN EFI_PHYSICAL_ADDRESS Start
,
999 IN UINT64 NumberOfPages
,
1000 IN UINT64 NewAttributes
1003 CoreAcquireMemoryLock ();
1006 // Update the attributes to the new value
1008 CoreConvertPagesEx(Start
, NumberOfPages
, FALSE
, (EFI_MEMORY_TYPE
)0, TRUE
, NewAttributes
);
1010 CoreReleaseMemoryLock ();
1015 Internal function. Finds a consecutive free page range below
1016 the requested address.
1018 @param MaxAddress The address that the range must be below
1019 @param MinAddress The address that the range must be above
1020 @param NumberOfPages Number of pages needed
1021 @param NewType The type of memory the range is going to be
1023 @param Alignment Bits to align with
1024 @param NeedGuard Flag to indicate Guard page is needed or not
1026 @return The base address of the range, or 0 if the range was not found
1030 CoreFindFreePagesI (
1031 IN UINT64 MaxAddress
,
1032 IN UINT64 MinAddress
,
1033 IN UINT64 NumberOfPages
,
1034 IN EFI_MEMORY_TYPE NewType
,
1036 IN BOOLEAN NeedGuard
1039 UINT64 NumberOfBytes
;
1043 UINT64 DescNumberOfBytes
;
1047 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
1051 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
1054 // If MaxAddress is not aligned to the end of a page
1058 // Change MaxAddress to be 1 page lower
1060 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
1063 // Set MaxAddress to a page boundary
1065 MaxAddress
&= ~(UINT64
)EFI_PAGE_MASK
;
1068 // Set MaxAddress to end of the page
1070 MaxAddress
|= EFI_PAGE_MASK
;
1073 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1076 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1077 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1080 // If it's not a free entry, don't bother with it
1082 if (Entry
->Type
!= EfiConventionalMemory
) {
1086 DescStart
= Entry
->Start
;
1087 DescEnd
= Entry
->End
;
1090 // If desc is past max allowed address or below min allowed address, skip it
1092 if ((DescStart
>= MaxAddress
) || (DescEnd
< MinAddress
)) {
1097 // If desc ends past max allowed address, clip the end
1099 if (DescEnd
>= MaxAddress
) {
1100 DescEnd
= MaxAddress
;
1103 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
1105 // Skip if DescEnd is less than DescStart after alignment clipping
1106 if (DescEnd
< DescStart
) {
1111 // Compute the number of bytes we can used from this
1112 // descriptor, and see it's enough to satisfy the request
1114 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
1116 if (DescNumberOfBytes
>= NumberOfBytes
) {
1118 // If the start of the allocated range is below the min address allowed, skip it
1120 if ((DescEnd
- NumberOfBytes
+ 1) < MinAddress
) {
1125 // If this is the best match so far remember it
1127 if (DescEnd
> Target
) {
1129 DescEnd
= AdjustMemoryS (
1130 DescEnd
+ 1 - DescNumberOfBytes
,
1145 // If this is a grow down, adjust target to be the allocation base
1147 Target
-= NumberOfBytes
- 1;
1150 // If we didn't find a match, return 0
1152 if ((Target
& EFI_PAGE_MASK
) != 0) {
1161 Internal function. Finds a consecutive free page range below
1162 the requested address
1164 @param MaxAddress The address that the range must be below
1165 @param NoPages Number of pages needed
1166 @param NewType The type of memory the range is going to be
1168 @param Alignment Bits to align with
1169 @param NeedGuard Flag to indicate Guard page is needed or not
1171 @return The base address of the range, or 0 if the range was not found.
1176 IN UINT64 MaxAddress
,
1178 IN EFI_MEMORY_TYPE NewType
,
1180 IN BOOLEAN NeedGuard
1186 // Attempt to find free pages in the preferred bin based on the requested memory type
1188 if ((UINT32
)NewType
< EfiMaxMemoryType
&& MaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1189 Start
= CoreFindFreePagesI (
1190 mMemoryTypeStatistics
[NewType
].MaximumAddress
,
1191 mMemoryTypeStatistics
[NewType
].BaseAddress
,
1203 // Attempt to find free pages in the default allocation bin
1205 if (MaxAddress
>= mDefaultMaximumAddress
) {
1206 Start
= CoreFindFreePagesI (mDefaultMaximumAddress
, 0, NoPages
, NewType
,
1207 Alignment
, NeedGuard
);
1209 if (Start
< mDefaultBaseAddress
) {
1210 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 (MaxAddress
, 0, NoPages
, NewType
, Alignment
,
1229 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1231 if (!PromoteMemoryResource ()) {
1236 // If any memory resources were promoted, then re-attempt the allocation
1238 return FindFreePages (MaxAddress
, NoPages
, NewType
, Alignment
, NeedGuard
);
1243 Allocates pages from the memory map.
1245 @param Type The type of allocation to perform
1246 @param MemoryType The type of memory to turn the allocated pages
1248 @param NumberOfPages The number of pages to allocate
1249 @param Memory A pointer to receive the base allocated memory
1251 @param NeedGuard Flag to indicate Guard page is needed or not
1253 @return Status. On success, Memory is filled in with the base address allocated
1254 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1256 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1257 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1258 @retval EFI_SUCCESS Pages successfully allocated.
1263 CoreInternalAllocatePages (
1264 IN EFI_ALLOCATE_TYPE Type
,
1265 IN EFI_MEMORY_TYPE MemoryType
,
1266 IN UINTN NumberOfPages
,
1267 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
1268 IN BOOLEAN NeedGuard
1273 UINT64 NumberOfBytes
;
1278 if ((UINT32
)Type
>= MaxAllocateType
) {
1279 return EFI_INVALID_PARAMETER
;
1282 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
< MEMORY_TYPE_OEM_RESERVED_MIN
) ||
1283 (MemoryType
== EfiConventionalMemory
) || (MemoryType
== EfiPersistentMemory
)) {
1284 return EFI_INVALID_PARAMETER
;
1287 if (Memory
== NULL
) {
1288 return EFI_INVALID_PARAMETER
;
1291 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1293 if (MemoryType
== EfiACPIReclaimMemory
||
1294 MemoryType
== EfiACPIMemoryNVS
||
1295 MemoryType
== EfiRuntimeServicesCode
||
1296 MemoryType
== EfiRuntimeServicesData
) {
1298 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1301 if (Type
== AllocateAddress
) {
1302 if ((*Memory
& (Alignment
- 1)) != 0) {
1303 return EFI_NOT_FOUND
;
1307 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1308 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1311 // If this is for below a particular address, then
1316 // The max address is the max natively addressable address for the processor
1318 MaxAddress
= MAX_ADDRESS
;
1321 // Check for Type AllocateAddress,
1322 // if NumberOfPages is 0 or
1323 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ADDRESS or
1324 // if (Start + NumberOfBytes) rolls over 0 or
1325 // if Start is above MAX_ADDRESS or
1326 // if End is above MAX_ADDRESS,
1327 // return EFI_NOT_FOUND.
1329 if (Type
== AllocateAddress
) {
1330 if ((NumberOfPages
== 0) ||
1331 (NumberOfPages
> RShiftU64 (MaxAddress
, EFI_PAGE_SHIFT
))) {
1332 return EFI_NOT_FOUND
;
1334 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1335 End
= Start
+ NumberOfBytes
- 1;
1337 if ((Start
>= End
) ||
1338 (Start
> MaxAddress
) ||
1339 (End
> MaxAddress
)) {
1340 return EFI_NOT_FOUND
;
1344 if (Type
== AllocateMaxAddress
) {
1348 CoreAcquireMemoryLock ();
1351 // If not a specific address, then find an address to allocate
1353 if (Type
!= AllocateAddress
) {
1354 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
,
1357 Status
= EFI_OUT_OF_RESOURCES
;
1363 // Convert pages from FreeMemory to the requested type
1366 Status
= CoreConvertPagesWithGuard(Start
, NumberOfPages
, MemoryType
);
1368 Status
= CoreConvertPages(Start
, NumberOfPages
, MemoryType
);
1372 CoreReleaseMemoryLock ();
1374 if (!EFI_ERROR (Status
)) {
1376 SetGuardForMemory (Start
, NumberOfPages
);
1385 Allocates pages from the memory map.
1387 @param Type The type of allocation to perform
1388 @param MemoryType The type of memory to turn the allocated pages
1390 @param NumberOfPages The number of pages to allocate
1391 @param Memory A pointer to receive the base allocated memory
1394 @return Status. On success, Memory is filled in with the base address allocated
1395 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1397 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1398 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1399 @retval EFI_SUCCESS Pages successfully allocated.
1405 IN EFI_ALLOCATE_TYPE Type
,
1406 IN EFI_MEMORY_TYPE MemoryType
,
1407 IN UINTN NumberOfPages
,
1408 OUT EFI_PHYSICAL_ADDRESS
*Memory
1414 NeedGuard
= IsPageTypeToGuard (MemoryType
, Type
) && !mOnGuarding
;
1415 Status
= CoreInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
,
1417 if (!EFI_ERROR (Status
)) {
1419 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
1420 MemoryProfileActionAllocatePages
,
1422 EFI_PAGES_TO_SIZE (NumberOfPages
),
1423 (VOID
*) (UINTN
) *Memory
,
1426 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1427 ApplyMemoryProtectionPolicy (EfiConventionalMemory
, MemoryType
, *Memory
,
1428 EFI_PAGES_TO_SIZE (NumberOfPages
));
1434 Frees previous allocated pages.
1436 @param Memory Base address of memory being freed
1437 @param NumberOfPages The number of pages to free
1438 @param MemoryType Pointer to memory type
1440 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1441 @retval EFI_INVALID_PARAMETER Address not aligned
1442 @return EFI_SUCCESS -Pages successfully freed.
1447 CoreInternalFreePages (
1448 IN EFI_PHYSICAL_ADDRESS Memory
,
1449 IN UINTN NumberOfPages
,
1450 OUT EFI_MEMORY_TYPE
*MemoryType OPTIONAL
1462 CoreAcquireMemoryLock ();
1465 // Find the entry that the covers the range
1469 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1470 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1471 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1475 if (Link
== &gMemoryMap
) {
1476 Status
= EFI_NOT_FOUND
;
1480 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1482 ASSERT (Entry
!= NULL
);
1483 if (Entry
->Type
== EfiACPIReclaimMemory
||
1484 Entry
->Type
== EfiACPIMemoryNVS
||
1485 Entry
->Type
== EfiRuntimeServicesCode
||
1486 Entry
->Type
== EfiRuntimeServicesData
) {
1488 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1492 if ((Memory
& (Alignment
- 1)) != 0) {
1493 Status
= EFI_INVALID_PARAMETER
;
1497 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1498 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1500 if (MemoryType
!= NULL
) {
1501 *MemoryType
= Entry
->Type
;
1504 IsGuarded
= IsPageTypeToGuard (Entry
->Type
, AllocateAnyPages
) &&
1505 IsMemoryGuarded (Memory
);
1507 Status
= CoreConvertPagesWithGuard (Memory
, NumberOfPages
,
1508 EfiConventionalMemory
);
1510 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1514 CoreReleaseMemoryLock ();
1516 UnsetGuardForMemory(Memory
, NumberOfPages
);
1522 Frees previous allocated pages.
1524 @param Memory Base address of memory being freed
1525 @param NumberOfPages The number of pages to free
1527 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1528 @retval EFI_INVALID_PARAMETER Address not aligned
1529 @return EFI_SUCCESS -Pages successfully freed.
1535 IN EFI_PHYSICAL_ADDRESS Memory
,
1536 IN UINTN NumberOfPages
1540 EFI_MEMORY_TYPE MemoryType
;
1542 Status
= CoreInternalFreePages (Memory
, NumberOfPages
, &MemoryType
);
1543 if (!EFI_ERROR (Status
)) {
1545 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
1546 MemoryProfileActionFreePages
,
1548 EFI_PAGES_TO_SIZE (NumberOfPages
),
1549 (VOID
*) (UINTN
) Memory
,
1552 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1553 ApplyMemoryProtectionPolicy (MemoryType
, EfiConventionalMemory
, Memory
,
1554 EFI_PAGES_TO_SIZE (NumberOfPages
));
1560 This function checks to see if the last memory map descriptor in a memory map
1561 can be merged with any of the other memory map descriptors in a memorymap.
1562 Memory descriptors may be merged if they are adjacent and have the same type
1565 @param MemoryMap A pointer to the start of the memory map.
1566 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1567 @param DescriptorSize The size, in bytes, of an individual
1568 EFI_MEMORY_DESCRIPTOR.
1570 @return A pointer to the next available descriptor in MemoryMap
1573 EFI_MEMORY_DESCRIPTOR
*
1574 MergeMemoryMapDescriptor (
1575 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1576 IN EFI_MEMORY_DESCRIPTOR
*MemoryMapDescriptor
,
1577 IN UINTN DescriptorSize
1581 // Traverse the array of descriptors in MemoryMap
1583 for (; MemoryMap
!= MemoryMapDescriptor
; MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
)) {
1585 // Check to see if the Type fields are identical.
1587 if (MemoryMap
->Type
!= MemoryMapDescriptor
->Type
) {
1592 // Check to see if the Attribute fields are identical.
1594 if (MemoryMap
->Attribute
!= MemoryMapDescriptor
->Attribute
) {
1599 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1601 if (MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1603 // Merge MemoryMapDescriptor into MemoryMap
1605 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1608 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1610 return MemoryMapDescriptor
;
1614 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1616 if (MemoryMap
->PhysicalStart
- EFI_PAGES_TO_SIZE ((UINTN
)MemoryMapDescriptor
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1618 // Merge MemoryMapDescriptor into MemoryMap
1620 MemoryMap
->PhysicalStart
= MemoryMapDescriptor
->PhysicalStart
;
1621 MemoryMap
->VirtualStart
= MemoryMapDescriptor
->VirtualStart
;
1622 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1625 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1627 return MemoryMapDescriptor
;
1632 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1634 // Return the slot immediately after MemoryMapDescriptor as the next available
1635 // slot in the MemoryMap array
1637 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor
, DescriptorSize
);
1641 This function returns a copy of the current memory map. The map is an array of
1642 memory descriptors, each of which describes a contiguous block of memory.
1644 @param MemoryMapSize A pointer to the size, in bytes, of the
1645 MemoryMap buffer. On input, this is the size of
1646 the buffer allocated by the caller. On output,
1647 it is the size of the buffer returned by the
1648 firmware if the buffer was large enough, or the
1649 size of the buffer needed to contain the map if
1650 the buffer was too small.
1651 @param MemoryMap A pointer to the buffer in which firmware places
1652 the current memory map.
1653 @param MapKey A pointer to the location in which firmware
1654 returns the key for the current memory map.
1655 @param DescriptorSize A pointer to the location in which firmware
1656 returns the size, in bytes, of an individual
1657 EFI_MEMORY_DESCRIPTOR.
1658 @param DescriptorVersion A pointer to the location in which firmware
1659 returns the version number associated with the
1660 EFI_MEMORY_DESCRIPTOR.
1662 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1664 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1665 buffer size needed to hold the memory map is
1666 returned in MemoryMapSize.
1667 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1673 IN OUT UINTN
*MemoryMapSize
,
1674 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1676 OUT UINTN
*DescriptorSize
,
1677 OUT UINT32
*DescriptorVersion
1683 UINTN NumberOfEntries
;
1686 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1687 EFI_GCD_MAP_ENTRY MergeGcdMapEntry
;
1688 EFI_MEMORY_TYPE Type
;
1689 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
1692 // Make sure the parameters are valid
1694 if (MemoryMapSize
== NULL
) {
1695 return EFI_INVALID_PARAMETER
;
1698 CoreAcquireGcdMemoryLock ();
1701 // Count the number of Reserved and runtime MMIO entries
1702 // And, count the number of Persistent entries.
1704 NumberOfEntries
= 0;
1705 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1706 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1707 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypePersistent
) ||
1708 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1709 ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1710 ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
))) {
1715 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1718 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1719 // prevent people from having pointer math bugs in their code.
1720 // now you have to use *DescriptorSize to make things work.
1722 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1724 if (DescriptorSize
!= NULL
) {
1725 *DescriptorSize
= Size
;
1728 if (DescriptorVersion
!= NULL
) {
1729 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1732 CoreAcquireMemoryLock ();
1735 // Compute the buffer size needed to fit the entire map
1737 BufferSize
= Size
* NumberOfEntries
;
1738 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1742 if (*MemoryMapSize
< BufferSize
) {
1743 Status
= EFI_BUFFER_TOO_SMALL
;
1747 if (MemoryMap
== NULL
) {
1748 Status
= EFI_INVALID_PARAMETER
;
1755 ZeroMem (MemoryMap
, BufferSize
);
1756 MemoryMapStart
= MemoryMap
;
1757 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1758 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1759 ASSERT (Entry
->VirtualStart
== 0);
1762 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1764 MemoryMap
->Type
= Entry
->Type
;
1765 MemoryMap
->PhysicalStart
= Entry
->Start
;
1766 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1767 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1769 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1770 // memory type bin and needs to be converted to the same memory type as the rest of the
1771 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1772 // improves the chances for a successful S4 resume in the presence of minor page allocation
1773 // differences across reboots.
1775 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1776 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
1777 if (mMemoryTypeStatistics
[Type
].Special
&&
1778 mMemoryTypeStatistics
[Type
].NumberOfPages
> 0 &&
1779 Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
&&
1780 Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
) {
1781 MemoryMap
->Type
= Type
;
1785 MemoryMap
->Attribute
= Entry
->Attribute
;
1786 if (MemoryMap
->Type
< EfiMaxMemoryType
) {
1787 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1788 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1793 // Check to see if the new Memory Map Descriptor can be merged with an
1794 // existing descriptor if they are adjacent and have the same attributes
1796 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1800 ZeroMem (&MergeGcdMapEntry
, sizeof (MergeGcdMapEntry
));
1802 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; ; Link
= Link
->ForwardLink
) {
1803 if (Link
!= &mGcdMemorySpaceMap
) {
1805 // Merge adjacent same type and attribute GCD memory range
1807 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1809 if ((MergeGcdMapEntry
.Capabilities
== GcdMapEntry
->Capabilities
) &&
1810 (MergeGcdMapEntry
.Attributes
== GcdMapEntry
->Attributes
) &&
1811 (MergeGcdMapEntry
.GcdMemoryType
== GcdMapEntry
->GcdMemoryType
) &&
1812 (MergeGcdMapEntry
.GcdIoType
== GcdMapEntry
->GcdIoType
)) {
1813 MergeGcdMapEntry
.EndAddress
= GcdMapEntry
->EndAddress
;
1818 if ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1819 ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1820 ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
))) {
1822 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1823 // it will be recorded as page PhysicalStart and NumberOfPages.
1825 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1826 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1829 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1831 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1832 MemoryMap
->VirtualStart
= 0;
1833 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1834 MemoryMap
->Attribute
= (MergeGcdMapEntry
.Attributes
& ~EFI_MEMORY_PORT_IO
) |
1835 (MergeGcdMapEntry
.Capabilities
& (EFI_MEMORY_RP
| EFI_MEMORY_WP
| EFI_MEMORY_XP
| EFI_MEMORY_RO
|
1836 EFI_MEMORY_UC
| EFI_MEMORY_UCE
| EFI_MEMORY_WC
| EFI_MEMORY_WT
| EFI_MEMORY_WB
));
1838 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1839 MemoryMap
->Type
= EfiReservedMemoryType
;
1840 } else if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1841 if ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1842 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1844 MemoryMap
->Type
= EfiMemoryMappedIO
;
1849 // Check to see if the new Memory Map Descriptor can be merged with an
1850 // existing descriptor if they are adjacent and have the same attributes
1852 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1855 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypePersistent
) {
1857 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1858 // it will be recorded as page PhysicalStart and NumberOfPages.
1860 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1861 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1864 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1866 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1867 MemoryMap
->VirtualStart
= 0;
1868 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1869 MemoryMap
->Attribute
= MergeGcdMapEntry
.Attributes
| EFI_MEMORY_NV
|
1870 (MergeGcdMapEntry
.Capabilities
& (EFI_MEMORY_RP
| EFI_MEMORY_WP
| EFI_MEMORY_XP
| EFI_MEMORY_RO
|
1871 EFI_MEMORY_UC
| EFI_MEMORY_UCE
| EFI_MEMORY_WC
| EFI_MEMORY_WT
| EFI_MEMORY_WB
));
1872 MemoryMap
->Type
= EfiPersistentMemory
;
1875 // Check to see if the new Memory Map Descriptor can be merged with an
1876 // existing descriptor if they are adjacent and have the same attributes
1878 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1880 if (Link
== &mGcdMemorySpaceMap
) {
1882 // break loop when arrive at head.
1886 if (GcdMapEntry
!= NULL
) {
1888 // Copy new GCD map entry for the following GCD range merge
1890 CopyMem (&MergeGcdMapEntry
, GcdMapEntry
, sizeof (MergeGcdMapEntry
));
1895 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1897 BufferSize
= ((UINT8
*)MemoryMap
- (UINT8
*)MemoryMapStart
);
1899 Status
= EFI_SUCCESS
;
1903 // Update the map key finally
1905 if (MapKey
!= NULL
) {
1906 *MapKey
= mMemoryMapKey
;
1909 CoreReleaseMemoryLock ();
1911 CoreReleaseGcdMemoryLock ();
1913 *MemoryMapSize
= BufferSize
;
1916 if (PcdGet8 (PcdHeapGuardPropertyMask
) & (BIT1
|BIT0
)) {
1917 DumpGuardedMemoryBitmap ();
1926 Internal function. Used by the pool functions to allocate pages
1927 to back pool allocation requests.
1929 @param PoolType The type of memory for the new pool pages
1930 @param NumberOfPages No of pages to allocate
1931 @param Alignment Bits to align.
1932 @param NeedGuard Flag to indicate Guard page is needed or not
1934 @return The allocated memory, or NULL
1938 CoreAllocatePoolPages (
1939 IN EFI_MEMORY_TYPE PoolType
,
1940 IN UINTN NumberOfPages
,
1942 IN BOOLEAN NeedGuard
1948 // Find the pages to convert
1950 Start
= FindFreePages (MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
,
1954 // Convert it to boot services data
1957 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32
)NumberOfPages
));
1960 CoreConvertPagesWithGuard (Start
, NumberOfPages
, PoolType
);
1962 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1966 return (VOID
*)(UINTN
) Start
;
1971 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1973 @param Memory The base address to free
1974 @param NumberOfPages The number of pages to free
1979 IN EFI_PHYSICAL_ADDRESS Memory
,
1980 IN UINTN NumberOfPages
1983 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1989 Make sure the memory map is following all the construction rules,
1990 it is the last time to check memory map error before exit boot services.
1992 @param MapKey Memory map key
1994 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1996 @retval EFI_SUCCESS Valid memory map.
2000 CoreTerminateMemoryMap (
2008 Status
= EFI_SUCCESS
;
2010 CoreAcquireMemoryLock ();
2012 if (MapKey
== mMemoryMapKey
) {
2015 // Make sure the memory map is following all the construction rules
2016 // This is the last chance we will be able to display any messages on
2017 // the console devices.
2020 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
2021 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
2022 if (Entry
->Type
< EfiMaxMemoryType
) {
2023 if (mMemoryTypeStatistics
[Entry
->Type
].Runtime
) {
2024 ASSERT (Entry
->Type
!= EfiACPIReclaimMemory
);
2025 ASSERT (Entry
->Type
!= EfiACPIMemoryNVS
);
2026 if ((Entry
->Start
& (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2027 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2028 Status
= EFI_INVALID_PARAMETER
;
2031 if (((Entry
->End
+ 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2032 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2033 Status
= EFI_INVALID_PARAMETER
;
2041 // The map key they gave us matches what we expect. Fall through and
2042 // return success. In an ideal world we would clear out all of
2043 // EfiBootServicesCode and EfiBootServicesData. However this function
2044 // is not the last one called by ExitBootServices(), so we have to
2045 // preserve the memory contents.
2048 Status
= EFI_INVALID_PARAMETER
;
2052 CoreReleaseMemoryLock ();