3 Copyright (c) 2006, 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 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
56 EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
57 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiReservedMemoryType
58 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiLoaderCode
59 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiLoaderData
60 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiBootServicesCode
61 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiBootServicesData
62 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiRuntimeServicesCode
63 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiRuntimeServicesData
64 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiConventionalMemory
65 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiUnusableMemory
66 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiACPIReclaimMemory
67 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiACPIMemoryNVS
68 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiMemoryMappedIO
69 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiMemoryMappedIOPortSpace
70 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
}, // EfiPalCode
71 { 0, EFI_MAX_ADDRESS
, 0, EfiMaxMemoryType
} // EfiMaxMemoryType
74 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= EFI_MAX_ADDRESS
;
76 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
77 { EfiReservedMemoryType
, 0 },
80 { EfiBootServicesCode
, 0 },
81 { EfiBootServicesData
, 0 },
82 { EfiRuntimeServicesCode
, 0 },
83 { EfiRuntimeServicesData
, 0 },
84 { EfiConventionalMemory
, 0 },
85 { EfiUnusableMemory
, 0 },
86 { EfiACPIReclaimMemory
, 0 },
87 { EfiACPIMemoryNVS
, 0 },
88 { EfiMemoryMappedIO
, 0 },
89 { EfiMemoryMappedIOPortSpace
, 0 },
91 { EfiMaxMemoryType
, 0 }
95 // Internal prototypes
99 PromoteMemoryResource (
106 IN EFI_MEMORY_TYPE Type
,
107 IN EFI_PHYSICAL_ADDRESS Start
,
108 IN EFI_PHYSICAL_ADDRESS End
,
114 CoreFreeMemoryMapStack (
122 IN UINT64 NumberOfPages
,
123 IN EFI_MEMORY_TYPE NewType
128 RemoveMemoryMapEntry (
133 CoreAcquireMemoryLock (
140 Enter critical section by gaining lock on gMemoryLock
152 CoreAcquireLock (&gMemoryLock
);
157 CoreReleaseMemoryLock (
164 Exit critical section by releasing lock on gMemoryLock
176 CoreReleaseLock (&gMemoryLock
);
181 PromoteMemoryResource (
188 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
201 EFI_GCD_MAP_ENTRY
*Entry
;
203 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "Promote the memory resource\n"));
205 CoreAcquireGcdMemoryLock ();
207 Link
= mGcdMemorySpaceMap
.ForwardLink
;
208 while (Link
!= &mGcdMemorySpaceMap
) {
210 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
212 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
213 Entry
->EndAddress
< EFI_MAX_ADDRESS
&&
214 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
215 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
217 // Update the GCD map
219 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
220 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
221 Entry
->ImageHandle
= gDxeCoreImageHandle
;
222 Entry
->DeviceHandle
= NULL
;
225 // Add to allocable system memory resource
229 EfiConventionalMemory
,
232 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
234 CoreFreeMemoryMapStack ();
238 Link
= Link
->ForwardLink
;
241 CoreReleaseGcdMemoryLock ();
247 CoreAddMemoryDescriptor (
248 IN EFI_MEMORY_TYPE Type
,
249 IN EFI_PHYSICAL_ADDRESS Start
,
250 IN UINT64 NumberOfPages
,
257 Called to initialize the memory map and add descriptors to
258 the current descriptor list.
260 The first descriptor that is added must be general usable
261 memory as the addition allocates heap.
265 Type - The type of memory to add
267 Start - The starting address in the memory range
270 NumberOfPages - The number of pages in the range
272 Attribute - Attributes of the memory to add
276 None. The range is added to the memory map
280 EFI_PHYSICAL_ADDRESS End
;
285 if ((Start
& EFI_PAGE_MASK
) != 0) {
289 if (Type
>= EfiMaxMemoryType
&& Type
<= 0x7fffffff) {
293 CoreAcquireMemoryLock ();
294 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
295 CoreAddRange (Type
, Start
, End
, Attribute
);
296 CoreFreeMemoryMapStack ();
297 CoreReleaseMemoryLock ();
300 // Check to see if the statistics for the different memory types have already been established
302 if (mMemoryTypeInformationInitialized
) {
307 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
309 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
311 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
313 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
314 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
318 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
320 // Allocate pages for the current memory type from the top of available memory
322 Status
= CoreAllocatePages (
325 gMemoryTypeInformation
[Index
].NumberOfPages
,
326 &mMemoryTypeStatistics
[Type
].BaseAddress
328 if (EFI_ERROR (Status
)) {
330 // If an error occurs allocating the pages for the current memory type, then
331 // free all the pages allocates for the previous memory types and return. This
332 // operation with be retied when/if more memory is added to the system
334 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
336 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
338 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
339 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
343 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
345 mMemoryTypeStatistics
[Type
].BaseAddress
,
346 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
348 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
349 mMemoryTypeStatistics
[Type
].MaximumAddress
= EFI_MAX_ADDRESS
;
356 // Compute the address at the top of the current statistics
358 mMemoryTypeStatistics
[Type
].MaximumAddress
=
359 mMemoryTypeStatistics
[Type
].BaseAddress
+
360 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
363 // If the current base address is the lowest address so far, then update the default
366 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
367 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
373 // There was enough system memory for all the the memory types were allocated. So,
374 // those memory areas can be freed for future allocations, and all future memory
375 // allocations can occur within their respective bins
377 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
379 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
381 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
382 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
386 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
388 mMemoryTypeStatistics
[Type
].BaseAddress
,
389 gMemoryTypeInformation
[Index
].NumberOfPages
391 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
396 // If the number of pages reserved for a memory type is 0, then all allocations for that type
397 // should be in the default range.
399 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
400 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
401 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
402 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
405 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
406 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== EFI_MAX_ADDRESS
) {
407 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
411 mMemoryTypeInformationInitialized
= TRUE
;
418 IN EFI_MEMORY_TYPE Type
,
419 IN EFI_PHYSICAL_ADDRESS Start
,
420 IN EFI_PHYSICAL_ADDRESS End
,
427 Internal function. Adds a ranges to the memory map.
428 The range must not already exist in the map.
432 Type - The type of memory range to add
434 Start - The starting address in the memory range
435 Must be paged aligned
437 End - The last address in the range
438 Must be the last byte of a page
440 Attribute - The attributes of the memory range to add
444 None. The range is added to the memory map
451 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
452 ASSERT (End
> Start
) ;
454 ASSERT_LOCKED (&gMemoryLock
);
456 DEBUG ((EFI_D_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
459 // Memory map being altered so updated key
464 // UEFI 2.0 added an event group for notificaiton on memory map changes.
465 // So we need to signal this Event Group every time the memory map changes.
466 // If we are in EFI 1.10 compatability mode no event groups will be
467 // found and nothing will happen we we call this function. These events
468 // will get signaled but since a lock is held around the call to this
469 // function the notificaiton events will only be called after this funciton
470 // returns and the lock is released.
472 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
475 // Look for adjoining memory descriptor
478 // Two memory descriptors can only be merged if they have the same Type
479 // and the same Attribute
482 Link
= gMemoryMap
.ForwardLink
;
483 while (Link
!= &gMemoryMap
) {
484 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
485 Link
= Link
->ForwardLink
;
487 if (Entry
->Type
!= Type
) {
491 if (Entry
->Attribute
!= Attribute
) {
495 if (Entry
->End
+ 1 == Start
) {
497 Start
= Entry
->Start
;
498 RemoveMemoryMapEntry (Entry
);
500 } else if (Entry
->Start
== End
+ 1) {
503 RemoveMemoryMapEntry (Entry
);
511 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
512 mMapStack
[mMapDepth
].FromPool
= FALSE
;
513 mMapStack
[mMapDepth
].Type
= Type
;
514 mMapStack
[mMapDepth
].Start
= Start
;
515 mMapStack
[mMapDepth
].End
= End
;
516 mMapStack
[mMapDepth
].VirtualStart
= 0;
517 mMapStack
[mMapDepth
].Attribute
= Attribute
;
518 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
521 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
528 CoreFreeMemoryMapStack (
535 Internal function. Moves any memory descriptors that are on the
536 temporary descriptor stack to heap.
552 ASSERT_LOCKED (&gMemoryLock
);
555 // If already freeing the map stack, then return
562 // Move the temporary memory descriptor stack into pool
569 // Allocate memory for a entry
571 Entry
= CoreAllocatePoolI (EfiRuntimeServicesData
, sizeof(MEMORY_MAP
));
576 // Update to proper entry
580 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
583 // Move this entry to general pool
585 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
586 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
588 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
589 Entry
->FromPool
= TRUE
;
592 // Find insertion location
594 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
595 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
596 if (Entry2
->FromPool
&& Entry2
->Start
> Entry
->Start
) {
601 InsertTailList (Link2
, &Entry
->Link
);
606 // It was removed, don't move it
608 CoreFreePoolI (Entry
);
618 RemoveMemoryMapEntry (
625 Internal function. Removes a descriptor entry.
629 Entry - The entry to remove
637 RemoveEntryList (&Entry
->Link
);
638 Entry
->Link
.ForwardLink
= NULL
;
640 if (Entry
->FromPool
) {
641 CoreFreePoolI (Entry
);
650 IN UINT64 NumberOfPages
,
651 IN EFI_MEMORY_TYPE NewType
657 Internal function. Converts a memory range to the specified type.
658 The range must exist in the memory map.
662 Start - The first address of the range
665 NumberOfPages - The number of pages to convert
667 NewType - The new type for the memory range
671 EFI_INVALID_PARAMETER - Invalid parameter
673 EFI_NOT_FOUND - Could not find a descriptor cover the specified range
674 or convertion not allowed.
676 EFI_SUCCESS - Successfully converts the memory range to the specified type.
681 UINT64 NumberOfBytes
;
689 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
690 End
= Start
+ NumberOfBytes
- 1;
692 ASSERT (NumberOfPages
);
693 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
694 ASSERT (End
> Start
) ;
695 ASSERT_LOCKED (&gMemoryLock
);
697 if (NumberOfPages
== 0 || (Start
& EFI_PAGE_MASK
) || (Start
> (Start
+ NumberOfBytes
))) {
698 return EFI_INVALID_PARAMETER
;
702 // Convert the entire range
705 while (Start
< End
) {
708 // Find the entry that the covers the range
710 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
711 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
713 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
718 if (Link
== &gMemoryMap
) {
719 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
720 return EFI_NOT_FOUND
;
724 // Convert range to the end, or to the end of the descriptor
725 // if that's all we've got
728 if (Entry
->End
< End
) {
729 RangeEnd
= Entry
->End
;
732 DEBUG ((EFI_D_PAGE
, "ConvertRange: %lx-%lx to %d\n", Start
, RangeEnd
, NewType
));
735 // Debug code - verify conversion is allowed
737 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
738 DEBUG ((EFI_D_ERROR
, "ConvertPages: Incompatible memory types\n"));
739 return EFI_NOT_FOUND
;
743 // Update counters for the number of pages allocated to each memory type
745 if (Entry
->Type
>= 0 && Entry
->Type
< EfiMaxMemoryType
) {
746 if (Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&&
747 Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) {
748 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
749 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
751 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
756 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
) {
757 if (Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
758 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
759 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
>
760 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
761 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
767 // Pull range out of descriptor
769 if (Entry
->Start
== Start
) {
774 Entry
->Start
= RangeEnd
+ 1;
776 } else if (Entry
->End
== RangeEnd
) {
781 Entry
->End
= Start
- 1;
786 // Pull it out of the center, clip current
792 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
793 mMapStack
[mMapDepth
].FromPool
= FALSE
;
794 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
795 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
796 mMapStack
[mMapDepth
].End
= Entry
->End
;
799 // Inherit Attribute from the Memory Descriptor that is being clipped
801 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
803 Entry
->End
= Start
- 1;
804 ASSERT (Entry
->Start
< Entry
->End
);
806 Entry
= &mMapStack
[mMapDepth
];
807 InsertTailList (&gMemoryMap
, &Entry
->Link
);
810 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
814 // The new range inherits the same Attribute as the Entry
815 //it is being cut out of
817 Attribute
= Entry
->Attribute
;
820 // If the descriptor is empty, then remove it from the map
822 if (Entry
->Start
== Entry
->End
+ 1) {
823 RemoveMemoryMapEntry (Entry
);
828 // Add our new range in
830 CoreAddRange (NewType
, Start
, RangeEnd
, Attribute
);
833 // Move any map descriptor stack to general pool
835 CoreFreeMemoryMapStack ();
838 // Bump the starting address, and convert the next range
840 Start
= RangeEnd
+ 1;
844 // Converted the whole range, done
854 IN UINT64 MaxAddress
,
855 IN UINT64 NumberOfPages
,
856 IN EFI_MEMORY_TYPE NewType
,
863 Internal function. Finds a consecutive free page range below
864 the requested address.
868 MaxAddress - The address that the range must be below
870 NumberOfPages - Number of pages needed
872 NewType - The type of memory the range is going to be turned into
874 Alignment - Bits to align with
878 The base address of the range, or 0 if the range was not found
882 UINT64 NumberOfBytes
;
886 UINT64 DescNumberOfBytes
;
890 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
894 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
897 // If MaxAddress is not aligned to the end of a page
901 // Change MaxAddress to be 1 page lower
903 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
906 // Set MaxAddress to a page boundary
908 MaxAddress
&= ~EFI_PAGE_MASK
;
911 // Set MaxAddress to end of the page
913 MaxAddress
|= EFI_PAGE_MASK
;
916 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
919 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
920 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
923 // If it's not a free entry, don't bother with it
925 if (Entry
->Type
!= EfiConventionalMemory
) {
929 DescStart
= Entry
->Start
;
930 DescEnd
= Entry
->End
;
933 // If desc is past max allowed address, skip it
935 if (DescStart
>= MaxAddress
) {
940 // If desc ends past max allowed address, clip the end
942 if (DescEnd
>= MaxAddress
) {
943 DescEnd
= MaxAddress
;
946 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
949 // Compute the number of bytes we can used from this
950 // descriptor, and see it's enough to satisfy the request
952 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
954 if (DescNumberOfBytes
>= NumberOfBytes
) {
957 // If this is the best match so far remember it
959 if (DescEnd
> Target
) {
966 // If this is a grow down, adjust target to be the allocation base
968 Target
-= NumberOfBytes
- 1;
971 // If we didn't find a match, return 0
973 if ((Target
& EFI_PAGE_MASK
) != 0) {
983 IN UINT64 MaxAddress
,
985 IN EFI_MEMORY_TYPE NewType
,
992 Internal function. Finds a consecutive free page range below
993 the requested address
997 MaxAddress - The address that the range must be below
999 NoPages - Number of pages needed
1001 NewType - The type of memory the range is going to be turned into
1003 Alignment - Bits to align with
1007 The base address of the range, or 0 if the range was not found.
1011 UINT64 NewMaxAddress
;
1014 NewMaxAddress
= MaxAddress
;
1016 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
&& NewMaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1017 NewMaxAddress
= mMemoryTypeStatistics
[NewType
].MaximumAddress
;
1019 if (NewMaxAddress
> mDefaultMaximumAddress
) {
1020 NewMaxAddress
= mDefaultMaximumAddress
;
1024 Start
= CoreFindFreePagesI (NewMaxAddress
, NoPages
, NewType
, Alignment
);
1026 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1029 // Here means there may be no enough memory to use, so try to go through
1030 // all the memory descript to promote the untested memory directly
1032 PromoteMemoryResource ();
1035 // Allocate memory again after the memory resource re-arranged
1037 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1048 IN EFI_ALLOCATE_TYPE Type
,
1049 IN EFI_MEMORY_TYPE MemoryType
,
1050 IN UINTN NumberOfPages
,
1051 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
1055 Routine Description:
1057 Allocates pages from the memory map.
1061 Type - The type of allocation to perform
1063 MemoryType - The type of memory to turn the allocated pages into
1065 NumberOfPages - The number of pages to allocate
1067 Memory - A pointer to receive the base allocated memory address
1071 Status. On success, Memory is filled in with the base address allocated
1073 EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec.
1075 EFI_NOT_FOUND - Could not allocate pages match the requirement.
1077 EFI_OUT_OF_RESOURCES - No enough pages to allocate.
1079 EFI_SUCCESS - Pages successfully allocated.
1088 if (Type
< AllocateAnyPages
|| Type
>= (UINTN
) MaxAllocateType
) {
1089 return EFI_INVALID_PARAMETER
;
1092 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
<= 0x7fffffff) ||
1093 MemoryType
== EfiConventionalMemory
) {
1094 return EFI_INVALID_PARAMETER
;
1097 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1099 if (MemoryType
== EfiACPIReclaimMemory
||
1100 MemoryType
== EfiACPIMemoryNVS
||
1101 MemoryType
== EfiRuntimeServicesCode
||
1102 MemoryType
== EfiRuntimeServicesData
) {
1104 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1107 if (Type
== AllocateAddress
) {
1108 if ((*Memory
& (Alignment
- 1)) != 0) {
1109 return EFI_NOT_FOUND
;
1113 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1114 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1117 // If this is for below a particular address, then
1122 // The max address is the max natively addressable address for the processor
1124 MaxAddress
= EFI_MAX_ADDRESS
;
1126 if (Type
== AllocateMaxAddress
) {
1130 CoreAcquireMemoryLock ();
1133 // If not a specific address, then find an address to allocate
1135 if (Type
!= AllocateAddress
) {
1136 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
);
1138 Status
= EFI_OUT_OF_RESOURCES
;
1144 // Convert pages from FreeMemory to the requested type
1146 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1149 CoreReleaseMemoryLock ();
1151 if (!EFI_ERROR (Status
)) {
1164 IN EFI_PHYSICAL_ADDRESS Memory
,
1165 IN UINTN NumberOfPages
1169 Routine Description:
1171 Frees previous allocated pages.
1175 Memory - Base address of memory being freed
1177 NumberOfPages - The number of pages to free
1181 EFI_NOT_FOUND - Could not find the entry that covers the range
1183 EFI_INVALID_PARAMETER - Address not aligned
1185 EFI_SUCCESS -Pages successfully freed.
1197 CoreAcquireMemoryLock ();
1200 // Find the entry that the covers the range
1203 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1204 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1205 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1209 if (Link
== &gMemoryMap
) {
1210 CoreReleaseMemoryLock ();
1211 return EFI_NOT_FOUND
;
1214 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1216 if (Entry
->Type
== EfiACPIReclaimMemory
||
1217 Entry
->Type
== EfiACPIMemoryNVS
||
1218 Entry
->Type
== EfiRuntimeServicesCode
||
1219 Entry
->Type
== EfiRuntimeServicesData
) {
1221 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1225 if ((Memory
& (Alignment
- 1)) != 0) {
1226 CoreReleaseMemoryLock ();
1227 return EFI_INVALID_PARAMETER
;
1230 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1231 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1233 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1235 CoreReleaseMemoryLock ();
1237 if (EFI_ERROR (Status
)) {
1242 // Destroy the contents
1244 if (Memory
< EFI_MAX_ADDRESS
) {
1245 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Memory
, NumberOfPages
<< EFI_PAGE_SHIFT
);
1256 IN OUT UINTN
*MemoryMapSize
,
1257 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1259 OUT UINTN
*DescriptorSize
,
1260 OUT UINT32
*DescriptorVersion
1264 Routine Description:
1266 This function returns a copy of the current memory map. The map is an array of
1267 memory descriptors, each of which describes a contiguous block of memory.
1271 MemoryMapSize - A pointer to the size, in bytes, of the MemoryMap buffer. On
1272 input, this is the size of the buffer allocated by the caller.
1273 On output, it is the size of the buffer returned by the firmware
1274 if the buffer was large enough, or the size of the buffer needed
1275 to contain the map if the buffer was too small.
1276 MemoryMap - A pointer to the buffer in which firmware places the current memory map.
1277 MapKey - A pointer to the location in which firmware returns the key for the
1279 DescriptorSize - A pointer to the location in which firmware returns the size, in
1280 bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1281 DescriptorVersion - A pointer to the location in which firmware returns the version
1282 number associated with the EFI_MEMORY_DESCRIPTOR.
1286 EFI_SUCCESS - The memory map was returned in the MemoryMap buffer.
1287 EFI_BUFFER_TOO_SMALL - The MemoryMap buffer was too small. The current buffer size
1288 needed to hold the memory map is returned in MemoryMapSize.
1289 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
1296 UINTN NumberOfRuntimeEntries
;
1299 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1302 // Make sure the parameters are valid
1304 if (MemoryMapSize
== NULL
) {
1305 return EFI_INVALID_PARAMETER
;
1308 CoreAcquireGcdMemoryLock ();
1311 // Count the number of Reserved and MMIO entries that are marked for runtime use
1313 NumberOfRuntimeEntries
= 0;
1314 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1315 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1316 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1317 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1318 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1319 NumberOfRuntimeEntries
++;
1324 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1327 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1328 // prevent people from having pointer math bugs in their code.
1329 // now you have to use *DescriptorSize to make things work.
1331 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1333 if (DescriptorSize
!= NULL
) {
1334 *DescriptorSize
= Size
;
1337 if (DescriptorVersion
!= NULL
) {
1338 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1341 CoreAcquireMemoryLock ();
1344 // Compute the buffer size needed to fit the entire map
1346 BufferSize
= Size
* NumberOfRuntimeEntries
;
1347 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1351 if (*MemoryMapSize
< BufferSize
) {
1352 Status
= EFI_BUFFER_TOO_SMALL
;
1356 if (MemoryMap
== NULL
) {
1357 Status
= EFI_INVALID_PARAMETER
;
1364 ZeroMem (MemoryMap
, Size
);
1365 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1366 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1367 ASSERT (Entry
->VirtualStart
== 0);
1369 MemoryMap
->Type
= Entry
->Type
;
1370 MemoryMap
->PhysicalStart
= Entry
->Start
;
1371 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1372 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1374 switch (Entry
->Type
) {
1375 case EfiRuntimeServicesCode
:
1376 case EfiRuntimeServicesData
:
1378 MemoryMap
->Attribute
= Entry
->Attribute
| EFI_MEMORY_RUNTIME
;
1382 MemoryMap
->Attribute
= Entry
->Attribute
;
1386 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1389 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1390 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1391 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1392 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1393 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1395 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1396 MemoryMap
->VirtualStart
= 0;
1397 MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1398 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
& ~EFI_MEMORY_PORT_IO
;
1400 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1401 MemoryMap
->Type
= EfiReservedMemoryType
;
1402 } else if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1403 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1404 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1406 MemoryMap
->Type
= EfiMemoryMappedIO
;
1410 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1415 Status
= EFI_SUCCESS
;
1419 CoreReleaseMemoryLock ();
1421 CoreReleaseGcdMemoryLock ();
1424 // Update the map key finally
1426 if (MapKey
!= NULL
) {
1427 *MapKey
= mMemoryMapKey
;
1430 *MemoryMapSize
= BufferSize
;
1436 CoreAllocatePoolPages (
1437 IN EFI_MEMORY_TYPE PoolType
,
1438 IN UINTN NumberOfPages
,
1443 Routine Description:
1445 Internal function. Used by the pool functions to allocate pages
1446 to back pool allocation requests.
1450 PoolType - The type of memory for the new pool pages
1452 NumberOfPages - No of pages to allocate
1454 Alignment - Bits to align.
1458 The allocated memory, or NULL
1465 // Find the pages to convert
1467 Start
= FindFreePages (EFI_MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
);
1470 // Convert it to boot services data
1473 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages
));
1475 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1478 return (VOID
*)(UINTN
)Start
;
1483 IN EFI_PHYSICAL_ADDRESS Memory
,
1484 IN UINTN NumberOfPages
1488 Routine Description:
1490 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1494 Memory - The base address to free
1496 NumberOfPages - The number of pages to free
1504 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1509 CoreTerminateMemoryMap (
1514 Routine Description:
1516 Make sure the memory map is following all the construction rules,
1517 it is the last time to check memory map error before exit boot services.
1521 MapKey - Memory map key
1525 EFI_INVALID_PARAMETER - Memory map not consistent with construction rules.
1527 EFI_SUCCESS - Valid memory map.
1535 Status
= EFI_SUCCESS
;
1537 CoreAcquireMemoryLock ();
1539 if (MapKey
== mMemoryMapKey
) {
1542 // Make sure the memory map is following all the construction rules
1543 // This is the last chance we will be able to display any messages on
1544 // the console devices.
1547 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1548 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1549 if (Entry
->Attribute
& EFI_MEMORY_RUNTIME
) {
1550 if (Entry
->Type
== EfiACPIReclaimMemory
|| Entry
->Type
== EfiACPIMemoryNVS
) {
1551 DEBUG((EFI_D_ERROR
, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1552 CoreReleaseMemoryLock ();
1553 return EFI_INVALID_PARAMETER
;
1555 if (Entry
->Start
& (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1556 DEBUG((EFI_D_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1557 CoreReleaseMemoryLock ();
1558 return EFI_INVALID_PARAMETER
;
1560 if ((Entry
->End
+ 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1561 DEBUG((EFI_D_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1562 CoreReleaseMemoryLock ();
1563 return EFI_INVALID_PARAMETER
;
1569 // The map key they gave us matches what we expect. Fall through and
1570 // return success. In an ideal world we would clear out all of
1571 // EfiBootServicesCode and EfiBootServicesData. However this function
1572 // is not the last one called by ExitBootServices(), so we have to
1573 // preserve the memory contents.
1576 Status
= EFI_INVALID_PARAMETER
;
1579 CoreReleaseMemoryLock ();