2 UEFI Memory page management functions.
4 Copyright (c) 2007 - 2018, 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_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
56 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
57 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
58 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
59 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
60 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
61 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
62 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
63 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
64 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
65 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
66 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
67 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
68 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
69 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiPersistentMemory
70 { 0, MAX_ALLOC_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
73 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= MAX_ALLOC_ADDRESS
;
74 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress
= MAX_ALLOC_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
;
407 EFI_PHYSICAL_ADDRESS StartAddress
;
408 EFI_PHYSICAL_ADDRESS EndAddress
;
409 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
411 DEBUG ((DEBUG_PAGE
, "Promote the memory resource\n"));
413 CoreAcquireGcdMemoryLock ();
416 Link
= mGcdMemorySpaceMap
.ForwardLink
;
417 while (Link
!= &mGcdMemorySpaceMap
) {
419 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
421 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
422 Entry
->EndAddress
< MAX_ALLOC_ADDRESS
&&
423 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
424 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
426 // Update the GCD map
428 if ((Entry
->Capabilities
& EFI_MEMORY_MORE_RELIABLE
) == EFI_MEMORY_MORE_RELIABLE
) {
429 Entry
->GcdMemoryType
= EfiGcdMemoryTypeMoreReliable
;
431 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
433 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
434 Entry
->ImageHandle
= gDxeCoreImageHandle
;
435 Entry
->DeviceHandle
= NULL
;
438 // Add to allocable system memory resource
442 EfiConventionalMemory
,
445 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
447 CoreFreeMemoryMapStack ();
452 Link
= Link
->ForwardLink
;
455 CoreReleaseGcdMemoryLock ();
459 // If freed-memory guard is enabled, we could promote pages from
460 // guarded free pages.
462 Promoted
= PromoteGuardedFreePages (&StartAddress
, &EndAddress
);
464 CoreGetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
466 EfiConventionalMemory
,
469 Descriptor
.Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
|
470 EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
478 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
479 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
480 size of boot time and runtime code.
484 CoreLoadingFixedAddressHook (
488 UINT32 RuntimeCodePageNumber
;
489 UINT32 BootTimeCodePageNumber
;
490 EFI_PHYSICAL_ADDRESS RuntimeCodeBase
;
491 EFI_PHYSICAL_ADDRESS BootTimeCodeBase
;
495 // Make sure these 2 areas are not initialzied.
497 if (!gLoadFixedAddressCodeMemoryReady
) {
498 RuntimeCodePageNumber
= PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber
);
499 BootTimeCodePageNumber
= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber
);
500 RuntimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(gLoadModuleAtFixAddressConfigurationTable
.DxeCodeTopAddress
- EFI_PAGES_TO_SIZE (RuntimeCodePageNumber
));
501 BootTimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(RuntimeCodeBase
- EFI_PAGES_TO_SIZE (BootTimeCodePageNumber
));
503 // Try to allocate runtime memory.
505 Status
= CoreAllocatePages (
507 EfiRuntimeServicesCode
,
508 RuntimeCodePageNumber
,
511 if (EFI_ERROR(Status
)) {
513 // Runtime memory allocation failed
518 // Try to allocate boot memory.
520 Status
= CoreAllocatePages (
523 BootTimeCodePageNumber
,
526 if (EFI_ERROR(Status
)) {
528 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
529 // new memory range is installed.
533 RuntimeCodePageNumber
537 gLoadFixedAddressCodeMemoryReady
= TRUE
;
543 Called to initialize the memory map and add descriptors to
544 the current descriptor list.
545 The first descriptor that is added must be general usable
546 memory as the addition allocates heap.
548 @param Type The type of memory to add
549 @param Start The starting address in the memory range Must be
551 @param NumberOfPages The number of pages in the range
552 @param Attribute Attributes of the memory to add
554 @return None. The range is added to the memory map
558 CoreAddMemoryDescriptor (
559 IN EFI_MEMORY_TYPE Type
,
560 IN EFI_PHYSICAL_ADDRESS Start
,
561 IN UINT64 NumberOfPages
,
565 EFI_PHYSICAL_ADDRESS End
;
570 if ((Start
& EFI_PAGE_MASK
) != 0) {
574 if (Type
>= EfiMaxMemoryType
&& Type
< MEMORY_TYPE_OEM_RESERVED_MIN
) {
577 CoreAcquireMemoryLock ();
578 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
579 CoreAddRange (Type
, Start
, End
, Attribute
);
580 CoreFreeMemoryMapStack ();
581 CoreReleaseMemoryLock ();
583 ApplyMemoryProtectionPolicy (EfiMaxMemoryType
, Type
, Start
,
584 LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
));
587 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
589 if (PcdGet64(PcdLoadModuleAtFixAddressEnable
) != 0) {
590 CoreLoadingFixedAddressHook();
594 // Check to see if the statistics for the different memory types have already been established
596 if (mMemoryTypeInformationInitialized
) {
602 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
604 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
606 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
608 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
609 if ((UINT32
)Type
> EfiMaxMemoryType
) {
612 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
614 // Allocate pages for the current memory type from the top of available memory
616 Status
= CoreAllocatePages (
619 gMemoryTypeInformation
[Index
].NumberOfPages
,
620 &mMemoryTypeStatistics
[Type
].BaseAddress
622 if (EFI_ERROR (Status
)) {
624 // If an error occurs allocating the pages for the current memory type, then
625 // free all the pages allocates for the previous memory types and return. This
626 // operation with be retied when/if more memory is added to the system
628 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
630 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
632 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
633 if ((UINT32
)Type
> EfiMaxMemoryType
) {
637 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
639 mMemoryTypeStatistics
[Type
].BaseAddress
,
640 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
642 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
643 mMemoryTypeStatistics
[Type
].MaximumAddress
= MAX_ALLOC_ADDRESS
;
650 // Compute the address at the top of the current statistics
652 mMemoryTypeStatistics
[Type
].MaximumAddress
=
653 mMemoryTypeStatistics
[Type
].BaseAddress
+
654 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
657 // If the current base address is the lowest address so far, then update the default
660 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
661 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
667 // There was enough system memory for all the the memory types were allocated. So,
668 // those memory areas can be freed for future allocations, and all future memory
669 // allocations can occur within their respective bins
671 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
673 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
675 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
676 if ((UINT32
)Type
> EfiMaxMemoryType
) {
679 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
681 mMemoryTypeStatistics
[Type
].BaseAddress
,
682 gMemoryTypeInformation
[Index
].NumberOfPages
684 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
685 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
690 // If the number of pages reserved for a memory type is 0, then all allocations for that type
691 // should be in the default range.
693 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
694 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
695 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
696 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
699 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
700 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== MAX_ALLOC_ADDRESS
) {
701 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
705 mMemoryTypeInformationInitialized
= TRUE
;
710 Internal function. Converts a memory range to the specified type or attributes.
711 The range must exist in the memory map. Either ChangingType or
712 ChangingAttributes must be set, but not both.
714 @param Start The first address of the range Must be page
716 @param NumberOfPages The number of pages to convert
717 @param ChangingType Boolean indicating that type value should be changed
718 @param NewType The new type for the memory range
719 @param ChangingAttributes Boolean indicating that attributes value should be changed
720 @param NewAttributes The new attributes for the memory range
722 @retval EFI_INVALID_PARAMETER Invalid parameter
723 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
724 range or convertion not allowed.
725 @retval EFI_SUCCESS Successfully converts the memory range to the
732 IN UINT64 NumberOfPages
,
733 IN BOOLEAN ChangingType
,
734 IN EFI_MEMORY_TYPE NewType
,
735 IN BOOLEAN ChangingAttributes
,
736 IN UINT64 NewAttributes
740 UINT64 NumberOfBytes
;
744 EFI_MEMORY_TYPE MemType
;
749 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
750 End
= Start
+ NumberOfBytes
- 1;
752 ASSERT (NumberOfPages
);
753 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
754 ASSERT (End
> Start
) ;
755 ASSERT_LOCKED (&gMemoryLock
);
756 ASSERT ( (ChangingType
== FALSE
) || (ChangingAttributes
== FALSE
) );
758 if (NumberOfPages
== 0 || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
>= End
)) {
759 return EFI_INVALID_PARAMETER
;
763 // Convert the entire range
766 while (Start
< End
) {
769 // Find the entry that the covers the range
771 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
772 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
774 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
779 if (Link
== &gMemoryMap
) {
780 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
781 return EFI_NOT_FOUND
;
785 // If we are converting the type of the range from EfiConventionalMemory to
786 // another type, we have to ensure that the entire range is covered by a
789 if (ChangingType
&& (NewType
!= EfiConventionalMemory
)) {
790 if (Entry
->End
< End
) {
791 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: range %lx - %lx covers multiple entries\n", Start
, End
));
792 return EFI_NOT_FOUND
;
796 // Convert range to the end, or to the end of the descriptor
797 // if that's all we've got
801 ASSERT (Entry
!= NULL
);
802 if (Entry
->End
< End
) {
803 RangeEnd
= Entry
->End
;
807 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to type %d\n", Start
, RangeEnd
, NewType
));
809 if (ChangingAttributes
) {
810 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to attr %lx\n", Start
, RangeEnd
, NewAttributes
));
815 // Debug code - verify conversion is allowed
817 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
818 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: Incompatible memory types, "));
819 if (Entry
->Type
== EfiConventionalMemory
) {
820 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to free have been freed\n"));
822 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "the pages to allocate have been allocated\n"));
824 return EFI_NOT_FOUND
;
828 // Update counters for the number of pages allocated to each memory type
830 if ((UINT32
)Entry
->Type
< EfiMaxMemoryType
) {
831 if ((Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) ||
832 (Start
>= mDefaultBaseAddress
&& Start
<= mDefaultMaximumAddress
) ) {
833 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
834 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
836 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
841 if ((UINT32
)NewType
< EfiMaxMemoryType
) {
842 if ((Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) ||
843 (Start
>= mDefaultBaseAddress
&& Start
<= mDefaultMaximumAddress
) ) {
844 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
845 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
> gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
846 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
853 // Pull range out of descriptor
855 if (Entry
->Start
== Start
) {
860 Entry
->Start
= RangeEnd
+ 1;
862 } else if (Entry
->End
== RangeEnd
) {
867 Entry
->End
= Start
- 1;
872 // Pull it out of the center, clip current
878 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
879 mMapStack
[mMapDepth
].FromPages
= FALSE
;
880 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
881 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
882 mMapStack
[mMapDepth
].End
= Entry
->End
;
885 // Inherit Attribute from the Memory Descriptor that is being clipped
887 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
889 Entry
->End
= Start
- 1;
890 ASSERT (Entry
->Start
< Entry
->End
);
892 Entry
= &mMapStack
[mMapDepth
];
893 InsertTailList (&gMemoryMap
, &Entry
->Link
);
896 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
900 // The new range inherits the same Attribute as the Entry
901 // it is being cut out of unless attributes are being changed
904 Attribute
= Entry
->Attribute
;
907 Attribute
= NewAttributes
;
908 MemType
= Entry
->Type
;
912 // If the descriptor is empty, then remove it from the map
914 if (Entry
->Start
== Entry
->End
+ 1) {
915 RemoveMemoryMapEntry (Entry
);
920 // Add our new range in. Don't do this for freed pages if freed-memory
923 if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED
) ||
925 MemType
!= EfiConventionalMemory
) {
926 CoreAddRange (MemType
, Start
, RangeEnd
, Attribute
);
929 if (ChangingType
&& (MemType
== EfiConventionalMemory
)) {
931 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
932 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
933 // that the page starting at address 0 is always filled with zeros.
936 if (RangeEnd
> EFI_PAGE_SIZE
) {
937 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
) EFI_PAGE_SIZE
, (UINTN
) (RangeEnd
- EFI_PAGE_SIZE
+ 1));
940 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
) Start
, (UINTN
) (RangeEnd
- Start
+ 1));
945 // Move any map descriptor stack to general pool
947 CoreFreeMemoryMapStack ();
950 // Bump the starting address, and convert the next range
952 Start
= RangeEnd
+ 1;
956 // Converted the whole range, done
964 Internal function. Converts a memory range to the specified type.
965 The range must exist in the memory map.
967 @param Start The first address of the range Must be page
969 @param NumberOfPages The number of pages to convert
970 @param NewType The new type for the memory range
972 @retval EFI_INVALID_PARAMETER Invalid parameter
973 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
974 range or convertion not allowed.
975 @retval EFI_SUCCESS Successfully converts the memory range to the
982 IN UINT64 NumberOfPages
,
983 IN EFI_MEMORY_TYPE NewType
986 return CoreConvertPagesEx(Start
, NumberOfPages
, TRUE
, NewType
, FALSE
, 0);
991 Internal function. Converts a memory range to use new attributes.
993 @param Start The first address of the range Must be page
995 @param NumberOfPages The number of pages to convert
996 @param NewAttributes The new attributes value for the range.
1000 CoreUpdateMemoryAttributes (
1001 IN EFI_PHYSICAL_ADDRESS Start
,
1002 IN UINT64 NumberOfPages
,
1003 IN UINT64 NewAttributes
1006 CoreAcquireMemoryLock ();
1009 // Update the attributes to the new value
1011 CoreConvertPagesEx(Start
, NumberOfPages
, FALSE
, (EFI_MEMORY_TYPE
)0, TRUE
, NewAttributes
);
1013 CoreReleaseMemoryLock ();
1018 Internal function. Finds a consecutive free page range below
1019 the requested address.
1021 @param MaxAddress The address that the range must be below
1022 @param MinAddress The address that the range must be above
1023 @param NumberOfPages Number of pages needed
1024 @param NewType The type of memory the range is going to be
1026 @param Alignment Bits to align with
1027 @param NeedGuard Flag to indicate Guard page is needed or not
1029 @return The base address of the range, or 0 if the range was not found
1033 CoreFindFreePagesI (
1034 IN UINT64 MaxAddress
,
1035 IN UINT64 MinAddress
,
1036 IN UINT64 NumberOfPages
,
1037 IN EFI_MEMORY_TYPE NewType
,
1039 IN BOOLEAN NeedGuard
1042 UINT64 NumberOfBytes
;
1046 UINT64 DescNumberOfBytes
;
1050 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
1054 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
1057 // If MaxAddress is not aligned to the end of a page
1061 // Change MaxAddress to be 1 page lower
1063 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
1066 // Set MaxAddress to a page boundary
1068 MaxAddress
&= ~(UINT64
)EFI_PAGE_MASK
;
1071 // Set MaxAddress to end of the page
1073 MaxAddress
|= EFI_PAGE_MASK
;
1076 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1079 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1080 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1083 // If it's not a free entry, don't bother with it
1085 if (Entry
->Type
!= EfiConventionalMemory
) {
1089 DescStart
= Entry
->Start
;
1090 DescEnd
= Entry
->End
;
1093 // If desc is past max allowed address or below min allowed address, skip it
1095 if ((DescStart
>= MaxAddress
) || (DescEnd
< MinAddress
)) {
1100 // If desc ends past max allowed address, clip the end
1102 if (DescEnd
>= MaxAddress
) {
1103 DescEnd
= MaxAddress
;
1106 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
1108 // Skip if DescEnd is less than DescStart after alignment clipping
1109 if (DescEnd
< DescStart
) {
1114 // Compute the number of bytes we can used from this
1115 // descriptor, and see it's enough to satisfy the request
1117 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
1119 if (DescNumberOfBytes
>= NumberOfBytes
) {
1121 // If the start of the allocated range is below the min address allowed, skip it
1123 if ((DescEnd
- NumberOfBytes
+ 1) < MinAddress
) {
1128 // If this is the best match so far remember it
1130 if (DescEnd
> Target
) {
1132 DescEnd
= AdjustMemoryS (
1133 DescEnd
+ 1 - DescNumberOfBytes
,
1148 // If this is a grow down, adjust target to be the allocation base
1150 Target
-= NumberOfBytes
- 1;
1153 // If we didn't find a match, return 0
1155 if ((Target
& EFI_PAGE_MASK
) != 0) {
1164 Internal function. Finds a consecutive free page range below
1165 the requested address
1167 @param MaxAddress The address that the range must be below
1168 @param NoPages Number of pages needed
1169 @param NewType The type of memory the range is going to be
1171 @param Alignment Bits to align with
1172 @param NeedGuard Flag to indicate Guard page is needed or not
1174 @return The base address of the range, or 0 if the range was not found.
1179 IN UINT64 MaxAddress
,
1181 IN EFI_MEMORY_TYPE NewType
,
1183 IN BOOLEAN NeedGuard
1189 // Attempt to find free pages in the preferred bin based on the requested memory type
1191 if ((UINT32
)NewType
< EfiMaxMemoryType
&& MaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1192 Start
= CoreFindFreePagesI (
1193 mMemoryTypeStatistics
[NewType
].MaximumAddress
,
1194 mMemoryTypeStatistics
[NewType
].BaseAddress
,
1206 // Attempt to find free pages in the default allocation bin
1208 if (MaxAddress
>= mDefaultMaximumAddress
) {
1209 Start
= CoreFindFreePagesI (mDefaultMaximumAddress
, 0, NoPages
, NewType
,
1210 Alignment
, NeedGuard
);
1212 if (Start
< mDefaultBaseAddress
) {
1213 mDefaultBaseAddress
= Start
;
1220 // The allocation did not succeed in any of the prefered bins even after
1221 // promoting resources. Attempt to find free pages anywhere is the requested
1222 // address range. If this allocation fails, then there are not enough
1223 // resources anywhere to satisfy the request.
1225 Start
= CoreFindFreePagesI (MaxAddress
, 0, NoPages
, NewType
, Alignment
,
1232 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1234 if (!PromoteMemoryResource ()) {
1239 // If any memory resources were promoted, then re-attempt the allocation
1241 return FindFreePages (MaxAddress
, NoPages
, NewType
, Alignment
, NeedGuard
);
1246 Allocates pages from the memory map.
1248 @param Type The type of allocation to perform
1249 @param MemoryType The type of memory to turn the allocated pages
1251 @param NumberOfPages The number of pages to allocate
1252 @param Memory A pointer to receive the base allocated memory
1254 @param NeedGuard Flag to indicate Guard page is needed or not
1256 @return Status. On success, Memory is filled in with the base address allocated
1257 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1259 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1260 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1261 @retval EFI_SUCCESS Pages successfully allocated.
1266 CoreInternalAllocatePages (
1267 IN EFI_ALLOCATE_TYPE Type
,
1268 IN EFI_MEMORY_TYPE MemoryType
,
1269 IN UINTN NumberOfPages
,
1270 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
1271 IN BOOLEAN NeedGuard
1276 UINT64 NumberOfBytes
;
1281 if ((UINT32
)Type
>= MaxAllocateType
) {
1282 return EFI_INVALID_PARAMETER
;
1285 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
< MEMORY_TYPE_OEM_RESERVED_MIN
) ||
1286 (MemoryType
== EfiConventionalMemory
) || (MemoryType
== EfiPersistentMemory
)) {
1287 return EFI_INVALID_PARAMETER
;
1290 if (Memory
== NULL
) {
1291 return EFI_INVALID_PARAMETER
;
1294 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1296 if (MemoryType
== EfiACPIReclaimMemory
||
1297 MemoryType
== EfiACPIMemoryNVS
||
1298 MemoryType
== EfiRuntimeServicesCode
||
1299 MemoryType
== EfiRuntimeServicesData
) {
1301 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1304 if (Type
== AllocateAddress
) {
1305 if ((*Memory
& (Alignment
- 1)) != 0) {
1306 return EFI_NOT_FOUND
;
1310 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1311 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1314 // If this is for below a particular address, then
1319 // The max address is the max natively addressable address for the processor
1321 MaxAddress
= MAX_ALLOC_ADDRESS
;
1324 // Check for Type AllocateAddress,
1325 // if NumberOfPages is 0 or
1326 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
1327 // if (Start + NumberOfBytes) rolls over 0 or
1328 // if Start is above MAX_ALLOC_ADDRESS or
1329 // if End is above MAX_ALLOC_ADDRESS,
1330 // return EFI_NOT_FOUND.
1332 if (Type
== AllocateAddress
) {
1333 if ((NumberOfPages
== 0) ||
1334 (NumberOfPages
> RShiftU64 (MaxAddress
, EFI_PAGE_SHIFT
))) {
1335 return EFI_NOT_FOUND
;
1337 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1338 End
= Start
+ NumberOfBytes
- 1;
1340 if ((Start
>= End
) ||
1341 (Start
> MaxAddress
) ||
1342 (End
> MaxAddress
)) {
1343 return EFI_NOT_FOUND
;
1347 if (Type
== AllocateMaxAddress
) {
1351 CoreAcquireMemoryLock ();
1354 // If not a specific address, then find an address to allocate
1356 if (Type
!= AllocateAddress
) {
1357 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
,
1360 Status
= EFI_OUT_OF_RESOURCES
;
1366 // Convert pages from FreeMemory to the requested type
1369 Status
= CoreConvertPagesWithGuard(Start
, NumberOfPages
, MemoryType
);
1371 Status
= CoreConvertPages(Start
, NumberOfPages
, MemoryType
);
1375 CoreReleaseMemoryLock ();
1377 if (!EFI_ERROR (Status
)) {
1379 SetGuardForMemory (Start
, NumberOfPages
);
1388 Allocates pages from the memory map.
1390 @param Type The type of allocation to perform
1391 @param MemoryType The type of memory to turn the allocated pages
1393 @param NumberOfPages The number of pages to allocate
1394 @param Memory A pointer to receive the base allocated memory
1397 @return Status. On success, Memory is filled in with the base address allocated
1398 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1400 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1401 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1402 @retval EFI_SUCCESS Pages successfully allocated.
1408 IN EFI_ALLOCATE_TYPE Type
,
1409 IN EFI_MEMORY_TYPE MemoryType
,
1410 IN UINTN NumberOfPages
,
1411 OUT EFI_PHYSICAL_ADDRESS
*Memory
1417 NeedGuard
= IsPageTypeToGuard (MemoryType
, Type
) && !mOnGuarding
;
1418 Status
= CoreInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
,
1420 if (!EFI_ERROR (Status
)) {
1422 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
1423 MemoryProfileActionAllocatePages
,
1425 EFI_PAGES_TO_SIZE (NumberOfPages
),
1426 (VOID
*) (UINTN
) *Memory
,
1429 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1430 ApplyMemoryProtectionPolicy (EfiConventionalMemory
, MemoryType
, *Memory
,
1431 EFI_PAGES_TO_SIZE (NumberOfPages
));
1437 Frees previous allocated pages.
1439 @param Memory Base address of memory being freed
1440 @param NumberOfPages The number of pages to free
1441 @param MemoryType Pointer to memory type
1443 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1444 @retval EFI_INVALID_PARAMETER Address not aligned
1445 @return EFI_SUCCESS -Pages successfully freed.
1450 CoreInternalFreePages (
1451 IN EFI_PHYSICAL_ADDRESS Memory
,
1452 IN UINTN NumberOfPages
,
1453 OUT EFI_MEMORY_TYPE
*MemoryType OPTIONAL
1465 CoreAcquireMemoryLock ();
1468 // Find the entry that the covers the range
1472 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1473 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1474 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1478 if (Link
== &gMemoryMap
) {
1479 Status
= EFI_NOT_FOUND
;
1483 Alignment
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
1485 ASSERT (Entry
!= NULL
);
1486 if (Entry
->Type
== EfiACPIReclaimMemory
||
1487 Entry
->Type
== EfiACPIMemoryNVS
||
1488 Entry
->Type
== EfiRuntimeServicesCode
||
1489 Entry
->Type
== EfiRuntimeServicesData
) {
1491 Alignment
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
1495 if ((Memory
& (Alignment
- 1)) != 0) {
1496 Status
= EFI_INVALID_PARAMETER
;
1500 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1501 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1503 if (MemoryType
!= NULL
) {
1504 *MemoryType
= Entry
->Type
;
1507 IsGuarded
= IsPageTypeToGuard (Entry
->Type
, AllocateAnyPages
) &&
1508 IsMemoryGuarded (Memory
);
1510 Status
= CoreConvertPagesWithGuard (Memory
, NumberOfPages
,
1511 EfiConventionalMemory
);
1513 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1517 CoreReleaseMemoryLock ();
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
)) {
1544 GuardFreedPagesChecked (Memory
, NumberOfPages
);
1546 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
1547 MemoryProfileActionFreePages
,
1549 EFI_PAGES_TO_SIZE (NumberOfPages
),
1550 (VOID
*) (UINTN
) Memory
,
1553 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType
);
1554 ApplyMemoryProtectionPolicy (MemoryType
, EfiConventionalMemory
, Memory
,
1555 EFI_PAGES_TO_SIZE (NumberOfPages
));
1561 This function checks to see if the last memory map descriptor in a memory map
1562 can be merged with any of the other memory map descriptors in a memorymap.
1563 Memory descriptors may be merged if they are adjacent and have the same type
1566 @param MemoryMap A pointer to the start of the memory map.
1567 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1568 @param DescriptorSize The size, in bytes, of an individual
1569 EFI_MEMORY_DESCRIPTOR.
1571 @return A pointer to the next available descriptor in MemoryMap
1574 EFI_MEMORY_DESCRIPTOR
*
1575 MergeMemoryMapDescriptor (
1576 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1577 IN EFI_MEMORY_DESCRIPTOR
*MemoryMapDescriptor
,
1578 IN UINTN DescriptorSize
1582 // Traverse the array of descriptors in MemoryMap
1584 for (; MemoryMap
!= MemoryMapDescriptor
; MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
)) {
1586 // Check to see if the Type fields are identical.
1588 if (MemoryMap
->Type
!= MemoryMapDescriptor
->Type
) {
1593 // Check to see if the Attribute fields are identical.
1595 if (MemoryMap
->Attribute
!= MemoryMapDescriptor
->Attribute
) {
1600 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1602 if (MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1604 // Merge MemoryMapDescriptor into MemoryMap
1606 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1609 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1611 return MemoryMapDescriptor
;
1615 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1617 if (MemoryMap
->PhysicalStart
- EFI_PAGES_TO_SIZE ((UINTN
)MemoryMapDescriptor
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1619 // Merge MemoryMapDescriptor into MemoryMap
1621 MemoryMap
->PhysicalStart
= MemoryMapDescriptor
->PhysicalStart
;
1622 MemoryMap
->VirtualStart
= MemoryMapDescriptor
->VirtualStart
;
1623 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1626 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1628 return MemoryMapDescriptor
;
1633 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1635 // Return the slot immediately after MemoryMapDescriptor as the next available
1636 // slot in the MemoryMap array
1638 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor
, DescriptorSize
);
1642 This function returns a copy of the current memory map. The map is an array of
1643 memory descriptors, each of which describes a contiguous block of memory.
1645 @param MemoryMapSize A pointer to the size, in bytes, of the
1646 MemoryMap buffer. On input, this is the size of
1647 the buffer allocated by the caller. On output,
1648 it is the size of the buffer returned by the
1649 firmware if the buffer was large enough, or the
1650 size of the buffer needed to contain the map if
1651 the buffer was too small.
1652 @param MemoryMap A pointer to the buffer in which firmware places
1653 the current memory map.
1654 @param MapKey A pointer to the location in which firmware
1655 returns the key for the current memory map.
1656 @param DescriptorSize A pointer to the location in which firmware
1657 returns the size, in bytes, of an individual
1658 EFI_MEMORY_DESCRIPTOR.
1659 @param DescriptorVersion A pointer to the location in which firmware
1660 returns the version number associated with the
1661 EFI_MEMORY_DESCRIPTOR.
1663 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1665 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1666 buffer size needed to hold the memory map is
1667 returned in MemoryMapSize.
1668 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1674 IN OUT UINTN
*MemoryMapSize
,
1675 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1677 OUT UINTN
*DescriptorSize
,
1678 OUT UINT32
*DescriptorVersion
1684 UINTN NumberOfEntries
;
1687 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1688 EFI_GCD_MAP_ENTRY MergeGcdMapEntry
;
1689 EFI_MEMORY_TYPE Type
;
1690 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
1691 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1694 // Make sure the parameters are valid
1696 if (MemoryMapSize
== NULL
) {
1697 return EFI_INVALID_PARAMETER
;
1700 CoreAcquireGcdMemoryLock ();
1703 // Count the number of Reserved and runtime MMIO entries
1704 // And, count the number of Persistent entries.
1706 NumberOfEntries
= 0;
1707 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1708 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1709 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypePersistent
) ||
1710 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1711 ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1712 ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
))) {
1717 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1720 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1721 // prevent people from having pointer math bugs in their code.
1722 // now you have to use *DescriptorSize to make things work.
1724 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1726 if (DescriptorSize
!= NULL
) {
1727 *DescriptorSize
= Size
;
1730 if (DescriptorVersion
!= NULL
) {
1731 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1734 CoreAcquireMemoryLock ();
1737 // Compute the buffer size needed to fit the entire map
1739 BufferSize
= Size
* NumberOfEntries
;
1740 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1744 if (*MemoryMapSize
< BufferSize
) {
1745 Status
= EFI_BUFFER_TOO_SMALL
;
1749 if (MemoryMap
== NULL
) {
1750 Status
= EFI_INVALID_PARAMETER
;
1757 ZeroMem (MemoryMap
, BufferSize
);
1758 MemoryMapStart
= MemoryMap
;
1759 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1760 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1761 ASSERT (Entry
->VirtualStart
== 0);
1764 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1766 MemoryMap
->Type
= Entry
->Type
;
1767 MemoryMap
->PhysicalStart
= Entry
->Start
;
1768 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1769 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1771 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1772 // memory type bin and needs to be converted to the same memory type as the rest of the
1773 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1774 // improves the chances for a successful S4 resume in the presence of minor page allocation
1775 // differences across reboots.
1777 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1778 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
1779 if (mMemoryTypeStatistics
[Type
].Special
&&
1780 mMemoryTypeStatistics
[Type
].NumberOfPages
> 0 &&
1781 Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
&&
1782 Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
) {
1783 MemoryMap
->Type
= Type
;
1787 MemoryMap
->Attribute
= Entry
->Attribute
;
1788 if (MemoryMap
->Type
< EfiMaxMemoryType
) {
1789 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1790 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1795 // Check to see if the new Memory Map Descriptor can be merged with an
1796 // existing descriptor if they are adjacent and have the same attributes
1798 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1802 ZeroMem (&MergeGcdMapEntry
, sizeof (MergeGcdMapEntry
));
1804 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; ; Link
= Link
->ForwardLink
) {
1805 if (Link
!= &mGcdMemorySpaceMap
) {
1807 // Merge adjacent same type and attribute GCD memory range
1809 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1811 if ((MergeGcdMapEntry
.Capabilities
== GcdMapEntry
->Capabilities
) &&
1812 (MergeGcdMapEntry
.Attributes
== GcdMapEntry
->Attributes
) &&
1813 (MergeGcdMapEntry
.GcdMemoryType
== GcdMapEntry
->GcdMemoryType
) &&
1814 (MergeGcdMapEntry
.GcdIoType
== GcdMapEntry
->GcdIoType
)) {
1815 MergeGcdMapEntry
.EndAddress
= GcdMapEntry
->EndAddress
;
1820 if ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1821 ((MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1822 ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
))) {
1824 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1825 // it will be recorded as page PhysicalStart and NumberOfPages.
1827 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1828 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1831 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1833 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1834 MemoryMap
->VirtualStart
= 0;
1835 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1836 MemoryMap
->Attribute
= (MergeGcdMapEntry
.Attributes
& ~EFI_MEMORY_PORT_IO
) |
1837 (MergeGcdMapEntry
.Capabilities
& (EFI_MEMORY_RP
| EFI_MEMORY_WP
| EFI_MEMORY_XP
| EFI_MEMORY_RO
|
1838 EFI_MEMORY_UC
| EFI_MEMORY_UCE
| EFI_MEMORY_WC
| EFI_MEMORY_WT
| EFI_MEMORY_WB
));
1840 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1841 MemoryMap
->Type
= EfiReservedMemoryType
;
1842 } else if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1843 if ((MergeGcdMapEntry
.Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1844 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1846 MemoryMap
->Type
= EfiMemoryMappedIO
;
1851 // Check to see if the new Memory Map Descriptor can be merged with an
1852 // existing descriptor if they are adjacent and have the same attributes
1854 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1857 if (MergeGcdMapEntry
.GcdMemoryType
== EfiGcdMemoryTypePersistent
) {
1859 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1860 // it will be recorded as page PhysicalStart and NumberOfPages.
1862 ASSERT ((MergeGcdMapEntry
.BaseAddress
& EFI_PAGE_MASK
) == 0);
1863 ASSERT (((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1) & EFI_PAGE_MASK
) == 0);
1866 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1868 MemoryMap
->PhysicalStart
= MergeGcdMapEntry
.BaseAddress
;
1869 MemoryMap
->VirtualStart
= 0;
1870 MemoryMap
->NumberOfPages
= RShiftU64 ((MergeGcdMapEntry
.EndAddress
- MergeGcdMapEntry
.BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1871 MemoryMap
->Attribute
= MergeGcdMapEntry
.Attributes
| EFI_MEMORY_NV
|
1872 (MergeGcdMapEntry
.Capabilities
& (EFI_MEMORY_RP
| EFI_MEMORY_WP
| EFI_MEMORY_XP
| EFI_MEMORY_RO
|
1873 EFI_MEMORY_UC
| EFI_MEMORY_UCE
| EFI_MEMORY_WC
| EFI_MEMORY_WT
| EFI_MEMORY_WB
));
1874 MemoryMap
->Type
= EfiPersistentMemory
;
1877 // Check to see if the new Memory Map Descriptor can be merged with an
1878 // existing descriptor if they are adjacent and have the same attributes
1880 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1882 if (Link
== &mGcdMemorySpaceMap
) {
1884 // break loop when arrive at head.
1888 if (GcdMapEntry
!= NULL
) {
1890 // Copy new GCD map entry for the following GCD range merge
1892 CopyMem (&MergeGcdMapEntry
, GcdMapEntry
, sizeof (MergeGcdMapEntry
));
1897 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1899 BufferSize
= ((UINT8
*)MemoryMap
- (UINT8
*)MemoryMapStart
);
1902 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1903 // set attributes and change memory paging attribute accordingly.
1904 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1905 // value from Capabilities in GCD memory map. This might cause
1906 // boot problems. Clearing all paging related capabilities can
1907 // workaround it. Following code is supposed to be removed once
1908 // the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in
1909 // UEFI spec and adopted by both EDK-II Core and all supported
1912 MemoryMapEnd
= MemoryMap
;
1913 MemoryMap
= MemoryMapStart
;
1914 while (MemoryMap
< MemoryMapEnd
) {
1915 MemoryMap
->Attribute
&= ~(UINT64
)(EFI_MEMORY_RP
| EFI_MEMORY_RO
|
1917 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, Size
);
1919 MergeMemoryMap (MemoryMapStart
, &BufferSize
, Size
);
1920 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MemoryMapStart
+ BufferSize
);
1922 Status
= EFI_SUCCESS
;
1926 // Update the map key finally
1928 if (MapKey
!= NULL
) {
1929 *MapKey
= mMemoryMapKey
;
1932 CoreReleaseMemoryLock ();
1934 CoreReleaseGcdMemoryLock ();
1936 *MemoryMapSize
= BufferSize
;
1939 DumpGuardedMemoryBitmap ();
1947 Internal function. Used by the pool functions to allocate pages
1948 to back pool allocation requests.
1950 @param PoolType The type of memory for the new pool pages
1951 @param NumberOfPages No of pages to allocate
1952 @param Alignment Bits to align.
1953 @param NeedGuard Flag to indicate Guard page is needed or not
1955 @return The allocated memory, or NULL
1959 CoreAllocatePoolPages (
1960 IN EFI_MEMORY_TYPE PoolType
,
1961 IN UINTN NumberOfPages
,
1963 IN BOOLEAN NeedGuard
1969 // Find the pages to convert
1971 Start
= FindFreePages (MAX_ALLOC_ADDRESS
, NumberOfPages
, PoolType
, Alignment
,
1975 // Convert it to boot services data
1978 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32
)NumberOfPages
));
1981 CoreConvertPagesWithGuard (Start
, NumberOfPages
, PoolType
);
1983 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1987 return (VOID
*)(UINTN
) Start
;
1992 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1994 @param Memory The base address to free
1995 @param NumberOfPages The number of pages to free
2000 IN EFI_PHYSICAL_ADDRESS Memory
,
2001 IN UINTN NumberOfPages
2004 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
2010 Make sure the memory map is following all the construction rules,
2011 it is the last time to check memory map error before exit boot services.
2013 @param MapKey Memory map key
2015 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2017 @retval EFI_SUCCESS Valid memory map.
2021 CoreTerminateMemoryMap (
2029 Status
= EFI_SUCCESS
;
2031 CoreAcquireMemoryLock ();
2033 if (MapKey
== mMemoryMapKey
) {
2036 // Make sure the memory map is following all the construction rules
2037 // This is the last chance we will be able to display any messages on
2038 // the console devices.
2041 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
2042 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
2043 if (Entry
->Type
< EfiMaxMemoryType
) {
2044 if (mMemoryTypeStatistics
[Entry
->Type
].Runtime
) {
2045 ASSERT (Entry
->Type
!= EfiACPIReclaimMemory
);
2046 ASSERT (Entry
->Type
!= EfiACPIMemoryNVS
);
2047 if ((Entry
->Start
& (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2048 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2049 Status
= EFI_INVALID_PARAMETER
;
2052 if (((Entry
->End
+ 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY
- 1)) != 0) {
2053 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2054 Status
= EFI_INVALID_PARAMETER
;
2062 // The map key they gave us matches what we expect. Fall through and
2063 // return success. In an ideal world we would clear out all of
2064 // EfiBootServicesCode and EfiBootServicesData. However this function
2065 // is not the last one called by ExitBootServices(), so we have to
2066 // preserve the memory contents.
2069 Status
= EFI_INVALID_PARAMETER
;
2073 CoreReleaseMemoryLock ();