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
98 PromoteMemoryResource (
105 IN EFI_MEMORY_TYPE Type
,
106 IN EFI_PHYSICAL_ADDRESS Start
,
107 IN EFI_PHYSICAL_ADDRESS End
,
113 CoreFreeMemoryMapStack (
121 IN UINT64 NumberOfPages
,
122 IN EFI_MEMORY_TYPE NewType
127 RemoveMemoryMapEntry (
132 CoreAcquireMemoryLock (
139 Enter critical section by gaining lock on gMemoryLock
151 CoreAcquireLock (&gMemoryLock
);
156 CoreReleaseMemoryLock (
163 Exit critical section by releasing lock on gMemoryLock
175 CoreReleaseLock (&gMemoryLock
);
179 PromoteMemoryResource (
186 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
199 EFI_GCD_MAP_ENTRY
*Entry
;
201 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "Promote the memory resource\n"));
203 CoreAcquireGcdMemoryLock ();
205 Link
= mGcdMemorySpaceMap
.ForwardLink
;
206 while (Link
!= &mGcdMemorySpaceMap
) {
208 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
210 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
211 Entry
->EndAddress
< EFI_MAX_ADDRESS
&&
212 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
213 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
215 // Update the GCD map
217 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
218 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
219 Entry
->ImageHandle
= gDxeCoreImageHandle
;
220 Entry
->DeviceHandle
= NULL
;
223 // Add to allocable system memory resource
227 EfiConventionalMemory
,
230 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
232 CoreFreeMemoryMapStack ();
236 Link
= Link
->ForwardLink
;
239 CoreReleaseGcdMemoryLock ();
245 CoreAddMemoryDescriptor (
246 IN EFI_MEMORY_TYPE Type
,
247 IN EFI_PHYSICAL_ADDRESS Start
,
248 IN UINT64 NumberOfPages
,
255 Called to initialize the memory map and add descriptors to
256 the current descriptor list.
258 The first descriptor that is added must be general usable
259 memory as the addition allocates heap.
263 Type - The type of memory to add
265 Start - The starting address in the memory range
268 NumberOfPages - The number of pages in the range
270 Attribute - Attributes of the memory to add
274 None. The range is added to the memory map
278 EFI_PHYSICAL_ADDRESS End
;
283 if ((Start
& EFI_PAGE_MASK
) != 0) {
287 if (Type
>= EfiMaxMemoryType
&& Type
<= 0x7fffffff) {
291 CoreAcquireMemoryLock ();
292 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
293 CoreAddRange (Type
, Start
, End
, Attribute
);
294 CoreFreeMemoryMapStack ();
295 CoreReleaseMemoryLock ();
298 // Check to see if the statistics for the different memory types have already been established
300 if (mMemoryTypeInformationInitialized
) {
305 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
307 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
309 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
311 Type
= gMemoryTypeInformation
[Index
].Type
;
312 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
316 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
318 // Allocate pages for the current memory type from the top of available memory
320 Status
= CoreAllocatePages (
323 gMemoryTypeInformation
[Index
].NumberOfPages
,
324 &mMemoryTypeStatistics
[Type
].BaseAddress
326 if (EFI_ERROR (Status
)) {
328 // If an error occurs allocating the pages for the current memory type, then
329 // free all the pages allocates for the previous memory types and return. This
330 // operation with be retied when/if more memory is added to the system
332 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
334 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
336 Type
= gMemoryTypeInformation
[FreeIndex
].Type
;
337 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
341 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
343 mMemoryTypeStatistics
[Type
].BaseAddress
,
344 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
346 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
347 mMemoryTypeStatistics
[Type
].MaximumAddress
= EFI_MAX_ADDRESS
;
354 // Compute the address at the top of the current statistics
356 mMemoryTypeStatistics
[Type
].MaximumAddress
=
357 mMemoryTypeStatistics
[Type
].BaseAddress
+
358 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
361 // If the current base address is the lowest address so far, then update the default
364 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
365 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
371 // There was enough system memory for all the the memory types were allocated. So,
372 // those memory areas can be freed for future allocations, and all future memory
373 // allocations can occur within their respective bins
375 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
377 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
379 Type
= gMemoryTypeInformation
[Index
].Type
;
380 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
384 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
386 mMemoryTypeStatistics
[Type
].BaseAddress
,
387 gMemoryTypeInformation
[Index
].NumberOfPages
389 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
394 // If the number of pages reserved for a memory type is 0, then all allocations for that type
395 // should be in the default range.
397 for (Type
= 0; Type
< EfiMaxMemoryType
; Type
++) {
398 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
399 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
400 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
403 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
404 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== EFI_MAX_ADDRESS
) {
405 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
409 mMemoryTypeInformationInitialized
= TRUE
;
416 IN EFI_MEMORY_TYPE Type
,
417 IN EFI_PHYSICAL_ADDRESS Start
,
418 IN EFI_PHYSICAL_ADDRESS End
,
425 Internal function. Adds a ranges to the memory map.
426 The range must not already exist in the map.
430 Type - The type of memory range to add
432 Start - The starting address in the memory range
433 Must be paged aligned
435 End - The last address in the range
436 Must be the last byte of a page
438 Attribute - The attributes of the memory range to add
442 None. The range is added to the memory map
449 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
450 ASSERT (End
> Start
) ;
452 ASSERT_LOCKED (&gMemoryLock
);
454 DEBUG ((EFI_D_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
457 // Memory map being altered so updated key
462 // UEFI 2.0 added an event group for notificaiton on memory map changes.
463 // So we need to signal this Event Group every time the memory map changes.
464 // If we are in EFI 1.10 compatability mode no event groups will be
465 // found and nothing will happen we we call this function. These events
466 // will get signaled but since a lock is held around the call to this
467 // function the notificaiton events will only be called after this funciton
468 // returns and the lock is released.
470 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
473 // Look for adjoining memory descriptor
476 // Two memory descriptors can only be merged if they have the same Type
477 // and the same Attribute
480 Link
= gMemoryMap
.ForwardLink
;
481 while (Link
!= &gMemoryMap
) {
482 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
483 Link
= Link
->ForwardLink
;
485 if (Entry
->Type
!= Type
) {
489 if (Entry
->Attribute
!= Attribute
) {
493 if (Entry
->End
+ 1 == Start
) {
495 Start
= Entry
->Start
;
496 RemoveMemoryMapEntry (Entry
);
498 } else if (Entry
->Start
== End
+ 1) {
501 RemoveMemoryMapEntry (Entry
);
509 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
510 mMapStack
[mMapDepth
].FromPool
= FALSE
;
511 mMapStack
[mMapDepth
].Type
= Type
;
512 mMapStack
[mMapDepth
].Start
= Start
;
513 mMapStack
[mMapDepth
].End
= End
;
514 mMapStack
[mMapDepth
].VirtualStart
= 0;
515 mMapStack
[mMapDepth
].Attribute
= Attribute
;
516 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
519 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
526 CoreFreeMemoryMapStack (
533 Internal function. Moves any memory descriptors that are on the
534 temporary descriptor stack to heap.
550 ASSERT_LOCKED (&gMemoryLock
);
553 // If already freeing the map stack, then return
560 // Move the temporary memory descriptor stack into pool
567 // Allocate memory for a entry
569 Entry
= CoreAllocatePoolI (EfiRuntimeServicesData
, sizeof(MEMORY_MAP
));
574 // Update to proper entry
578 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
581 // Move this entry to general pool
583 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
584 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
586 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
587 Entry
->FromPool
= TRUE
;
590 // Find insertion location
592 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
593 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
594 if (Entry2
->FromPool
&& Entry2
->Start
> Entry
->Start
) {
599 InsertTailList (Link2
, &Entry
->Link
);
604 // It was removed, don't move it
606 CoreFreePoolI (Entry
);
616 RemoveMemoryMapEntry (
623 Internal function. Removes a descriptor entry.
627 Entry - The entry to remove
635 RemoveEntryList (&Entry
->Link
);
636 Entry
->Link
.ForwardLink
= NULL
;
638 if (Entry
->FromPool
) {
639 CoreFreePoolI (Entry
);
648 IN UINT64 NumberOfPages
,
649 IN EFI_MEMORY_TYPE NewType
655 Internal function. Converts a memory range to the specified type.
656 The range must exist in the memory map.
660 Start - The first address of the range
663 NumberOfPages - The number of pages to convert
665 NewType - The new type for the memory range
669 EFI_INVALID_PARAMETER - Invalid parameter
671 EFI_NOT_FOUND - Could not find a descriptor cover the specified range
672 or convertion not allowed.
674 EFI_SUCCESS - Successfully converts the memory range to the specified type.
679 UINT64 NumberOfBytes
;
687 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
688 End
= Start
+ NumberOfBytes
- 1;
690 ASSERT (NumberOfPages
);
691 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
692 ASSERT (End
> Start
) ;
693 ASSERT_LOCKED (&gMemoryLock
);
695 if (NumberOfPages
== 0 || (Start
& EFI_PAGE_MASK
) || (Start
> (Start
+ NumberOfBytes
))) {
696 return EFI_INVALID_PARAMETER
;
700 // Convert the entire range
703 while (Start
< End
) {
706 // Find the entry that the covers the range
708 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
709 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
711 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
716 if (Link
== &gMemoryMap
) {
717 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
718 return EFI_NOT_FOUND
;
722 // Convert range to the end, or to the end of the descriptor
723 // if that's all we've got
726 if (Entry
->End
< End
) {
727 RangeEnd
= Entry
->End
;
730 DEBUG ((EFI_D_PAGE
, "ConvertRange: %lx-%lx to %d\n", Start
, RangeEnd
, NewType
));
733 // Debug code - verify conversion is allowed
735 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
736 DEBUG ((EFI_D_ERROR
, "ConvertPages: Incompatible memory types\n"));
737 return EFI_NOT_FOUND
;
741 // Update counters for the number of pages allocated to each memory type
743 if (Entry
->Type
>= 0 && Entry
->Type
< EfiMaxMemoryType
) {
744 if (Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&&
745 Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) {
746 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
747 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
749 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
754 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
) {
755 if (Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
756 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
757 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
>
758 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
759 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
765 // Pull range out of descriptor
767 if (Entry
->Start
== Start
) {
772 Entry
->Start
= RangeEnd
+ 1;
774 } else if (Entry
->End
== RangeEnd
) {
779 Entry
->End
= Start
- 1;
784 // Pull it out of the center, clip current
790 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
791 mMapStack
[mMapDepth
].FromPool
= FALSE
;
792 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
793 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
794 mMapStack
[mMapDepth
].End
= Entry
->End
;
797 // Inherit Attribute from the Memory Descriptor that is being clipped
799 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
801 Entry
->End
= Start
- 1;
802 ASSERT (Entry
->Start
< Entry
->End
);
804 Entry
= &mMapStack
[mMapDepth
];
805 InsertTailList (&gMemoryMap
, &Entry
->Link
);
808 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
812 // The new range inherits the same Attribute as the Entry
813 //it is being cut out of
815 Attribute
= Entry
->Attribute
;
818 // If the descriptor is empty, then remove it from the map
820 if (Entry
->Start
== Entry
->End
+ 1) {
821 RemoveMemoryMapEntry (Entry
);
826 // Add our new range in
828 CoreAddRange (NewType
, Start
, RangeEnd
, Attribute
);
831 // Move any map descriptor stack to general pool
833 CoreFreeMemoryMapStack ();
836 // Bump the starting address, and convert the next range
838 Start
= RangeEnd
+ 1;
842 // Converted the whole range, done
852 IN UINT64 MaxAddress
,
853 IN UINT64 NumberOfPages
,
854 IN EFI_MEMORY_TYPE NewType
,
861 Internal function. Finds a consecutive free page range below
862 the requested address.
866 MaxAddress - The address that the range must be below
868 NumberOfPages - Number of pages needed
870 NewType - The type of memory the range is going to be turned into
872 Alignment - Bits to align with
876 The base address of the range, or 0 if the range was not found
880 UINT64 NumberOfBytes
;
884 UINT64 DescNumberOfBytes
;
888 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
892 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
895 // If MaxAddress is not aligned to the end of a page
899 // Change MaxAddress to be 1 page lower
901 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
904 // Set MaxAddress to a page boundary
906 MaxAddress
&= ~EFI_PAGE_MASK
;
909 // Set MaxAddress to end of the page
911 MaxAddress
|= EFI_PAGE_MASK
;
914 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
917 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
918 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
921 // If it's not a free entry, don't bother with it
923 if (Entry
->Type
!= EfiConventionalMemory
) {
927 DescStart
= Entry
->Start
;
928 DescEnd
= Entry
->End
;
931 // If desc is past max allowed address, skip it
933 if (DescStart
>= MaxAddress
) {
938 // If desc ends past max allowed address, clip the end
940 if (DescEnd
>= MaxAddress
) {
941 DescEnd
= MaxAddress
;
944 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
947 // Compute the number of bytes we can used from this
948 // descriptor, and see it's enough to satisfy the request
950 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
952 if (DescNumberOfBytes
>= NumberOfBytes
) {
955 // If this is the best match so far remember it
957 if (DescEnd
> Target
) {
964 // If this is a grow down, adjust target to be the allocation base
966 Target
-= NumberOfBytes
- 1;
969 // If we didn't find a match, return 0
971 if ((Target
& EFI_PAGE_MASK
) != 0) {
981 IN UINT64 MaxAddress
,
983 IN EFI_MEMORY_TYPE NewType
,
990 Internal function. Finds a consecutive free page range below
991 the requested address
995 MaxAddress - The address that the range must be below
997 NoPages - Number of pages needed
999 NewType - The type of memory the range is going to be turned into
1001 Alignment - Bits to align with
1005 The base address of the range, or 0 if the range was not found.
1009 UINT64 NewMaxAddress
;
1012 NewMaxAddress
= MaxAddress
;
1014 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
&& NewMaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
1015 NewMaxAddress
= mMemoryTypeStatistics
[NewType
].MaximumAddress
;
1017 if (NewMaxAddress
> mDefaultMaximumAddress
) {
1018 NewMaxAddress
= mDefaultMaximumAddress
;
1022 Start
= CoreFindFreePagesI (NewMaxAddress
, NoPages
, NewType
, Alignment
);
1024 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1027 // Here means there may be no enough memory to use, so try to go through
1028 // all the memory descript to promote the untested memory directly
1030 PromoteMemoryResource ();
1033 // Allocate memory again after the memory resource re-arranged
1035 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
1046 IN EFI_ALLOCATE_TYPE Type
,
1047 IN EFI_MEMORY_TYPE MemoryType
,
1048 IN UINTN NumberOfPages
,
1049 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
1053 Routine Description:
1055 Allocates pages from the memory map.
1059 Type - The type of allocation to perform
1061 MemoryType - The type of memory to turn the allocated pages into
1063 NumberOfPages - The number of pages to allocate
1065 Memory - A pointer to receive the base allocated memory address
1069 Status. On success, Memory is filled in with the base address allocated
1071 EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec.
1073 EFI_NOT_FOUND - Could not allocate pages match the requirement.
1075 EFI_OUT_OF_RESOURCES - No enough pages to allocate.
1077 EFI_SUCCESS - Pages successfully allocated.
1086 if (Type
< AllocateAnyPages
|| Type
>= (UINTN
) MaxAllocateType
) {
1087 return EFI_INVALID_PARAMETER
;
1090 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
<= 0x7fffffff) ||
1091 MemoryType
== EfiConventionalMemory
) {
1092 return EFI_INVALID_PARAMETER
;
1095 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1097 if (MemoryType
== EfiACPIReclaimMemory
||
1098 MemoryType
== EfiACPIMemoryNVS
||
1099 MemoryType
== EfiRuntimeServicesCode
||
1100 MemoryType
== EfiRuntimeServicesData
) {
1102 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1105 if (Type
== AllocateAddress
) {
1106 if ((*Memory
& (Alignment
- 1)) != 0) {
1107 return EFI_NOT_FOUND
;
1111 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1112 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1115 // If this is for below a particular address, then
1120 // The max address is the max natively addressable address for the processor
1122 MaxAddress
= EFI_MAX_ADDRESS
;
1124 if (Type
== AllocateMaxAddress
) {
1128 CoreAcquireMemoryLock ();
1131 // If not a specific address, then find an address to allocate
1133 if (Type
!= AllocateAddress
) {
1134 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
);
1136 Status
= EFI_OUT_OF_RESOURCES
;
1142 // Convert pages from FreeMemory to the requested type
1144 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1147 CoreReleaseMemoryLock ();
1149 if (!EFI_ERROR (Status
)) {
1162 IN EFI_PHYSICAL_ADDRESS Memory
,
1163 IN UINTN NumberOfPages
1167 Routine Description:
1169 Frees previous allocated pages.
1173 Memory - Base address of memory being freed
1175 NumberOfPages - The number of pages to free
1179 EFI_NOT_FOUND - Could not find the entry that covers the range
1181 EFI_INVALID_PARAMETER - Address not aligned
1183 EFI_SUCCESS -Pages successfully freed.
1195 CoreAcquireMemoryLock ();
1198 // Find the entry that the covers the range
1201 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1202 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1203 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1207 if (Link
== &gMemoryMap
) {
1208 CoreReleaseMemoryLock ();
1209 return EFI_NOT_FOUND
;
1212 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1214 if (Entry
->Type
== EfiACPIReclaimMemory
||
1215 Entry
->Type
== EfiACPIMemoryNVS
||
1216 Entry
->Type
== EfiRuntimeServicesCode
||
1217 Entry
->Type
== EfiRuntimeServicesData
) {
1219 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1223 if ((Memory
& (Alignment
- 1)) != 0) {
1224 CoreReleaseMemoryLock ();
1225 return EFI_INVALID_PARAMETER
;
1228 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1229 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1231 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1233 CoreReleaseMemoryLock ();
1235 if (EFI_ERROR (Status
)) {
1240 // Destroy the contents
1242 if (Memory
< EFI_MAX_ADDRESS
) {
1243 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Memory
, NumberOfPages
<< EFI_PAGE_SHIFT
);
1254 IN OUT UINTN
*MemoryMapSize
,
1255 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1257 OUT UINTN
*DescriptorSize
,
1258 OUT UINT32
*DescriptorVersion
1262 Routine Description:
1264 This function returns a copy of the current memory map. The map is an array of
1265 memory descriptors, each of which describes a contiguous block of memory.
1269 MemoryMapSize - A pointer to the size, in bytes, of the MemoryMap buffer. On
1270 input, this is the size of the buffer allocated by the caller.
1271 On output, it is the size of the buffer returned by the firmware
1272 if the buffer was large enough, or the size of the buffer needed
1273 to contain the map if the buffer was too small.
1274 MemoryMap - A pointer to the buffer in which firmware places the current memory map.
1275 MapKey - A pointer to the location in which firmware returns the key for the
1277 DescriptorSize - A pointer to the location in which firmware returns the size, in
1278 bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1279 DescriptorVersion - A pointer to the location in which firmware returns the version
1280 number associated with the EFI_MEMORY_DESCRIPTOR.
1284 EFI_SUCCESS - The memory map was returned in the MemoryMap buffer.
1285 EFI_BUFFER_TOO_SMALL - The MemoryMap buffer was too small. The current buffer size
1286 needed to hold the memory map is returned in MemoryMapSize.
1287 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
1294 UINTN NumberOfRuntimeEntries
;
1297 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1300 // Make sure the parameters are valid
1302 if (MemoryMapSize
== NULL
) {
1303 return EFI_INVALID_PARAMETER
;
1306 CoreAcquireGcdMemoryLock ();
1309 // Count the number of Reserved and MMIO entries that are marked for runtime use
1311 NumberOfRuntimeEntries
= 0;
1312 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1313 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1314 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1315 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1316 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1317 NumberOfRuntimeEntries
++;
1322 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1325 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1326 // prevent people from having pointer math bugs in their code.
1327 // now you have to use *DescriptorSize to make things work.
1329 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1331 if (DescriptorSize
!= NULL
) {
1332 *DescriptorSize
= Size
;
1335 if (DescriptorVersion
!= NULL
) {
1336 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1339 CoreAcquireMemoryLock ();
1342 // Compute the buffer size needed to fit the entire map
1344 BufferSize
= Size
* NumberOfRuntimeEntries
;
1345 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1349 if (*MemoryMapSize
< BufferSize
) {
1350 Status
= EFI_BUFFER_TOO_SMALL
;
1354 if (MemoryMap
== NULL
) {
1355 Status
= EFI_INVALID_PARAMETER
;
1362 ZeroMem (MemoryMap
, Size
);
1363 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1364 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1365 ASSERT (Entry
->VirtualStart
== 0);
1367 MemoryMap
->Type
= Entry
->Type
;
1368 MemoryMap
->PhysicalStart
= Entry
->Start
;
1369 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1370 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1372 switch (Entry
->Type
) {
1373 case EfiRuntimeServicesCode
:
1374 case EfiRuntimeServicesData
:
1376 MemoryMap
->Attribute
= Entry
->Attribute
| EFI_MEMORY_RUNTIME
;
1380 MemoryMap
->Attribute
= Entry
->Attribute
;
1384 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1387 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1388 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1389 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1390 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1391 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1393 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1394 MemoryMap
->VirtualStart
= 0;
1395 MemoryMap
->NumberOfPages
= MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1396 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
& ~EFI_MEMORY_PORT_IO
;
1398 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1399 MemoryMap
->Type
= EfiReservedMemoryType
;
1400 } else if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1401 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1402 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1404 MemoryMap
->Type
= EfiMemoryMappedIO
;
1408 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1413 Status
= EFI_SUCCESS
;
1417 CoreReleaseMemoryLock ();
1419 CoreReleaseGcdMemoryLock ();
1422 // Update the map key finally
1424 if (MapKey
!= NULL
) {
1425 *MapKey
= mMemoryMapKey
;
1428 *MemoryMapSize
= BufferSize
;
1434 CoreAllocatePoolPages (
1435 IN EFI_MEMORY_TYPE PoolType
,
1436 IN UINTN NumberOfPages
,
1441 Routine Description:
1443 Internal function. Used by the pool functions to allocate pages
1444 to back pool allocation requests.
1448 PoolType - The type of memory for the new pool pages
1450 NumberOfPages - No of pages to allocate
1452 Alignment - Bits to align.
1456 The allocated memory, or NULL
1464 // Find the pages to convert
1466 Start
= FindFreePages (EFI_MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
);
1469 // Convert it to boot services data
1472 DEBUG ((EFI_D_ERROR
| EFI_D_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages
));
1474 Status
= CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1477 return (VOID
*)(UINTN
)Start
;
1482 IN EFI_PHYSICAL_ADDRESS Memory
,
1483 IN UINTN NumberOfPages
1487 Routine Description:
1489 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1493 Memory - The base address to free
1495 NumberOfPages - The number of pages to free
1503 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1508 CoreTerminateMemoryMap (
1513 Routine Description:
1515 Make sure the memory map is following all the construction rules,
1516 it is the last time to check memory map error before exit boot services.
1520 MapKey - Memory map key
1524 EFI_INVALID_PARAMETER - Memory map not consistent with construction rules.
1526 EFI_SUCCESS - Valid memory map.
1534 Status
= EFI_SUCCESS
;
1536 CoreAcquireMemoryLock ();
1538 if (MapKey
== mMemoryMapKey
) {
1541 // Make sure the memory map is following all the construction rules
1542 // This is the last chance we will be able to display any messages on
1543 // the console devices.
1546 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1547 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1548 if (Entry
->Attribute
& EFI_MEMORY_RUNTIME
) {
1549 if (Entry
->Type
== EfiACPIReclaimMemory
|| Entry
->Type
== EfiACPIMemoryNVS
) {
1550 DEBUG((EFI_D_ERROR
, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1551 CoreReleaseMemoryLock ();
1552 return EFI_INVALID_PARAMETER
;
1554 if (Entry
->Start
& (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1555 DEBUG((EFI_D_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1556 CoreReleaseMemoryLock ();
1557 return EFI_INVALID_PARAMETER
;
1559 if ((Entry
->End
+ 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1560 DEBUG((EFI_D_ERROR
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1561 CoreReleaseMemoryLock ();
1562 return EFI_INVALID_PARAMETER
;
1568 // The map key they gave us matches what we expect. Fall through and
1569 // return success. In an ideal world we would clear out all of
1570 // EfiBootServicesCode and EfiBootServicesData. However this function
1571 // is not the last one called by ExitBootServices(), so we have to
1572 // preserve the memory contents.
1575 Status
= EFI_INVALID_PARAMETER
;
1578 CoreReleaseMemoryLock ();