2 UEFI Memory page management functions.
4 Copyright (c) 2007 - 2015, 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.
18 #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
21 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
24 EFI_PHYSICAL_ADDRESS BaseAddress
;
25 EFI_PHYSICAL_ADDRESS MaximumAddress
;
26 UINT64 CurrentNumberOfPages
;
28 UINTN InformationIndex
;
31 } EFI_MEMORY_TYPE_STATISTICS
;
34 // MemoryMap - The current memory map
36 UINTN mMemoryMapKey
= 0;
38 #define MAX_MAP_DEPTH 6
41 /// mMapDepth - depth of new descriptor stack
45 /// mMapStack - space to use as temp storage to build new map descriptors
47 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
48 UINTN mFreeMapStack
= 0;
50 /// This list maintain the free memory map list
52 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
53 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
55 EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
56 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
57 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
58 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
59 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
60 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
61 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
62 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
63 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
64 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
65 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
66 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
67 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
68 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
69 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
70 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiPersistentMemory
71 { 0, MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
74 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= MAX_ADDRESS
;
75 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress
= MAX_ADDRESS
;
77 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
78 { EfiReservedMemoryType
, 0 },
81 { EfiBootServicesCode
, 0 },
82 { EfiBootServicesData
, 0 },
83 { EfiRuntimeServicesCode
, 0 },
84 { EfiRuntimeServicesData
, 0 },
85 { EfiConventionalMemory
, 0 },
86 { EfiUnusableMemory
, 0 },
87 { EfiACPIReclaimMemory
, 0 },
88 { EfiACPIMemoryNVS
, 0 },
89 { EfiMemoryMappedIO
, 0 },
90 { EfiMemoryMappedIOPortSpace
, 0 },
92 { EfiPersistentMemory
, 0 },
93 { EfiMaxMemoryType
, 0 }
96 // Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
97 // and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
98 // address assigned by DXE core.
100 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady
= FALSE
;
103 Enter critical section by gaining lock on gMemoryLock.
107 CoreAcquireMemoryLock (
111 CoreAcquireLock (&gMemoryLock
);
117 Exit critical section by releasing lock on gMemoryLock.
121 CoreReleaseMemoryLock (
125 CoreReleaseLock (&gMemoryLock
);
132 Internal function. Removes a descriptor entry.
134 @param Entry The entry to remove
138 RemoveMemoryMapEntry (
139 IN OUT MEMORY_MAP
*Entry
142 RemoveEntryList (&Entry
->Link
);
143 Entry
->Link
.ForwardLink
= NULL
;
145 if (Entry
->FromPages
) {
147 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
149 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
154 Internal function. Adds a ranges to the memory map.
155 The range must not already exist in the map.
157 @param Type The type of memory range to add
158 @param Start The starting address in the memory range Must be
160 @param End The last address in the range Must be the last
162 @param Attribute The attributes of the memory range to add
167 IN EFI_MEMORY_TYPE Type
,
168 IN EFI_PHYSICAL_ADDRESS Start
,
169 IN EFI_PHYSICAL_ADDRESS End
,
176 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
177 ASSERT (End
> Start
) ;
179 ASSERT_LOCKED (&gMemoryLock
);
181 DEBUG ((DEBUG_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
184 // If memory of type EfiConventionalMemory is being added that includes the page
185 // starting at address 0, then zero the page starting at address 0. This has
186 // two benifits. It helps find NULL pointer bugs and it also maximizes
187 // compatibility with operating systems that may evaluate memory in this page
188 // for legacy data structures. If memory of any other type is added starting
189 // at address 0, then do not zero the page at address 0 because the page is being
190 // used for other purposes.
192 if (Type
== EfiConventionalMemory
&& Start
== 0 && (End
>= EFI_PAGE_SIZE
- 1)) {
193 SetMem ((VOID
*)(UINTN
)Start
, EFI_PAGE_SIZE
, 0);
197 // Memory map being altered so updated key
202 // UEFI 2.0 added an event group for notificaiton on memory map changes.
203 // So we need to signal this Event Group every time the memory map changes.
204 // If we are in EFI 1.10 compatability mode no event groups will be
205 // found and nothing will happen we we call this function. These events
206 // will get signaled but since a lock is held around the call to this
207 // function the notificaiton events will only be called after this funciton
208 // returns and the lock is released.
210 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
213 // Look for adjoining memory descriptor
216 // Two memory descriptors can only be merged if they have the same Type
217 // and the same Attribute
220 Link
= gMemoryMap
.ForwardLink
;
221 while (Link
!= &gMemoryMap
) {
222 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
223 Link
= Link
->ForwardLink
;
225 if (Entry
->Type
!= Type
) {
229 if (Entry
->Attribute
!= Attribute
) {
233 if (Entry
->End
+ 1 == Start
) {
235 Start
= Entry
->Start
;
236 RemoveMemoryMapEntry (Entry
);
238 } else if (Entry
->Start
== End
+ 1) {
241 RemoveMemoryMapEntry (Entry
);
249 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
250 mMapStack
[mMapDepth
].FromPages
= FALSE
;
251 mMapStack
[mMapDepth
].Type
= Type
;
252 mMapStack
[mMapDepth
].Start
= Start
;
253 mMapStack
[mMapDepth
].End
= End
;
254 mMapStack
[mMapDepth
].VirtualStart
= 0;
255 mMapStack
[mMapDepth
].Attribute
= Attribute
;
256 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
259 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
265 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
266 If the list is emtry, then allocate a new page to refuel the list.
267 Please Note this algorithm to allocate the memory map descriptor has a property
268 that the memory allocated for memory entries always grows, and will never really be freed
269 For example, if the current boot uses 2000 memory map entries at the maximum point, but
270 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
271 memory map entries is still allocated from EfiBootServicesMemory.
274 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
278 AllocateMemoryMapEntry (
282 MEMORY_MAP
* FreeDescriptorEntries
;
286 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
288 // The list is empty, to allocate one page to refuel the list
290 FreeDescriptorEntries
= CoreAllocatePoolPages (EfiBootServicesData
, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
291 if(FreeDescriptorEntries
!= NULL
) {
293 // Enque the free memmory map entries into the list
295 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION
/ sizeof(MEMORY_MAP
); Index
++) {
296 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
297 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
304 // dequeue the first descriptor from the list
306 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
307 RemoveEntryList (&Entry
->Link
);
314 Internal function. Moves any memory descriptors that are on the
315 temporary descriptor stack to heap.
319 CoreFreeMemoryMapStack (
327 ASSERT_LOCKED (&gMemoryLock
);
330 // If already freeing the map stack, then return
332 if (mFreeMapStack
!= 0) {
337 // Move the temporary memory descriptor stack into pool
341 while (mMapDepth
!= 0) {
343 // Deque an memory map entry from mFreeMemoryMapEntryList
345 Entry
= AllocateMemoryMapEntry ();
350 // Update to proper entry
354 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
357 // Move this entry to general memory
359 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
360 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
362 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
363 Entry
->FromPages
= TRUE
;
366 // Find insertion location
368 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
369 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
370 if (Entry2
->FromPages
&& Entry2
->Start
> Entry
->Start
) {
375 InsertTailList (Link2
, &Entry
->Link
);
379 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
380 // so here no need to move it to memory.
382 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
390 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
394 PromoteMemoryResource (
399 EFI_GCD_MAP_ENTRY
*Entry
;
402 DEBUG ((DEBUG_PAGE
, "Promote the memory resource\n"));
404 CoreAcquireGcdMemoryLock ();
407 Link
= mGcdMemorySpaceMap
.ForwardLink
;
408 while (Link
!= &mGcdMemorySpaceMap
) {
410 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
412 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
413 Entry
->EndAddress
< MAX_ADDRESS
&&
414 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
415 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
417 // Update the GCD map
419 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
420 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
421 Entry
->ImageHandle
= gDxeCoreImageHandle
;
422 Entry
->DeviceHandle
= NULL
;
425 // Add to allocable system memory resource
429 EfiConventionalMemory
,
432 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
434 CoreFreeMemoryMapStack ();
439 Link
= Link
->ForwardLink
;
442 CoreReleaseGcdMemoryLock ();
447 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
448 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
449 size of boot time and runtime code.
453 CoreLoadingFixedAddressHook (
457 UINT32 RuntimeCodePageNumber
;
458 UINT32 BootTimeCodePageNumber
;
459 EFI_PHYSICAL_ADDRESS RuntimeCodeBase
;
460 EFI_PHYSICAL_ADDRESS BootTimeCodeBase
;
464 // Make sure these 2 areas are not initialzied.
466 if (!gLoadFixedAddressCodeMemoryReady
) {
467 RuntimeCodePageNumber
= PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber
);
468 BootTimeCodePageNumber
= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber
);
469 RuntimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(gLoadModuleAtFixAddressConfigurationTable
.DxeCodeTopAddress
- EFI_PAGES_TO_SIZE (RuntimeCodePageNumber
));
470 BootTimeCodeBase
= (EFI_PHYSICAL_ADDRESS
)(RuntimeCodeBase
- EFI_PAGES_TO_SIZE (BootTimeCodePageNumber
));
472 // Try to allocate runtime memory.
474 Status
= CoreAllocatePages (
476 EfiRuntimeServicesCode
,
477 RuntimeCodePageNumber
,
480 if (EFI_ERROR(Status
)) {
482 // Runtime memory allocation failed
487 // Try to allocate boot memory.
489 Status
= CoreAllocatePages (
492 BootTimeCodePageNumber
,
495 if (EFI_ERROR(Status
)) {
497 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
498 // new memory range is installed.
502 RuntimeCodePageNumber
506 gLoadFixedAddressCodeMemoryReady
= TRUE
;
512 Called to initialize the memory map and add descriptors to
513 the current descriptor list.
514 The first descriptor that is added must be general usable
515 memory as the addition allocates heap.
517 @param Type The type of memory to add
518 @param Start The starting address in the memory range Must be
520 @param NumberOfPages The number of pages in the range
521 @param Attribute Attributes of the memory to add
523 @return None. The range is added to the memory map
527 CoreAddMemoryDescriptor (
528 IN EFI_MEMORY_TYPE Type
,
529 IN EFI_PHYSICAL_ADDRESS Start
,
530 IN UINT64 NumberOfPages
,
534 EFI_PHYSICAL_ADDRESS End
;
539 if ((Start
& EFI_PAGE_MASK
) != 0) {
543 if (Type
>= EfiMaxMemoryType
&& Type
<= 0x7fffffff) {
546 CoreAcquireMemoryLock ();
547 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
548 CoreAddRange (Type
, Start
, End
, Attribute
);
549 CoreFreeMemoryMapStack ();
550 CoreReleaseMemoryLock ();
553 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
555 if (PcdGet64(PcdLoadModuleAtFixAddressEnable
) != 0) {
556 CoreLoadingFixedAddressHook();
560 // Check to see if the statistics for the different memory types have already been established
562 if (mMemoryTypeInformationInitialized
) {
568 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
570 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
572 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
574 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
575 if ((UINT32
)Type
> EfiMaxMemoryType
) {
578 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
580 // Allocate pages for the current memory type from the top of available memory
582 Status
= CoreAllocatePages (
585 gMemoryTypeInformation
[Index
].NumberOfPages
,
586 &mMemoryTypeStatistics
[Type
].BaseAddress
588 if (EFI_ERROR (Status
)) {
590 // If an error occurs allocating the pages for the current memory type, then
591 // free all the pages allocates for the previous memory types and return. This
592 // operation with be retied when/if more memory is added to the system
594 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
596 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
598 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
599 if ((UINT32
)Type
> EfiMaxMemoryType
) {
603 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
605 mMemoryTypeStatistics
[Type
].BaseAddress
,
606 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
608 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
609 mMemoryTypeStatistics
[Type
].MaximumAddress
= MAX_ADDRESS
;
616 // Compute the address at the top of the current statistics
618 mMemoryTypeStatistics
[Type
].MaximumAddress
=
619 mMemoryTypeStatistics
[Type
].BaseAddress
+
620 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
623 // If the current base address is the lowest address so far, then update the default
626 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
627 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
633 // There was enough system memory for all the the memory types were allocated. So,
634 // those memory areas can be freed for future allocations, and all future memory
635 // allocations can occur within their respective bins
637 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
639 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
641 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
642 if ((UINT32
)Type
> EfiMaxMemoryType
) {
645 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
647 mMemoryTypeStatistics
[Type
].BaseAddress
,
648 gMemoryTypeInformation
[Index
].NumberOfPages
650 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
651 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
656 // If the number of pages reserved for a memory type is 0, then all allocations for that type
657 // should be in the default range.
659 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
660 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
661 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
662 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
665 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
666 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== MAX_ADDRESS
) {
667 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
671 mMemoryTypeInformationInitialized
= TRUE
;
676 Internal function. Converts a memory range to the specified type or attributes.
677 The range must exist in the memory map. Either ChangingType or
678 ChangingAttributes must be set, but not both.
680 @param Start The first address of the range Must be page
682 @param NumberOfPages The number of pages to convert
683 @param ChangingType Boolean indicating that type value should be changed
684 @param NewType The new type for the memory range
685 @param ChangingAttributes Boolean indicating that attributes value should be changed
686 @param NewAttributes The new attributes for the memory range
688 @retval EFI_INVALID_PARAMETER Invalid parameter
689 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
690 range or convertion not allowed.
691 @retval EFI_SUCCESS Successfully converts the memory range to the
698 IN UINT64 NumberOfPages
,
699 IN BOOLEAN ChangingType
,
700 IN EFI_MEMORY_TYPE NewType
,
701 IN BOOLEAN ChangingAttributes
,
702 IN UINT64 NewAttributes
706 UINT64 NumberOfBytes
;
710 EFI_MEMORY_TYPE MemType
;
715 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
716 End
= Start
+ NumberOfBytes
- 1;
718 ASSERT (NumberOfPages
);
719 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
720 ASSERT (End
> Start
) ;
721 ASSERT_LOCKED (&gMemoryLock
);
722 ASSERT ( (ChangingType
== FALSE
) || (ChangingAttributes
== FALSE
) );
724 if (NumberOfPages
== 0 || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
> (Start
+ NumberOfBytes
))) {
725 return EFI_INVALID_PARAMETER
;
729 // Convert the entire range
732 while (Start
< End
) {
735 // Find the entry that the covers the range
737 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
738 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
740 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
745 if (Link
== &gMemoryMap
) {
746 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
747 return EFI_NOT_FOUND
;
751 // Convert range to the end, or to the end of the descriptor
752 // if that's all we've got
756 ASSERT (Entry
!= NULL
);
757 if (Entry
->End
< End
) {
758 RangeEnd
= Entry
->End
;
762 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to type %d\n", Start
, RangeEnd
, NewType
));
764 if (ChangingAttributes
) {
765 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to attr %lx\n", Start
, RangeEnd
, NewAttributes
));
770 // Debug code - verify conversion is allowed
772 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
773 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: Incompatible memory types\n"));
774 return EFI_NOT_FOUND
;
778 // Update counters for the number of pages allocated to each memory type
780 if ((UINT32
)Entry
->Type
< EfiMaxMemoryType
) {
781 if ((Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) ||
782 (Start
>= mDefaultBaseAddress
&& Start
<= mDefaultMaximumAddress
) ) {
783 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
784 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
786 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
791 if ((UINT32
)NewType
< EfiMaxMemoryType
) {
792 if ((Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) ||
793 (Start
>= mDefaultBaseAddress
&& Start
<= mDefaultMaximumAddress
) ) {
794 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
795 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
> gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
796 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
803 // Pull range out of descriptor
805 if (Entry
->Start
== Start
) {
810 Entry
->Start
= RangeEnd
+ 1;
812 } else if (Entry
->End
== RangeEnd
) {
817 Entry
->End
= Start
- 1;
822 // Pull it out of the center, clip current
828 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
829 mMapStack
[mMapDepth
].FromPages
= FALSE
;
830 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
831 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
832 mMapStack
[mMapDepth
].End
= Entry
->End
;
835 // Inherit Attribute from the Memory Descriptor that is being clipped
837 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
839 Entry
->End
= Start
- 1;
840 ASSERT (Entry
->Start
< Entry
->End
);
842 Entry
= &mMapStack
[mMapDepth
];
843 InsertTailList (&gMemoryMap
, &Entry
->Link
);
846 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
850 // The new range inherits the same Attribute as the Entry
851 // it is being cut out of unless attributes are being changed
854 Attribute
= Entry
->Attribute
;
857 Attribute
= NewAttributes
;
858 MemType
= Entry
->Type
;
862 // If the descriptor is empty, then remove it from the map
864 if (Entry
->Start
== Entry
->End
+ 1) {
865 RemoveMemoryMapEntry (Entry
);
870 // Add our new range in
872 CoreAddRange (MemType
, Start
, RangeEnd
, Attribute
);
873 if (ChangingType
&& (MemType
== EfiConventionalMemory
)) {
875 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
876 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
877 // that the page starting at address 0 is always filled with zeros.
880 if (RangeEnd
> EFI_PAGE_SIZE
) {
881 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
) EFI_PAGE_SIZE
, (UINTN
) (RangeEnd
- EFI_PAGE_SIZE
+ 1));
884 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
) Start
, (UINTN
) (RangeEnd
- Start
+ 1));
889 // Move any map descriptor stack to general pool
891 CoreFreeMemoryMapStack ();
894 // Bump the starting address, and convert the next range
896 Start
= RangeEnd
+ 1;
900 // Converted the whole range, done
908 Internal function. Converts a memory range to the specified type.
909 The range must exist in the memory map.
911 @param Start The first address of the range Must be page
913 @param NumberOfPages The number of pages to convert
914 @param NewType The new type for the memory range
916 @retval EFI_INVALID_PARAMETER Invalid parameter
917 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
918 range or convertion not allowed.
919 @retval EFI_SUCCESS Successfully converts the memory range to the
926 IN UINT64 NumberOfPages
,
927 IN EFI_MEMORY_TYPE NewType
930 return CoreConvertPagesEx(Start
, NumberOfPages
, TRUE
, NewType
, FALSE
, 0);
935 Internal function. Converts a memory range to use new attributes.
937 @param Start The first address of the range Must be page
939 @param NumberOfPages The number of pages to convert
940 @param NewAttributes The new attributes value for the range.
944 CoreUpdateMemoryAttributes (
945 IN EFI_PHYSICAL_ADDRESS Start
,
946 IN UINT64 NumberOfPages
,
947 IN UINT64 NewAttributes
950 CoreAcquireMemoryLock ();
953 // Update the attributes to the new value
955 CoreConvertPagesEx(Start
, NumberOfPages
, FALSE
, (EFI_MEMORY_TYPE
)0, TRUE
, NewAttributes
);
957 CoreReleaseMemoryLock ();
962 Internal function. Finds a consecutive free page range below
963 the requested address.
965 @param MaxAddress The address that the range must be below
966 @param MinAddress The address that the range must be above
967 @param NumberOfPages Number of pages needed
968 @param NewType The type of memory the range is going to be
970 @param Alignment Bits to align with
972 @return The base address of the range, or 0 if the range was not found
977 IN UINT64 MaxAddress
,
978 IN UINT64 MinAddress
,
979 IN UINT64 NumberOfPages
,
980 IN EFI_MEMORY_TYPE NewType
,
984 UINT64 NumberOfBytes
;
988 UINT64 DescNumberOfBytes
;
992 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
996 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
999 // If MaxAddress is not aligned to the end of a page
1003 // Change MaxAddress to be 1 page lower
1005 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
1008 // Set MaxAddress to a page boundary
1010 MaxAddress
&= ~(UINT64
)EFI_PAGE_MASK
;
1013 // Set MaxAddress to end of the page
1015 MaxAddress
|= EFI_PAGE_MASK
;
1018 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
1021 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1022 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1025 // If it's not a free entry, don't bother with it
1027 if (Entry
->Type
!= EfiConventionalMemory
) {
1031 DescStart
= Entry
->Start
;
1032 DescEnd
= Entry
->End
;
1035 // If desc is past max allowed address or below min allowed address, skip it
1037 if ((DescStart
>= MaxAddress
) || (DescEnd
< MinAddress
)) {
1042 // If desc ends past max allowed address, clip the end
1044 if (DescEnd
>= MaxAddress
) {
1045 DescEnd
= MaxAddress
;
1048 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
1051 // Compute the number of bytes we can used from this
1052 // descriptor, and see it's enough to satisfy the request
1054 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
1056 if (DescNumberOfBytes
>= NumberOfBytes
) {
1058 // If the start of the allocated range is below the min address allowed, skip it
1060 if ((DescEnd
- NumberOfBytes
+ 1) < MinAddress
) {
1065 // If this is the best match so far remember it
1067 if (DescEnd
> Target
) {
1074 // If this is a grow down, adjust target to be the allocation base
1076 Target
-= NumberOfBytes
- 1;
1079 // If we didn't find a match, return 0
1081 if ((Target
& EFI_PAGE_MASK
) != 0) {
1090 Internal function. Finds a consecutive free page range below
1091 the requested address
1093 @param MaxAddress The address that the range must be below
1094 @param NoPages Number of pages needed
1095 @param NewType The type of memory the range is going to be
1097 @param Alignment Bits to align with
1099 @return The base address of the range, or 0 if the range was not found.
1104 IN UINT64 MaxAddress
,
1106 IN EFI_MEMORY_TYPE NewType
,
1113 // Attempt to find free pages in the preferred bin based on the requested memory type
1115 if ((UINT32
)NewType
< EfiMaxMemoryType
&& MaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1116 Start
= CoreFindFreePagesI (
1117 mMemoryTypeStatistics
[NewType
].MaximumAddress
,
1118 mMemoryTypeStatistics
[NewType
].BaseAddress
,
1129 // Attempt to find free pages in the default allocation bin
1131 if (MaxAddress
>= mDefaultMaximumAddress
) {
1132 Start
= CoreFindFreePagesI (mDefaultMaximumAddress
, 0, NoPages
, NewType
, Alignment
);
1134 if (Start
< mDefaultBaseAddress
) {
1135 mDefaultBaseAddress
= Start
;
1142 // The allocation did not succeed in any of the prefered bins even after
1143 // promoting resources. Attempt to find free pages anywhere is the requested
1144 // address range. If this allocation fails, then there are not enough
1145 // resources anywhere to satisfy the request.
1147 Start
= CoreFindFreePagesI (MaxAddress
, 0, NoPages
, NewType
, Alignment
);
1153 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1155 if (!PromoteMemoryResource ()) {
1160 // If any memory resources were promoted, then re-attempt the allocation
1162 return FindFreePages (MaxAddress
, NoPages
, NewType
, Alignment
);
1167 Allocates pages from the memory map.
1169 @param Type The type of allocation to perform
1170 @param MemoryType The type of memory to turn the allocated pages
1172 @param NumberOfPages The number of pages to allocate
1173 @param Memory A pointer to receive the base allocated memory
1176 @return Status. On success, Memory is filled in with the base address allocated
1177 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1179 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1180 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1181 @retval EFI_SUCCESS Pages successfully allocated.
1186 CoreInternalAllocatePages (
1187 IN EFI_ALLOCATE_TYPE Type
,
1188 IN EFI_MEMORY_TYPE MemoryType
,
1189 IN UINTN NumberOfPages
,
1190 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
1198 if ((UINT32
)Type
>= MaxAllocateType
) {
1199 return EFI_INVALID_PARAMETER
;
1202 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
<= 0x7fffffff) ||
1203 (MemoryType
== EfiConventionalMemory
) || (MemoryType
== EfiPersistentMemory
)) {
1204 return EFI_INVALID_PARAMETER
;
1207 if (Memory
== NULL
) {
1208 return EFI_INVALID_PARAMETER
;
1211 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1213 if (MemoryType
== EfiACPIReclaimMemory
||
1214 MemoryType
== EfiACPIMemoryNVS
||
1215 MemoryType
== EfiRuntimeServicesCode
||
1216 MemoryType
== EfiRuntimeServicesData
) {
1218 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1221 if (Type
== AllocateAddress
) {
1222 if ((*Memory
& (Alignment
- 1)) != 0) {
1223 return EFI_NOT_FOUND
;
1227 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1228 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1231 // If this is for below a particular address, then
1236 // The max address is the max natively addressable address for the processor
1238 MaxAddress
= MAX_ADDRESS
;
1240 if (Type
== AllocateMaxAddress
) {
1244 CoreAcquireMemoryLock ();
1247 // If not a specific address, then find an address to allocate
1249 if (Type
!= AllocateAddress
) {
1250 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
);
1252 Status
= EFI_OUT_OF_RESOURCES
;
1258 // Convert pages from FreeMemory to the requested type
1260 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1263 CoreReleaseMemoryLock ();
1265 if (!EFI_ERROR (Status
)) {
1273 Allocates pages from the memory map.
1275 @param Type The type of allocation to perform
1276 @param MemoryType The type of memory to turn the allocated pages
1278 @param NumberOfPages The number of pages to allocate
1279 @param Memory A pointer to receive the base allocated memory
1282 @return Status. On success, Memory is filled in with the base address allocated
1283 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1285 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1286 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1287 @retval EFI_SUCCESS Pages successfully allocated.
1293 IN EFI_ALLOCATE_TYPE Type
,
1294 IN EFI_MEMORY_TYPE MemoryType
,
1295 IN UINTN NumberOfPages
,
1296 OUT EFI_PHYSICAL_ADDRESS
*Memory
1301 Status
= CoreInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
);
1302 if (!EFI_ERROR (Status
)) {
1303 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages
, MemoryType
, EFI_PAGES_TO_SIZE (NumberOfPages
), (VOID
*) (UINTN
) *Memory
);
1309 Frees previous allocated pages.
1311 @param Memory Base address of memory being freed
1312 @param NumberOfPages The number of pages to free
1314 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1315 @retval EFI_INVALID_PARAMETER Address not aligned
1316 @return EFI_SUCCESS -Pages successfully freed.
1321 CoreInternalFreePages (
1322 IN EFI_PHYSICAL_ADDRESS Memory
,
1323 IN UINTN NumberOfPages
1334 CoreAcquireMemoryLock ();
1337 // Find the entry that the covers the range
1340 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1341 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1342 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1346 if (Link
== &gMemoryMap
) {
1347 Status
= EFI_NOT_FOUND
;
1351 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1353 ASSERT (Entry
!= NULL
);
1354 if (Entry
->Type
== EfiACPIReclaimMemory
||
1355 Entry
->Type
== EfiACPIMemoryNVS
||
1356 Entry
->Type
== EfiRuntimeServicesCode
||
1357 Entry
->Type
== EfiRuntimeServicesData
) {
1359 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1363 if ((Memory
& (Alignment
- 1)) != 0) {
1364 Status
= EFI_INVALID_PARAMETER
;
1368 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1369 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1371 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1373 if (EFI_ERROR (Status
)) {
1378 CoreReleaseMemoryLock ();
1383 Frees previous allocated pages.
1385 @param Memory Base address of memory being freed
1386 @param NumberOfPages The number of pages to free
1388 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1389 @retval EFI_INVALID_PARAMETER Address not aligned
1390 @return EFI_SUCCESS -Pages successfully freed.
1396 IN EFI_PHYSICAL_ADDRESS Memory
,
1397 IN UINTN NumberOfPages
1402 Status
= CoreInternalFreePages (Memory
, NumberOfPages
);
1403 if (!EFI_ERROR (Status
)) {
1404 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionFreePages
, (EFI_MEMORY_TYPE
) 0, EFI_PAGES_TO_SIZE (NumberOfPages
), (VOID
*) (UINTN
) Memory
);
1410 This function checks to see if the last memory map descriptor in a memory map
1411 can be merged with any of the other memory map descriptors in a memorymap.
1412 Memory descriptors may be merged if they are adjacent and have the same type
1415 @param MemoryMap A pointer to the start of the memory map.
1416 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1417 @param DescriptorSize The size, in bytes, of an individual
1418 EFI_MEMORY_DESCRIPTOR.
1420 @return A pointer to the next available descriptor in MemoryMap
1423 EFI_MEMORY_DESCRIPTOR
*
1424 MergeMemoryMapDescriptor (
1425 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1426 IN EFI_MEMORY_DESCRIPTOR
*MemoryMapDescriptor
,
1427 IN UINTN DescriptorSize
1431 // Traverse the array of descriptors in MemoryMap
1433 for (; MemoryMap
!= MemoryMapDescriptor
; MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
)) {
1435 // Check to see if the Type fields are identical.
1437 if (MemoryMap
->Type
!= MemoryMapDescriptor
->Type
) {
1442 // Check to see if the Attribute fields are identical.
1444 if (MemoryMap
->Attribute
!= MemoryMapDescriptor
->Attribute
) {
1449 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1451 if (MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1453 // Merge MemoryMapDescriptor into MemoryMap
1455 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1458 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1460 return MemoryMapDescriptor
;
1464 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1466 if (MemoryMap
->PhysicalStart
- EFI_PAGES_TO_SIZE ((UINTN
)MemoryMapDescriptor
->NumberOfPages
) == MemoryMapDescriptor
->PhysicalStart
) {
1468 // Merge MemoryMapDescriptor into MemoryMap
1470 MemoryMap
->PhysicalStart
= MemoryMapDescriptor
->PhysicalStart
;
1471 MemoryMap
->VirtualStart
= MemoryMapDescriptor
->VirtualStart
;
1472 MemoryMap
->NumberOfPages
+= MemoryMapDescriptor
->NumberOfPages
;
1475 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1477 return MemoryMapDescriptor
;
1482 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1484 // Return the slot immediately after MemoryMapDescriptor as the next available
1485 // slot in the MemoryMap array
1487 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor
, DescriptorSize
);
1491 This function returns a copy of the current memory map. The map is an array of
1492 memory descriptors, each of which describes a contiguous block of memory.
1494 @param MemoryMapSize A pointer to the size, in bytes, of the
1495 MemoryMap buffer. On input, this is the size of
1496 the buffer allocated by the caller. On output,
1497 it is the size of the buffer returned by the
1498 firmware if the buffer was large enough, or the
1499 size of the buffer needed to contain the map if
1500 the buffer was too small.
1501 @param MemoryMap A pointer to the buffer in which firmware places
1502 the current memory map.
1503 @param MapKey A pointer to the location in which firmware
1504 returns the key for the current memory map.
1505 @param DescriptorSize A pointer to the location in which firmware
1506 returns the size, in bytes, of an individual
1507 EFI_MEMORY_DESCRIPTOR.
1508 @param DescriptorVersion A pointer to the location in which firmware
1509 returns the version number associated with the
1510 EFI_MEMORY_DESCRIPTOR.
1512 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1514 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1515 buffer size needed to hold the memory map is
1516 returned in MemoryMapSize.
1517 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1523 IN OUT UINTN
*MemoryMapSize
,
1524 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1526 OUT UINTN
*DescriptorSize
,
1527 OUT UINT32
*DescriptorVersion
1533 UINTN NumberOfEntries
;
1536 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1537 EFI_MEMORY_TYPE Type
;
1538 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
1541 // Make sure the parameters are valid
1543 if (MemoryMapSize
== NULL
) {
1544 return EFI_INVALID_PARAMETER
;
1547 CoreAcquireGcdMemoryLock ();
1550 // Count the number of Reserved and runtime MMIO entries
1551 // And, count the number of Persistent entries.
1553 NumberOfEntries
= 0;
1554 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1555 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1556 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypePersistentMemory
) ||
1557 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1558 ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1559 ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
))) {
1564 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1567 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1568 // prevent people from having pointer math bugs in their code.
1569 // now you have to use *DescriptorSize to make things work.
1571 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1573 if (DescriptorSize
!= NULL
) {
1574 *DescriptorSize
= Size
;
1577 if (DescriptorVersion
!= NULL
) {
1578 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1581 CoreAcquireMemoryLock ();
1584 // Compute the buffer size needed to fit the entire map
1586 BufferSize
= Size
* NumberOfEntries
;
1587 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1591 if (*MemoryMapSize
< BufferSize
) {
1592 Status
= EFI_BUFFER_TOO_SMALL
;
1596 if (MemoryMap
== NULL
) {
1597 Status
= EFI_INVALID_PARAMETER
;
1604 ZeroMem (MemoryMap
, BufferSize
);
1605 MemoryMapStart
= MemoryMap
;
1606 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1607 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1608 ASSERT (Entry
->VirtualStart
== 0);
1611 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1613 MemoryMap
->Type
= Entry
->Type
;
1614 MemoryMap
->PhysicalStart
= Entry
->Start
;
1615 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1616 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1618 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1619 // memory type bin and needs to be converted to the same memory type as the rest of the
1620 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1621 // improves the chances for a successful S4 resume in the presence of minor page allocation
1622 // differences across reboots.
1624 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1625 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
1626 if (mMemoryTypeStatistics
[Type
].Special
&&
1627 mMemoryTypeStatistics
[Type
].NumberOfPages
> 0 &&
1628 Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
&&
1629 Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
) {
1630 MemoryMap
->Type
= Type
;
1634 MemoryMap
->Attribute
= Entry
->Attribute
;
1635 if (MemoryMap
->Type
< EfiMaxMemoryType
) {
1636 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1637 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1642 // Check to see if the new Memory Map Descriptor can be merged with an
1643 // existing descriptor if they are adjacent and have the same attributes
1645 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1648 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1649 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1650 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1651 ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) &&
1652 ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
))) {
1654 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1656 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1657 MemoryMap
->VirtualStart
= 0;
1658 MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1659 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
& ~EFI_MEMORY_PORT_IO
;
1661 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1662 MemoryMap
->Type
= EfiReservedMemoryType
;
1663 } else if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1664 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1665 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1667 MemoryMap
->Type
= EfiMemoryMappedIO
;
1672 // Check to see if the new Memory Map Descriptor can be merged with an
1673 // existing descriptor if they are adjacent and have the same attributes
1675 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1678 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypePersistentMemory
) {
1680 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1682 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1683 MemoryMap
->VirtualStart
= 0;
1684 MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1685 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
| EFI_MEMORY_NV
;
1686 MemoryMap
->Type
= EfiPersistentMemory
;
1689 // Check to see if the new Memory Map Descriptor can be merged with an
1690 // existing descriptor if they are adjacent and have the same attributes
1692 MemoryMap
= MergeMemoryMapDescriptor (MemoryMapStart
, MemoryMap
, Size
);
1697 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1699 BufferSize
= ((UINT8
*)MemoryMap
- (UINT8
*)MemoryMapStart
);
1701 Status
= EFI_SUCCESS
;
1705 // Update the map key finally
1707 if (MapKey
!= NULL
) {
1708 *MapKey
= mMemoryMapKey
;
1711 CoreReleaseMemoryLock ();
1713 CoreReleaseGcdMemoryLock ();
1715 *MemoryMapSize
= BufferSize
;
1722 Internal function. Used by the pool functions to allocate pages
1723 to back pool allocation requests.
1725 @param PoolType The type of memory for the new pool pages
1726 @param NumberOfPages No of pages to allocate
1727 @param Alignment Bits to align.
1729 @return The allocated memory, or NULL
1733 CoreAllocatePoolPages (
1734 IN EFI_MEMORY_TYPE PoolType
,
1735 IN UINTN NumberOfPages
,
1742 // Find the pages to convert
1744 Start
= FindFreePages (MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
);
1747 // Convert it to boot services data
1750 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32
)NumberOfPages
));
1752 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1755 return (VOID
*)(UINTN
) Start
;
1760 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1762 @param Memory The base address to free
1763 @param NumberOfPages The number of pages to free
1768 IN EFI_PHYSICAL_ADDRESS Memory
,
1769 IN UINTN NumberOfPages
1772 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1778 Make sure the memory map is following all the construction rules,
1779 it is the last time to check memory map error before exit boot services.
1781 @param MapKey Memory map key
1783 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1785 @retval EFI_SUCCESS Valid memory map.
1789 CoreTerminateMemoryMap (
1797 Status
= EFI_SUCCESS
;
1799 CoreAcquireMemoryLock ();
1801 if (MapKey
== mMemoryMapKey
) {
1804 // Make sure the memory map is following all the construction rules
1805 // This is the last chance we will be able to display any messages on
1806 // the console devices.
1809 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1810 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1811 if (Entry
->Type
< EfiMaxMemoryType
) {
1812 if (mMemoryTypeStatistics
[Entry
->Type
].Runtime
) {
1813 ASSERT (Entry
->Type
!= EfiACPIReclaimMemory
);
1814 ASSERT (Entry
->Type
!= EfiACPIMemoryNVS
);
1815 if ((Entry
->Start
& (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) != 0) {
1816 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1817 Status
= EFI_INVALID_PARAMETER
;
1820 if (((Entry
->End
+ 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) != 0) {
1821 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1822 Status
= EFI_INVALID_PARAMETER
;
1830 // The map key they gave us matches what we expect. Fall through and
1831 // return success. In an ideal world we would clear out all of
1832 // EfiBootServicesCode and EfiBootServicesData. However this function
1833 // is not the last one called by ExitBootServices(), so we have to
1834 // preserve the memory contents.
1837 Status
= EFI_INVALID_PARAMETER
;
1841 CoreReleaseMemoryLock ();