3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI Memory page management
27 #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
30 // Entry for tracking the memory regions for each memory type to help cooalese like memory types
33 EFI_PHYSICAL_ADDRESS BaseAddress
;
34 EFI_PHYSICAL_ADDRESS MaximumAddress
;
35 UINT64 CurrentNumberOfPages
;
36 UINTN InformationIndex
;
37 } EFI_MEMORY_TYPE_STAISTICS
;
40 // MemoryMap - The current memory map
42 UINTN mMemoryMapKey
= 0;
45 // mMapStack - space to use as temp storage to build new map descriptors
46 // mMapDepth - depth of new descriptor stack
49 #define MAX_MAP_DEPTH 6
51 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
52 UINTN mFreeMapStack
= 0;
54 // This list maintain the free memory map list
56 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
57 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
59 EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
60 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiReservedMemoryType
61 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiLoaderCode
62 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiLoaderData
63 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiBootServicesCode
64 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiBootServicesData
65 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiRuntimeServicesCode
66 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiRuntimeServicesData
67 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiConventionalMemory
68 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiUnusableMemory
69 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiACPIReclaimMemory
70 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiACPIMemoryNVS
71 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiMemoryMappedIO
72 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiMemoryMappedIOPortSpace
73 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiPalCode
74 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
} // EfiMaxMemoryType
77 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= EFI_MAX_ADDRESS
;
79 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
80 { EfiReservedMemoryType
, 0 },
83 { EfiBootServicesCode
, 0 },
84 { EfiBootServicesData
, 0 },
85 { EfiRuntimeServicesCode
, 0 },
86 { EfiRuntimeServicesData
, 0 },
87 { EfiConventionalMemory
, 0 },
88 { EfiUnusableMemory
, 0 },
89 { EfiACPIReclaimMemory
, 0 },
90 { EfiACPIMemoryNVS
, 0 },
91 { EfiMemoryMappedIO
, 0 },
92 { EfiMemoryMappedIOPortSpace
, 0 },
94 { EfiMaxMemoryType
, 0 }
98 // Internal prototypes
102 PromoteMemoryResource (
109 IN EFI_MEMORY_TYPE Type
,
110 IN EFI_PHYSICAL_ADDRESS Start
,
111 IN EFI_PHYSICAL_ADDRESS End
,
117 CoreFreeMemoryMapStack (
125 IN UINT64 NumberOfPages
,
126 IN EFI_MEMORY_TYPE NewType
131 RemoveMemoryMapEntry (
137 AllocateMemoryMapEntry (
142 CoreAcquireMemoryLock (
149 Enter critical section by gaining lock on gMemoryLock
161 CoreAcquireLock (&gMemoryLock
);
166 CoreReleaseMemoryLock (
173 Exit critical section by releasing lock on gMemoryLock
185 CoreReleaseLock (&gMemoryLock
);
190 PromoteMemoryResource (
197 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
210 EFI_GCD_MAP_ENTRY
*Entry
;
212 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "Promote the memory resource\n"));
214 CoreAcquireGcdMemoryLock ();
216 Link
= mGcdMemorySpaceMap
.ForwardLink
;
217 while (Link
!= &mGcdMemorySpaceMap
) {
219 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
221 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
222 Entry
->EndAddress
< EFI_MAX_ADDRESS
&&
223 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
224 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
226 // Update the GCD map
228 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
229 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
230 Entry
->ImageHandle
= gDxeCoreImageHandle
;
231 Entry
->DeviceHandle
= NULL
;
234 // Add to allocable system memory resource
238 EfiConventionalMemory
,
241 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
243 CoreFreeMemoryMapStack ();
247 Link
= Link
->ForwardLink
;
250 CoreReleaseGcdMemoryLock ();
256 CoreAddMemoryDescriptor (
257 IN EFI_MEMORY_TYPE Type
,
258 IN EFI_PHYSICAL_ADDRESS Start
,
259 IN UINT64 NumberOfPages
,
266 Called to initialize the memory map and add descriptors to
267 the current descriptor list.
269 The first descriptor that is added must be general usable
270 memory as the addition allocates heap.
274 Type - The type of memory to add
276 Start - The starting address in the memory range
279 NumberOfPages - The number of pages in the range
281 Attribute - Attributes of the memory to add
285 None. The range is added to the memory map
289 EFI_PHYSICAL_ADDRESS End
;
294 if ((Start
& EFI_PAGE_MASK
) != 0) {
298 if (Type
>= EfiMaxMemoryType
&& Type
<= 0x7fffffff) {
302 CoreAcquireMemoryLock ();
303 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
304 CoreAddRange (Type
, Start
, End
, Attribute
);
305 CoreFreeMemoryMapStack ();
306 CoreReleaseMemoryLock ();
309 // Check to see if the statistics for the different memory types have already been established
311 if (mMemoryTypeInformationInitialized
) {
316 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
318 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
320 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
322 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
323 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
327 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
329 // Allocate pages for the current memory type from the top of available memory
331 Status
= CoreAllocatePages (
334 gMemoryTypeInformation
[Index
].NumberOfPages
,
335 &mMemoryTypeStatistics
[Type
].BaseAddress
337 if (EFI_ERROR (Status
)) {
339 // If an error occurs allocating the pages for the current memory type, then
340 // free all the pages allocates for the previous memory types and return. This
341 // operation with be retied when/if more memory is added to the system
343 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
345 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
347 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
348 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
352 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
354 mMemoryTypeStatistics
[Type
].BaseAddress
,
355 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
357 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
358 mMemoryTypeStatistics
[Type
].MaximumAddress
= EFI_MAX_ADDRESS
;
365 // Compute the address at the top of the current statistics
367 mMemoryTypeStatistics
[Type
].MaximumAddress
=
368 mMemoryTypeStatistics
[Type
].BaseAddress
+
369 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
372 // If the current base address is the lowest address so far, then update the default
375 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
376 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
382 // There was enough system memory for all the the memory types were allocated. So,
383 // those memory areas can be freed for future allocations, and all future memory
384 // allocations can occur within their respective bins
386 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
388 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
390 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
391 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
395 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
397 mMemoryTypeStatistics
[Type
].BaseAddress
,
398 gMemoryTypeInformation
[Index
].NumberOfPages
400 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
405 // If the number of pages reserved for a memory type is 0, then all allocations for that type
406 // should be in the default range.
408 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
409 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
410 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
411 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
414 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
415 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== EFI_MAX_ADDRESS
) {
416 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
420 mMemoryTypeInformationInitialized
= TRUE
;
427 IN EFI_MEMORY_TYPE Type
,
428 IN EFI_PHYSICAL_ADDRESS Start
,
429 IN EFI_PHYSICAL_ADDRESS End
,
436 Internal function. Adds a ranges to the memory map.
437 The range must not already exist in the map.
441 Type - The type of memory range to add
443 Start - The starting address in the memory range
444 Must be paged aligned
446 End - The last address in the range
447 Must be the last byte of a page
449 Attribute - The attributes of the memory range to add
453 None. The range is added to the memory map
460 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
461 ASSERT (End
> Start
) ;
463 ASSERT_LOCKED (&gMemoryLock
);
465 DEBUG ((EFI_D_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
468 // Memory map being altered so updated key
473 // UEFI 2.0 added an event group for notificaiton on memory map changes.
474 // So we need to signal this Event Group every time the memory map changes.
475 // If we are in EFI 1.10 compatability mode no event groups will be
476 // found and nothing will happen we we call this function. These events
477 // will get signaled but since a lock is held around the call to this
478 // function the notificaiton events will only be called after this funciton
479 // returns and the lock is released.
481 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
484 // Look for adjoining memory descriptor
487 // Two memory descriptors can only be merged if they have the same Type
488 // and the same Attribute
491 Link
= gMemoryMap
.ForwardLink
;
492 while (Link
!= &gMemoryMap
) {
493 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
494 Link
= Link
->ForwardLink
;
496 if (Entry
->Type
!= Type
) {
500 if (Entry
->Attribute
!= Attribute
) {
504 if (Entry
->End
+ 1 == Start
) {
506 Start
= Entry
->Start
;
507 RemoveMemoryMapEntry (Entry
);
509 } else if (Entry
->Start
== End
+ 1) {
512 RemoveMemoryMapEntry (Entry
);
520 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
521 mMapStack
[mMapDepth
].FromPages
= FALSE
;
522 mMapStack
[mMapDepth
].Type
= Type
;
523 mMapStack
[mMapDepth
].Start
= Start
;
524 mMapStack
[mMapDepth
].End
= End
;
525 mMapStack
[mMapDepth
].VirtualStart
= 0;
526 mMapStack
[mMapDepth
].Attribute
= Attribute
;
527 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
530 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
537 CoreFreeMemoryMapStack (
544 Internal function. Moves any memory descriptors that are on the
545 temporary descriptor stack to heap.
561 ASSERT_LOCKED (&gMemoryLock
);
564 // If already freeing the map stack, then return
571 // Move the temporary memory descriptor stack into pool
577 // Deque an memory map entry from mFreeMemoryMapEntryList
579 Entry
= AllocateMemoryMapEntry ();
584 // Update to proper entry
588 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
591 // Move this entry to general memory
593 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
594 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
596 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
597 Entry
->FromPages
= TRUE
;
600 // Find insertion location
602 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
603 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
604 if (Entry2
->FromPages
&& Entry2
->Start
> Entry
->Start
) {
609 InsertTailList (Link2
, &Entry
->Link
);
613 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
614 // so here no need to move it to memory.
616 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
625 RemoveMemoryMapEntry (
632 Internal function. Removes a descriptor entry.
636 Entry - The entry to remove
644 RemoveEntryList (&Entry
->Link
);
645 Entry
->Link
.ForwardLink
= NULL
;
647 if (Entry
->FromPages
) {
649 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
651 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
657 AllocateMemoryMapEntry (
664 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
665 If the list is emtry, then allocate a new page to refuel the list.
666 Please Note this algorithm to allocate the memory map descriptor has a property
667 that the memory allocated for memory entries always grows, and will never really be freed
668 For example, if the current boot uses 2000 memory map entries at the maximum point, but
669 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
670 memory map entries is still allocated from EfiBootServicesMemory.
678 The Memory map descriptor dequed from the mFreeMemoryMapEntryList
682 MEMORY_MAP
* FreeDescriptorEntries
;
686 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
688 // The list is empty, to allocate one page to refuel the list
690 FreeDescriptorEntries
= CoreAllocatePoolPages (EfiBootServicesData
, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
691 if(FreeDescriptorEntries
!= NULL
) {
693 // Enque the free memmory map entries into the list
695 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION
/ sizeof(MEMORY_MAP
); Index
++) {
696 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
697 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
704 // dequeue the first descriptor from the list
706 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
707 RemoveEntryList (&Entry
->Link
);
716 IN UINT64 NumberOfPages
,
717 IN EFI_MEMORY_TYPE NewType
723 Internal function. Converts a memory range to the specified type.
724 The range must exist in the memory map.
728 Start - The first address of the range
731 NumberOfPages - The number of pages to convert
733 NewType - The new type for the memory range
737 EFI_INVALID_PARAMETER - Invalid parameter
739 EFI_NOT_FOUND - Could not find a descriptor cover the specified range
740 or convertion not allowed.
742 EFI_SUCCESS - Successfully converts the memory range to the specified type.
747 UINT64 NumberOfBytes
;
755 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
756 End
= Start
+ NumberOfBytes
- 1;
758 ASSERT (NumberOfPages
);
759 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
760 ASSERT (End
> Start
) ;
761 ASSERT_LOCKED (&gMemoryLock
);
763 if (NumberOfPages
== 0 || (Start
& EFI_PAGE_MASK
) || (Start
> (Start
+ NumberOfBytes
))) {
764 return EFI_INVALID_PARAMETER
;
768 // Convert the entire range
771 while (Start
< End
) {
774 // Find the entry that the covers the range
776 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
777 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
779 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
784 if (Link
== &gMemoryMap
) {
785 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
786 return EFI_NOT_FOUND
;
790 // Convert range to the end, or to the end of the descriptor
791 // if that's all we've got
794 if (Entry
->End
< End
) {
795 RangeEnd
= Entry
->End
;
798 DEBUG ((EFI_D_PAGE
, "ConvertRange: %lx-%lx to %d\n", Start
, RangeEnd
, NewType
));
801 // Debug code - verify conversion is allowed
803 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
804 DEBUG ((EFI_D_ERROR
, "ConvertPages: Incompatible memory types\n"));
805 return EFI_NOT_FOUND
;
809 // Update counters for the number of pages allocated to each memory type
811 if (Entry
->Type
>= 0 && Entry
->Type
< EfiMaxMemoryType
) {
812 if (Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&&
813 Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) {
814 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
815 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
817 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
822 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
) {
823 if (Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
824 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
825 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
>
826 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
827 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
833 // Pull range out of descriptor
835 if (Entry
->Start
== Start
) {
840 Entry
->Start
= RangeEnd
+ 1;
842 } else if (Entry
->End
== RangeEnd
) {
847 Entry
->End
= Start
- 1;
852 // Pull it out of the center, clip current
858 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
859 mMapStack
[mMapDepth
].FromPages
= FALSE
;
860 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
861 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
862 mMapStack
[mMapDepth
].End
= Entry
->End
;
865 // Inherit Attribute from the Memory Descriptor that is being clipped
867 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
869 Entry
->End
= Start
- 1;
870 ASSERT (Entry
->Start
< Entry
->End
);
872 Entry
= &mMapStack
[mMapDepth
];
873 InsertTailList (&gMemoryMap
, &Entry
->Link
);
876 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
880 // The new range inherits the same Attribute as the Entry
881 //it is being cut out of
883 Attribute
= Entry
->Attribute
;
886 // If the descriptor is empty, then remove it from the map
888 if (Entry
->Start
== Entry
->End
+ 1) {
889 RemoveMemoryMapEntry (Entry
);
894 // Add our new range in
896 CoreAddRange (NewType
, Start
, RangeEnd
, Attribute
);
899 // Move any map descriptor stack to general pool
901 CoreFreeMemoryMapStack ();
904 // Bump the starting address, and convert the next range
906 Start
= RangeEnd
+ 1;
910 // Converted the whole range, done
920 IN UINT64 MaxAddress
,
921 IN UINT64 NumberOfPages
,
922 IN EFI_MEMORY_TYPE NewType
,
929 Internal function. Finds a consecutive free page range below
930 the requested address.
934 MaxAddress - The address that the range must be below
936 NumberOfPages - Number of pages needed
938 NewType - The type of memory the range is going to be turned into
940 Alignment - Bits to align with
944 The base address of the range, or 0 if the range was not found
948 UINT64 NumberOfBytes
;
952 UINT64 DescNumberOfBytes
;
956 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
960 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
963 // If MaxAddress is not aligned to the end of a page
967 // Change MaxAddress to be 1 page lower
969 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
972 // Set MaxAddress to a page boundary
974 MaxAddress
&= ~EFI_PAGE_MASK
;
977 // Set MaxAddress to end of the page
979 MaxAddress
|= EFI_PAGE_MASK
;
982 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
985 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
986 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
989 // If it's not a free entry, don't bother with it
991 if (Entry
->Type
!= EfiConventionalMemory
) {
995 DescStart
= Entry
->Start
;
996 DescEnd
= Entry
->End
;
999 // If desc is past max allowed address, skip it
1001 if (DescStart
>= MaxAddress
) {
1006 // If desc ends past max allowed address, clip the end
1008 if (DescEnd
>= MaxAddress
) {
1009 DescEnd
= MaxAddress
;
1012 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
1015 // Compute the number of bytes we can used from this
1016 // descriptor, and see it's enough to satisfy the request
1018 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
1020 if (DescNumberOfBytes
>= NumberOfBytes
) {
1023 // If this is the best match so far remember it
1025 if (DescEnd
> Target
) {
1032 // If this is a grow down, adjust target to be the allocation base
1034 Target
-= NumberOfBytes
- 1;
1037 // If we didn't find a match, return 0
1039 if ((Target
& EFI_PAGE_MASK
) != 0) {
1049 IN UINT64 MaxAddress
,
1051 IN EFI_MEMORY_TYPE NewType
,
1056 Routine Description:
1058 Internal function. Finds a consecutive free page range below
1059 the requested address
1063 MaxAddress - The address that the range must be below
1065 NoPages - Number of pages needed
1067 NewType - The type of memory the range is going to be turned into
1069 Alignment - Bits to align with
1073 The base address of the range, or 0 if the range was not found.
1077 UINT64 NewMaxAddress
;
1080 NewMaxAddress
= MaxAddress
;
1082 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
&& NewMaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1083 NewMaxAddress
= mMemoryTypeStatistics
[NewType
].MaximumAddress
;
1085 if (NewMaxAddress
> mDefaultMaximumAddress
) {
1086 NewMaxAddress
= mDefaultMaximumAddress
;
1090 Start
= CoreFindFreePagesI (NewMaxAddress
, NoPages
, NewType
, Alignment
);
1092 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1095 // Here means there may be no enough memory to use, so try to go through
1096 // all the memory descript to promote the untested memory directly
1098 PromoteMemoryResource ();
1101 // Allocate memory again after the memory resource re-arranged
1103 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1114 IN EFI_ALLOCATE_TYPE Type
,
1115 IN EFI_MEMORY_TYPE MemoryType
,
1116 IN UINTN NumberOfPages
,
1117 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
1121 Routine Description:
1123 Allocates pages from the memory map.
1127 Type - The type of allocation to perform
1129 MemoryType - The type of memory to turn the allocated pages into
1131 NumberOfPages - The number of pages to allocate
1133 Memory - A pointer to receive the base allocated memory address
1137 Status. On success, Memory is filled in with the base address allocated
1139 EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec.
1141 EFI_NOT_FOUND - Could not allocate pages match the requirement.
1143 EFI_OUT_OF_RESOURCES - No enough pages to allocate.
1145 EFI_SUCCESS - Pages successfully allocated.
1154 if (Type
< AllocateAnyPages
|| Type
>= (UINTN
) MaxAllocateType
) {
1155 return EFI_INVALID_PARAMETER
;
1158 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
<= 0x7fffffff) ||
1159 MemoryType
== EfiConventionalMemory
) {
1160 return EFI_INVALID_PARAMETER
;
1163 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1165 if (MemoryType
== EfiACPIReclaimMemory
||
1166 MemoryType
== EfiACPIMemoryNVS
||
1167 MemoryType
== EfiRuntimeServicesCode
||
1168 MemoryType
== EfiRuntimeServicesData
) {
1170 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1173 if (Type
== AllocateAddress
) {
1174 if ((*Memory
& (Alignment
- 1)) != 0) {
1175 return EFI_NOT_FOUND
;
1179 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1180 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1183 // If this is for below a particular address, then
1188 // The max address is the max natively addressable address for the processor
1190 MaxAddress
= EFI_MAX_ADDRESS
;
1192 if (Type
== AllocateMaxAddress
) {
1196 CoreAcquireMemoryLock ();
1199 // If not a specific address, then find an address to allocate
1201 if (Type
!= AllocateAddress
) {
1202 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
);
1204 Status
= EFI_OUT_OF_RESOURCES
;
1210 // Convert pages from FreeMemory to the requested type
1212 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1215 CoreReleaseMemoryLock ();
1217 if (!EFI_ERROR (Status
)) {
1230 IN EFI_PHYSICAL_ADDRESS Memory
,
1231 IN UINTN NumberOfPages
1235 Routine Description:
1237 Frees previous allocated pages.
1241 Memory - Base address of memory being freed
1243 NumberOfPages - The number of pages to free
1247 EFI_NOT_FOUND - Could not find the entry that covers the range
1249 EFI_INVALID_PARAMETER - Address not aligned
1251 EFI_SUCCESS -Pages successfully freed.
1263 CoreAcquireMemoryLock ();
1266 // Find the entry that the covers the range
1269 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1270 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1271 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1275 if (Link
== &gMemoryMap
) {
1276 CoreReleaseMemoryLock ();
1277 return EFI_NOT_FOUND
;
1280 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1282 if (Entry
->Type
== EfiACPIReclaimMemory
||
1283 Entry
->Type
== EfiACPIMemoryNVS
||
1284 Entry
->Type
== EfiRuntimeServicesCode
||
1285 Entry
->Type
== EfiRuntimeServicesData
) {
1287 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1291 if ((Memory
& (Alignment
- 1)) != 0) {
1292 CoreReleaseMemoryLock ();
1293 return EFI_INVALID_PARAMETER
;
1296 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1297 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1299 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1301 CoreReleaseMemoryLock ();
1303 if (EFI_ERROR (Status
)) {
1308 // Destroy the contents
1310 if (Memory
< EFI_MAX_ADDRESS
) {
1311 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Memory
, NumberOfPages
<< EFI_PAGE_SHIFT
);
1322 IN OUT UINTN
*MemoryMapSize
,
1323 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1325 OUT UINTN
*DescriptorSize
,
1326 OUT UINT32
*DescriptorVersion
1330 Routine Description:
1332 This function returns a copy of the current memory map. The map is an array of
1333 memory descriptors, each of which describes a contiguous block of memory.
1337 MemoryMapSize - A pointer to the size, in bytes, of the MemoryMap buffer. On
1338 input, this is the size of the buffer allocated by the caller.
1339 On output, it is the size of the buffer returned by the firmware
1340 if the buffer was large enough, or the size of the buffer needed
1341 to contain the map if the buffer was too small.
1342 MemoryMap - A pointer to the buffer in which firmware places the current memory map.
1343 MapKey - A pointer to the location in which firmware returns the key for the
1345 DescriptorSize - A pointer to the location in which firmware returns the size, in
1346 bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1347 DescriptorVersion - A pointer to the location in which firmware returns the version
1348 number associated with the EFI_MEMORY_DESCRIPTOR.
1352 EFI_SUCCESS - The memory map was returned in the MemoryMap buffer.
1353 EFI_BUFFER_TOO_SMALL - The MemoryMap buffer was too small. The current buffer size
1354 needed to hold the memory map is returned in MemoryMapSize.
1355 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
1362 UINTN NumberOfRuntimeEntries
;
1365 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1368 // Make sure the parameters are valid
1370 if (MemoryMapSize
== NULL
) {
1371 return EFI_INVALID_PARAMETER
;
1374 CoreAcquireGcdMemoryLock ();
1377 // Count the number of Reserved and MMIO entries that are marked for runtime use
1379 NumberOfRuntimeEntries
= 0;
1380 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1381 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1382 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1383 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1384 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1385 NumberOfRuntimeEntries
++;
1390 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1393 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1394 // prevent people from having pointer math bugs in their code.
1395 // now you have to use *DescriptorSize to make things work.
1397 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1399 if (DescriptorSize
!= NULL
) {
1400 *DescriptorSize
= Size
;
1403 if (DescriptorVersion
!= NULL
) {
1404 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1407 CoreAcquireMemoryLock ();
1410 // Compute the buffer size needed to fit the entire map
1412 BufferSize
= Size
* NumberOfRuntimeEntries
;
1413 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1417 if (*MemoryMapSize
< BufferSize
) {
1418 Status
= EFI_BUFFER_TOO_SMALL
;
1422 if (MemoryMap
== NULL
) {
1423 Status
= EFI_INVALID_PARAMETER
;
1430 ZeroMem (MemoryMap
, Size
);
1431 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1432 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1433 ASSERT (Entry
->VirtualStart
== 0);
1435 MemoryMap
->Type
= Entry
->Type
;
1436 MemoryMap
->PhysicalStart
= Entry
->Start
;
1437 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1438 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1440 switch (Entry
->Type
) {
1441 case EfiRuntimeServicesCode
:
1442 case EfiRuntimeServicesData
:
1444 MemoryMap
->Attribute
= Entry
->Attribute
| EFI_MEMORY_RUNTIME
;
1448 MemoryMap
->Attribute
= Entry
->Attribute
;
1452 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1455 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1456 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1457 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1458 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1459 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1461 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1462 MemoryMap
->VirtualStart
= 0;
1463 MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1464 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
& ~EFI_MEMORY_PORT_IO
;
1466 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1467 MemoryMap
->Type
= EfiReservedMemoryType
;
1468 } else if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1469 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1470 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1472 MemoryMap
->Type
= EfiMemoryMappedIO
;
1476 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1481 Status
= EFI_SUCCESS
;
1485 CoreReleaseMemoryLock ();
1487 CoreReleaseGcdMemoryLock ();
1490 // Update the map key finally
1492 if (MapKey
!= NULL
) {
1493 *MapKey
= mMemoryMapKey
;
1496 *MemoryMapSize
= BufferSize
;
1502 CoreAllocatePoolPages (
1503 IN EFI_MEMORY_TYPE PoolType
,
1504 IN UINTN NumberOfPages
,
1509 Routine Description:
1511 Internal function. Used by the pool functions to allocate pages
1512 to back pool allocation requests.
1516 PoolType - The type of memory for the new pool pages
1518 NumberOfPages - No of pages to allocate
1520 Alignment - Bits to align.
1524 The allocated memory, or NULL
1531 // Find the pages to convert
1533 Start
= FindFreePages (EFI_MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
);
1536 // Convert it to boot services data
1539 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages
));
1541 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1544 return (VOID
*)(UINTN
)Start
;
1549 IN EFI_PHYSICAL_ADDRESS Memory
,
1550 IN UINTN NumberOfPages
1554 Routine Description:
1556 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1560 Memory - The base address to free
1562 NumberOfPages - The number of pages to free
1570 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1575 CoreTerminateMemoryMap (
1580 Routine Description:
1582 Make sure the memory map is following all the construction rules,
1583 it is the last time to check memory map error before exit boot services.
1587 MapKey - Memory map key
1591 EFI_INVALID_PARAMETER - Memory map not consistent with construction rules.
1593 EFI_SUCCESS - Valid memory map.
1601 Status
= EFI_SUCCESS
;
1603 CoreAcquireMemoryLock ();
1605 if (MapKey
== mMemoryMapKey
) {
1608 // Make sure the memory map is following all the construction rules
1609 // This is the last chance we will be able to display any messages on
1610 // the console devices.
1613 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1614 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1615 if (Entry
->Attribute
& EFI_MEMORY_RUNTIME
) {
1616 if (Entry
->Type
== EfiACPIReclaimMemory
|| Entry
->Type
== EfiACPIMemoryNVS
) {
1617 DEBUG((EFI_D_ERROR
, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1618 CoreReleaseMemoryLock ();
1619 return EFI_INVALID_PARAMETER
;
1621 if (Entry
->Start
& (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1622 DEBUG((EFI_D_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1623 CoreReleaseMemoryLock ();
1624 return EFI_INVALID_PARAMETER
;
1626 if ((Entry
->End
+ 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1627 DEBUG((EFI_D_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1628 CoreReleaseMemoryLock ();
1629 return EFI_INVALID_PARAMETER
;
1635 // The map key they gave us matches what we expect. Fall through and
1636 // return success. In an ideal world we would clear out all of
1637 // EfiBootServicesCode and EfiBootServicesData. However this function
1638 // is not the last one called by ExitBootServices(), so we have to
1639 // preserve the memory contents.
1642 Status
= EFI_INVALID_PARAMETER
;
1645 CoreReleaseMemoryLock ();