3 UEFI Memory page management functions.
5 Copyright (c) 2007 - 2008, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 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 help cooalese like memory types
24 EFI_PHYSICAL_ADDRESS BaseAddress
;
25 EFI_PHYSICAL_ADDRESS MaximumAddress
;
26 UINT64 CurrentNumberOfPages
;
28 UINTN InformationIndex
;
31 } EFI_MEMORY_TYPE_STAISTICS
;
34 // MemoryMap - The current memory map
36 UINTN mMemoryMapKey
= 0;
39 // mMapStack - space to use as temp storage to build new map descriptors
40 // mMapDepth - depth of new descriptor stack
43 #define MAX_MAP_DEPTH 6
45 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
46 UINTN mFreeMapStack
= 0;
48 // This list maintain the free memory map list
50 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
51 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
53 EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
54 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
55 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
56 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
57 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
58 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
59 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
60 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
61 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
62 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
63 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
64 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
65 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
66 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
67 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
68 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
71 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= EFI_MAX_ADDRESS
;
73 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
74 { EfiReservedMemoryType
, 0 },
77 { EfiBootServicesCode
, 0 },
78 { EfiBootServicesData
, 0 },
79 { EfiRuntimeServicesCode
, 0 },
80 { EfiRuntimeServicesData
, 0 },
81 { EfiConventionalMemory
, 0 },
82 { EfiUnusableMemory
, 0 },
83 { EfiACPIReclaimMemory
, 0 },
84 { EfiACPIMemoryNVS
, 0 },
85 { EfiMemoryMappedIO
, 0 },
86 { EfiMemoryMappedIOPortSpace
, 0 },
88 { EfiMaxMemoryType
, 0 }
92 // Internal prototypes
96 PromoteMemoryResource (
103 IN EFI_MEMORY_TYPE Type
,
104 IN EFI_PHYSICAL_ADDRESS Start
,
105 IN EFI_PHYSICAL_ADDRESS End
,
111 CoreFreeMemoryMapStack (
119 IN UINT64 NumberOfPages
,
120 IN EFI_MEMORY_TYPE NewType
125 RemoveMemoryMapEntry (
131 AllocateMemoryMapEntry (
136 CoreAcquireMemoryLock (
143 Enter critical section by gaining lock on gMemoryLock
155 CoreAcquireLock (&gMemoryLock
);
160 CoreReleaseMemoryLock (
167 Exit critical section by releasing lock on gMemoryLock
179 CoreReleaseLock (&gMemoryLock
);
184 PromoteMemoryResource (
191 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
204 EFI_GCD_MAP_ENTRY
*Entry
;
206 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "Promote the memory resource\n"));
208 CoreAcquireGcdMemoryLock ();
210 Link
= mGcdMemorySpaceMap
.ForwardLink
;
211 while (Link
!= &mGcdMemorySpaceMap
) {
213 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
215 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
216 Entry
->EndAddress
< EFI_MAX_ADDRESS
&&
217 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
218 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
220 // Update the GCD map
222 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
223 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
224 Entry
->ImageHandle
= gDxeCoreImageHandle
;
225 Entry
->DeviceHandle
= NULL
;
228 // Add to allocable system memory resource
232 EfiConventionalMemory
,
235 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
237 CoreFreeMemoryMapStack ();
241 Link
= Link
->ForwardLink
;
244 CoreReleaseGcdMemoryLock ();
250 CoreAddMemoryDescriptor (
251 IN EFI_MEMORY_TYPE Type
,
252 IN EFI_PHYSICAL_ADDRESS Start
,
253 IN UINT64 NumberOfPages
,
260 Called to initialize the memory map and add descriptors to
261 the current descriptor list.
263 The first descriptor that is added must be general usable
264 memory as the addition allocates heap.
268 Type - The type of memory to add
270 Start - The starting address in the memory range
273 NumberOfPages - The number of pages in the range
275 Attribute - Attributes of the memory to add
279 None. The range is added to the memory map
283 EFI_PHYSICAL_ADDRESS End
;
288 if ((Start
& EFI_PAGE_MASK
) != 0) {
292 if (Type
>= EfiMaxMemoryType
&& Type
<= 0x7fffffff) {
296 CoreAcquireMemoryLock ();
297 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
298 CoreAddRange (Type
, Start
, End
, Attribute
);
299 CoreFreeMemoryMapStack ();
300 CoreReleaseMemoryLock ();
303 // Check to see if the statistics for the different memory types have already been established
305 if (mMemoryTypeInformationInitialized
) {
310 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
312 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
314 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
316 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
317 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
321 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
323 // Allocate pages for the current memory type from the top of available memory
325 Status
= CoreAllocatePages (
328 gMemoryTypeInformation
[Index
].NumberOfPages
,
329 &mMemoryTypeStatistics
[Type
].BaseAddress
331 if (EFI_ERROR (Status
)) {
333 // If an error occurs allocating the pages for the current memory type, then
334 // free all the pages allocates for the previous memory types and return. This
335 // operation with be retied when/if more memory is added to the system
337 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
339 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
341 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
342 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
346 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
348 mMemoryTypeStatistics
[Type
].BaseAddress
,
349 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
351 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
352 mMemoryTypeStatistics
[Type
].MaximumAddress
= EFI_MAX_ADDRESS
;
359 // Compute the address at the top of the current statistics
361 mMemoryTypeStatistics
[Type
].MaximumAddress
=
362 mMemoryTypeStatistics
[Type
].BaseAddress
+
363 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
366 // If the current base address is the lowest address so far, then update the default
369 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
370 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
376 // There was enough system memory for all the the memory types were allocated. So,
377 // those memory areas can be freed for future allocations, and all future memory
378 // allocations can occur within their respective bins
380 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
382 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
384 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
385 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
389 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
391 mMemoryTypeStatistics
[Type
].BaseAddress
,
392 gMemoryTypeInformation
[Index
].NumberOfPages
394 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
395 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
400 // If the number of pages reserved for a memory type is 0, then all allocations for that type
401 // should be in the default range.
403 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
404 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
405 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
406 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
409 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
410 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== EFI_MAX_ADDRESS
) {
411 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
415 mMemoryTypeInformationInitialized
= TRUE
;
422 IN EFI_MEMORY_TYPE Type
,
423 IN EFI_PHYSICAL_ADDRESS Start
,
424 IN EFI_PHYSICAL_ADDRESS End
,
431 Internal function. Adds a ranges to the memory map.
432 The range must not already exist in the map.
436 Type - The type of memory range to add
438 Start - The starting address in the memory range
439 Must be paged aligned
441 End - The last address in the range
442 Must be the last byte of a page
444 Attribute - The attributes of the memory range to add
448 None. The range is added to the memory map
455 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
456 ASSERT (End
> Start
) ;
458 ASSERT_LOCKED (&gMemoryLock
);
460 DEBUG ((EFI_D_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
463 // Memory map being altered so updated key
468 // UEFI 2.0 added an event group for notificaiton on memory map changes.
469 // So we need to signal this Event Group every time the memory map changes.
470 // If we are in EFI 1.10 compatability mode no event groups will be
471 // found and nothing will happen we we call this function. These events
472 // will get signaled but since a lock is held around the call to this
473 // function the notificaiton events will only be called after this funciton
474 // returns and the lock is released.
476 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
479 // Look for adjoining memory descriptor
482 // Two memory descriptors can only be merged if they have the same Type
483 // and the same Attribute
486 Link
= gMemoryMap
.ForwardLink
;
487 while (Link
!= &gMemoryMap
) {
488 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
489 Link
= Link
->ForwardLink
;
491 if (Entry
->Type
!= Type
) {
495 if (Entry
->Attribute
!= Attribute
) {
499 if (Entry
->End
+ 1 == Start
) {
501 Start
= Entry
->Start
;
502 RemoveMemoryMapEntry (Entry
);
504 } else if (Entry
->Start
== End
+ 1) {
507 RemoveMemoryMapEntry (Entry
);
515 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
516 mMapStack
[mMapDepth
].FromPages
= FALSE
;
517 mMapStack
[mMapDepth
].Type
= Type
;
518 mMapStack
[mMapDepth
].Start
= Start
;
519 mMapStack
[mMapDepth
].End
= End
;
520 mMapStack
[mMapDepth
].VirtualStart
= 0;
521 mMapStack
[mMapDepth
].Attribute
= Attribute
;
522 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
525 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
532 CoreFreeMemoryMapStack (
539 Internal function. Moves any memory descriptors that are on the
540 temporary descriptor stack to heap.
556 ASSERT_LOCKED (&gMemoryLock
);
559 // If already freeing the map stack, then return
566 // Move the temporary memory descriptor stack into pool
572 // Deque an memory map entry from mFreeMemoryMapEntryList
574 Entry
= AllocateMemoryMapEntry ();
579 // Update to proper entry
583 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
586 // Move this entry to general memory
588 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
589 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
591 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
592 Entry
->FromPages
= TRUE
;
595 // Find insertion location
597 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
598 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
599 if (Entry2
->FromPages
&& Entry2
->Start
> Entry
->Start
) {
604 InsertTailList (Link2
, &Entry
->Link
);
608 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
609 // so here no need to move it to memory.
611 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
620 RemoveMemoryMapEntry (
627 Internal function. Removes a descriptor entry.
631 Entry - The entry to remove
639 RemoveEntryList (&Entry
->Link
);
640 Entry
->Link
.ForwardLink
= NULL
;
642 if (Entry
->FromPages
) {
644 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
646 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
652 AllocateMemoryMapEntry (
659 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
660 If the list is emtry, then allocate a new page to refuel the list.
661 Please Note this algorithm to allocate the memory map descriptor has a property
662 that the memory allocated for memory entries always grows, and will never really be freed
663 For example, if the current boot uses 2000 memory map entries at the maximum point, but
664 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
665 memory map entries is still allocated from EfiBootServicesMemory.
673 The Memory map descriptor dequed from the mFreeMemoryMapEntryList
677 MEMORY_MAP
* FreeDescriptorEntries
;
681 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
683 // The list is empty, to allocate one page to refuel the list
685 FreeDescriptorEntries
= CoreAllocatePoolPages (EfiBootServicesData
, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
686 if(FreeDescriptorEntries
!= NULL
) {
688 // Enque the free memmory map entries into the list
690 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION
/ sizeof(MEMORY_MAP
); Index
++) {
691 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
692 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
699 // dequeue the first descriptor from the list
701 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
702 RemoveEntryList (&Entry
->Link
);
711 IN UINT64 NumberOfPages
,
712 IN EFI_MEMORY_TYPE NewType
718 Internal function. Converts a memory range to the specified type.
719 The range must exist in the memory map.
723 Start - The first address of the range
726 NumberOfPages - The number of pages to convert
728 NewType - The new type for the memory range
732 EFI_INVALID_PARAMETER - Invalid parameter
734 EFI_NOT_FOUND - Could not find a descriptor cover the specified range
735 or convertion not allowed.
737 EFI_SUCCESS - Successfully converts the memory range to the specified type.
742 UINT64 NumberOfBytes
;
750 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
751 End
= Start
+ NumberOfBytes
- 1;
753 ASSERT (NumberOfPages
);
754 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
755 ASSERT (End
> Start
) ;
756 ASSERT_LOCKED (&gMemoryLock
);
758 if (NumberOfPages
== 0 || (Start
& EFI_PAGE_MASK
) || (Start
> (Start
+ NumberOfBytes
))) {
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 ((EFI_D_ERROR
| EFI_D_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
781 return EFI_NOT_FOUND
;
785 // Convert range to the end, or to the end of the descriptor
786 // if that's all we've got
789 if (Entry
->End
< End
) {
790 RangeEnd
= Entry
->End
;
793 DEBUG ((EFI_D_PAGE
, "ConvertRange: %lx-%lx to %d\n", Start
, RangeEnd
, NewType
));
796 // Debug code - verify conversion is allowed
798 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
799 DEBUG ((EFI_D_ERROR
, "ConvertPages: Incompatible memory types\n"));
800 return EFI_NOT_FOUND
;
804 // Update counters for the number of pages allocated to each memory type
806 if (Entry
->Type
>= 0 && Entry
->Type
< EfiMaxMemoryType
) {
807 if (Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&&
808 Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) {
809 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
810 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
812 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
817 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
) {
818 if (Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
819 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
820 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
>
821 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
822 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
828 // Pull range out of descriptor
830 if (Entry
->Start
== Start
) {
835 Entry
->Start
= RangeEnd
+ 1;
837 } else if (Entry
->End
== RangeEnd
) {
842 Entry
->End
= Start
- 1;
847 // Pull it out of the center, clip current
853 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
854 mMapStack
[mMapDepth
].FromPages
= FALSE
;
855 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
856 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
857 mMapStack
[mMapDepth
].End
= Entry
->End
;
860 // Inherit Attribute from the Memory Descriptor that is being clipped
862 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
864 Entry
->End
= Start
- 1;
865 ASSERT (Entry
->Start
< Entry
->End
);
867 Entry
= &mMapStack
[mMapDepth
];
868 InsertTailList (&gMemoryMap
, &Entry
->Link
);
871 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
875 // The new range inherits the same Attribute as the Entry
876 //it is being cut out of
878 Attribute
= Entry
->Attribute
;
881 // If the descriptor is empty, then remove it from the map
883 if (Entry
->Start
== Entry
->End
+ 1) {
884 RemoveMemoryMapEntry (Entry
);
889 // Add our new range in
891 CoreAddRange (NewType
, Start
, RangeEnd
, Attribute
);
894 // Move any map descriptor stack to general pool
896 CoreFreeMemoryMapStack ();
899 // Bump the starting address, and convert the next range
901 Start
= RangeEnd
+ 1;
905 // Converted the whole range, done
915 IN UINT64 MaxAddress
,
916 IN UINT64 NumberOfPages
,
917 IN EFI_MEMORY_TYPE NewType
,
924 Internal function. Finds a consecutive free page range below
925 the requested address.
929 MaxAddress - The address that the range must be below
931 NumberOfPages - Number of pages needed
933 NewType - The type of memory the range is going to be turned into
935 Alignment - Bits to align with
939 The base address of the range, or 0 if the range was not found
943 UINT64 NumberOfBytes
;
947 UINT64 DescNumberOfBytes
;
951 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
955 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
958 // If MaxAddress is not aligned to the end of a page
962 // Change MaxAddress to be 1 page lower
964 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
967 // Set MaxAddress to a page boundary
969 MaxAddress
&= ~EFI_PAGE_MASK
;
972 // Set MaxAddress to end of the page
974 MaxAddress
|= EFI_PAGE_MASK
;
977 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
980 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
981 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
984 // If it's not a free entry, don't bother with it
986 if (Entry
->Type
!= EfiConventionalMemory
) {
990 DescStart
= Entry
->Start
;
991 DescEnd
= Entry
->End
;
994 // If desc is past max allowed address, skip it
996 if (DescStart
>= MaxAddress
) {
1001 // If desc ends past max allowed address, clip the end
1003 if (DescEnd
>= MaxAddress
) {
1004 DescEnd
= MaxAddress
;
1007 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
1010 // Compute the number of bytes we can used from this
1011 // descriptor, and see it's enough to satisfy the request
1013 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
1015 if (DescNumberOfBytes
>= NumberOfBytes
) {
1018 // If this is the best match so far remember it
1020 if (DescEnd
> Target
) {
1027 // If this is a grow down, adjust target to be the allocation base
1029 Target
-= NumberOfBytes
- 1;
1032 // If we didn't find a match, return 0
1034 if ((Target
& EFI_PAGE_MASK
) != 0) {
1044 IN UINT64 MaxAddress
,
1046 IN EFI_MEMORY_TYPE NewType
,
1051 Routine Description:
1053 Internal function. Finds a consecutive free page range below
1054 the requested address
1058 MaxAddress - The address that the range must be below
1060 NoPages - Number of pages needed
1062 NewType - The type of memory the range is going to be turned into
1064 Alignment - Bits to align with
1068 The base address of the range, or 0 if the range was not found.
1072 UINT64 NewMaxAddress
;
1075 NewMaxAddress
= MaxAddress
;
1077 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
&& NewMaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1078 NewMaxAddress
= mMemoryTypeStatistics
[NewType
].MaximumAddress
;
1080 if (NewMaxAddress
> mDefaultMaximumAddress
) {
1081 NewMaxAddress
= mDefaultMaximumAddress
;
1085 Start
= CoreFindFreePagesI (NewMaxAddress
, NoPages
, NewType
, Alignment
);
1087 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1090 // Here means there may be no enough memory to use, so try to go through
1091 // all the memory descript to promote the untested memory directly
1093 PromoteMemoryResource ();
1096 // Allocate memory again after the memory resource re-arranged
1098 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1109 IN EFI_ALLOCATE_TYPE Type
,
1110 IN EFI_MEMORY_TYPE MemoryType
,
1111 IN UINTN NumberOfPages
,
1112 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
1116 Routine Description:
1118 Allocates pages from the memory map.
1122 Type - The type of allocation to perform
1124 MemoryType - The type of memory to turn the allocated pages into
1126 NumberOfPages - The number of pages to allocate
1128 Memory - A pointer to receive the base allocated memory address
1132 Status. On success, Memory is filled in with the base address allocated
1134 EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec.
1136 EFI_NOT_FOUND - Could not allocate pages match the requirement.
1138 EFI_OUT_OF_RESOURCES - No enough pages to allocate.
1140 EFI_SUCCESS - Pages successfully allocated.
1149 if (Type
< AllocateAnyPages
|| Type
>= (UINTN
) MaxAllocateType
) {
1150 return EFI_INVALID_PARAMETER
;
1153 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
<= 0x7fffffff) ||
1154 MemoryType
== EfiConventionalMemory
) {
1155 return EFI_INVALID_PARAMETER
;
1158 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1160 if (MemoryType
== EfiACPIReclaimMemory
||
1161 MemoryType
== EfiACPIMemoryNVS
||
1162 MemoryType
== EfiRuntimeServicesCode
||
1163 MemoryType
== EfiRuntimeServicesData
) {
1165 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1168 if (Type
== AllocateAddress
) {
1169 if ((*Memory
& (Alignment
- 1)) != 0) {
1170 return EFI_NOT_FOUND
;
1174 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1175 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1178 // If this is for below a particular address, then
1183 // The max address is the max natively addressable address for the processor
1185 MaxAddress
= EFI_MAX_ADDRESS
;
1187 if (Type
== AllocateMaxAddress
) {
1191 CoreAcquireMemoryLock ();
1194 // If not a specific address, then find an address to allocate
1196 if (Type
!= AllocateAddress
) {
1197 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
);
1199 Status
= EFI_OUT_OF_RESOURCES
;
1205 // Convert pages from FreeMemory to the requested type
1207 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1210 CoreReleaseMemoryLock ();
1212 if (!EFI_ERROR (Status
)) {
1225 IN EFI_PHYSICAL_ADDRESS Memory
,
1226 IN UINTN NumberOfPages
1230 Routine Description:
1232 Frees previous allocated pages.
1236 Memory - Base address of memory being freed
1238 NumberOfPages - The number of pages to free
1242 EFI_NOT_FOUND - Could not find the entry that covers the range
1244 EFI_INVALID_PARAMETER - Address not aligned
1246 EFI_SUCCESS -Pages successfully freed.
1258 CoreAcquireMemoryLock ();
1261 // Find the entry that the covers the range
1264 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1265 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1266 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1270 if (Link
== &gMemoryMap
) {
1271 CoreReleaseMemoryLock ();
1272 return EFI_NOT_FOUND
;
1275 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1277 if (Entry
->Type
== EfiACPIReclaimMemory
||
1278 Entry
->Type
== EfiACPIMemoryNVS
||
1279 Entry
->Type
== EfiRuntimeServicesCode
||
1280 Entry
->Type
== EfiRuntimeServicesData
) {
1282 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1286 if ((Memory
& (Alignment
- 1)) != 0) {
1287 CoreReleaseMemoryLock ();
1288 return EFI_INVALID_PARAMETER
;
1291 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1292 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1294 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1296 CoreReleaseMemoryLock ();
1298 if (EFI_ERROR (Status
)) {
1303 // Destroy the contents
1305 if (Memory
< EFI_MAX_ADDRESS
) {
1306 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Memory
, NumberOfPages
<< EFI_PAGE_SHIFT
);
1317 IN OUT UINTN
*MemoryMapSize
,
1318 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1320 OUT UINTN
*DescriptorSize
,
1321 OUT UINT32
*DescriptorVersion
1325 Routine Description:
1327 This function returns a copy of the current memory map. The map is an array of
1328 memory descriptors, each of which describes a contiguous block of memory.
1332 MemoryMapSize - A pointer to the size, in bytes, of the MemoryMap buffer. On
1333 input, this is the size of the buffer allocated by the caller.
1334 On output, it is the size of the buffer returned by the firmware
1335 if the buffer was large enough, or the size of the buffer needed
1336 to contain the map if the buffer was too small.
1337 MemoryMap - A pointer to the buffer in which firmware places the current memory map.
1338 MapKey - A pointer to the location in which firmware returns the key for the
1340 DescriptorSize - A pointer to the location in which firmware returns the size, in
1341 bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1342 DescriptorVersion - A pointer to the location in which firmware returns the version
1343 number associated with the EFI_MEMORY_DESCRIPTOR.
1347 EFI_SUCCESS - The memory map was returned in the MemoryMap buffer.
1348 EFI_BUFFER_TOO_SMALL - The MemoryMap buffer was too small. The current buffer size
1349 needed to hold the memory map is returned in MemoryMapSize.
1350 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
1357 UINTN NumberOfRuntimeEntries
;
1360 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1361 EFI_MEMORY_TYPE Type
;
1364 // Make sure the parameters are valid
1366 if (MemoryMapSize
== NULL
) {
1367 return EFI_INVALID_PARAMETER
;
1370 CoreAcquireGcdMemoryLock ();
1373 // Count the number of Reserved and MMIO entries that are marked for runtime use
1375 NumberOfRuntimeEntries
= 0;
1376 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1377 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1378 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1379 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1380 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1381 NumberOfRuntimeEntries
++;
1386 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1389 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1390 // prevent people from having pointer math bugs in their code.
1391 // now you have to use *DescriptorSize to make things work.
1393 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1395 if (DescriptorSize
!= NULL
) {
1396 *DescriptorSize
= Size
;
1399 if (DescriptorVersion
!= NULL
) {
1400 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1403 CoreAcquireMemoryLock ();
1406 // Compute the buffer size needed to fit the entire map
1408 BufferSize
= Size
* NumberOfRuntimeEntries
;
1409 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1413 if (*MemoryMapSize
< BufferSize
) {
1414 Status
= EFI_BUFFER_TOO_SMALL
;
1418 if (MemoryMap
== NULL
) {
1419 Status
= EFI_INVALID_PARAMETER
;
1426 ZeroMem (MemoryMap
, BufferSize
);
1427 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1428 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1429 ASSERT (Entry
->VirtualStart
== 0);
1432 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1434 MemoryMap
->Type
= Entry
->Type
;
1435 MemoryMap
->PhysicalStart
= Entry
->Start
;
1436 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1437 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1439 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1440 // memory type bin and needs to be converted to the same memory type as the rest of the
1441 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1442 // improves the chances for a successful S4 resume in the presence of minor page allocation
1443 // differences across reboots.
1445 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1446 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
1447 if (mMemoryTypeStatistics
[Type
].Special
&&
1448 mMemoryTypeStatistics
[Type
].NumberOfPages
> 0 &&
1449 Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
&&
1450 Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
) {
1451 MemoryMap
->Type
= Type
;
1455 MemoryMap
->Attribute
= Entry
->Attribute
;
1456 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1457 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1460 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1463 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1464 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1465 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1466 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1467 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1469 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1470 MemoryMap
->VirtualStart
= 0;
1471 MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1472 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
& ~EFI_MEMORY_PORT_IO
;
1474 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1475 MemoryMap
->Type
= EfiReservedMemoryType
;
1476 } else if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1477 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1478 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1480 MemoryMap
->Type
= EfiMemoryMappedIO
;
1484 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1489 Status
= EFI_SUCCESS
;
1493 CoreReleaseMemoryLock ();
1495 CoreReleaseGcdMemoryLock ();
1498 // Update the map key finally
1500 if (MapKey
!= NULL
) {
1501 *MapKey
= mMemoryMapKey
;
1504 *MemoryMapSize
= BufferSize
;
1510 CoreAllocatePoolPages (
1511 IN EFI_MEMORY_TYPE PoolType
,
1512 IN UINTN NumberOfPages
,
1517 Routine Description:
1519 Internal function. Used by the pool functions to allocate pages
1520 to back pool allocation requests.
1524 PoolType - The type of memory for the new pool pages
1526 NumberOfPages - No of pages to allocate
1528 Alignment - Bits to align.
1532 The allocated memory, or NULL
1539 // Find the pages to convert
1541 Start
= FindFreePages (EFI_MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
);
1544 // Convert it to boot services data
1547 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages
));
1549 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1552 return (VOID
*)(UINTN
)Start
;
1557 IN EFI_PHYSICAL_ADDRESS Memory
,
1558 IN UINTN NumberOfPages
1562 Routine Description:
1564 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1568 Memory - The base address to free
1570 NumberOfPages - The number of pages to free
1578 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1583 CoreTerminateMemoryMap (
1588 Routine Description:
1590 Make sure the memory map is following all the construction rules,
1591 it is the last time to check memory map error before exit boot services.
1595 MapKey - Memory map key
1599 EFI_INVALID_PARAMETER - Memory map not consistent with construction rules.
1601 EFI_SUCCESS - Valid memory map.
1609 Status
= EFI_SUCCESS
;
1611 CoreAcquireMemoryLock ();
1613 if (MapKey
== mMemoryMapKey
) {
1616 // Make sure the memory map is following all the construction rules
1617 // This is the last chance we will be able to display any messages on
1618 // the console devices.
1621 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1622 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1623 if (Entry
->Attribute
& EFI_MEMORY_RUNTIME
) {
1624 if (Entry
->Type
== EfiACPIReclaimMemory
|| Entry
->Type
== EfiACPIMemoryNVS
) {
1625 DEBUG((EFI_D_ERROR
, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1626 CoreReleaseMemoryLock ();
1627 return EFI_INVALID_PARAMETER
;
1629 if (Entry
->Start
& (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1630 DEBUG((EFI_D_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1631 CoreReleaseMemoryLock ();
1632 return EFI_INVALID_PARAMETER
;
1634 if ((Entry
->End
+ 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1635 DEBUG((EFI_D_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1636 CoreReleaseMemoryLock ();
1637 return EFI_INVALID_PARAMETER
;
1643 // The map key they gave us matches what we expect. Fall through and
1644 // return success. In an ideal world we would clear out all of
1645 // EfiBootServicesCode and EfiBootServicesData. However this function
1646 // is not the last one called by ExitBootServices(), so we have to
1647 // preserve the memory contents.
1650 Status
= EFI_INVALID_PARAMETER
;
1653 CoreReleaseMemoryLock ();