2 UEFI Memory page management functions.
4 Copyright (c) 2007 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
20 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
23 EFI_PHYSICAL_ADDRESS BaseAddress
;
24 EFI_PHYSICAL_ADDRESS MaximumAddress
;
25 UINT64 CurrentNumberOfPages
;
27 UINTN InformationIndex
;
30 } EFI_MEMORY_TYPE_STAISTICS
;
33 // MemoryMap - The current memory map
35 UINTN mMemoryMapKey
= 0;
38 // mMapStack - space to use as temp storage to build new map descriptors
39 // mMapDepth - depth of new descriptor stack
42 #define MAX_MAP_DEPTH 6
44 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
45 UINTN mFreeMapStack
= 0;
47 // This list maintain the free memory map list
49 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
50 BOOLEAN mMemoryTypeInformationInitialized
= FALSE
;
52 EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics
[EfiMaxMemoryType
+ 1] = {
53 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiReservedMemoryType
54 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderCode
55 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiLoaderData
56 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesCode
57 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiBootServicesData
58 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesCode
59 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiRuntimeServicesData
60 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiConventionalMemory
61 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiUnusableMemory
62 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIReclaimMemory
63 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, FALSE
}, // EfiACPIMemoryNVS
64 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIO
65 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
}, // EfiMemoryMappedIOPortSpace
66 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, TRUE
, TRUE
}, // EfiPalCode
67 { 0, EFI_MAX_ADDRESS
, 0, 0, EfiMaxMemoryType
, FALSE
, FALSE
} // EfiMaxMemoryType
70 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress
= EFI_MAX_ADDRESS
;
72 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation
[EfiMaxMemoryType
+ 1] = {
73 { EfiReservedMemoryType
, 0 },
76 { EfiBootServicesCode
, 0 },
77 { EfiBootServicesData
, 0 },
78 { EfiRuntimeServicesCode
, 0 },
79 { EfiRuntimeServicesData
, 0 },
80 { EfiConventionalMemory
, 0 },
81 { EfiUnusableMemory
, 0 },
82 { EfiACPIReclaimMemory
, 0 },
83 { EfiACPIMemoryNVS
, 0 },
84 { EfiMemoryMappedIO
, 0 },
85 { EfiMemoryMappedIOPortSpace
, 0 },
87 { EfiMaxMemoryType
, 0 }
92 Enter critical section by gaining lock on gMemoryLock.
96 CoreAcquireMemoryLock (
100 CoreAcquireLock (&gMemoryLock
);
106 Exit critical section by releasing lock on gMemoryLock.
110 CoreReleaseMemoryLock (
114 CoreReleaseLock (&gMemoryLock
);
121 Internal function. Removes a descriptor entry.
123 @param Entry The entry to remove
127 RemoveMemoryMapEntry (
128 IN OUT MEMORY_MAP
*Entry
131 RemoveEntryList (&Entry
->Link
);
132 Entry
->Link
.ForwardLink
= NULL
;
134 if (Entry
->FromPages
) {
136 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
138 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
143 Internal function. Adds a ranges to the memory map.
144 The range must not already exist in the map.
146 @param Type The type of memory range to add
147 @param Start The starting address in the memory range Must be
149 @param End The last address in the range Must be the last
151 @param Attribute The attributes of the memory range to add
156 IN EFI_MEMORY_TYPE Type
,
157 IN EFI_PHYSICAL_ADDRESS Start
,
158 IN EFI_PHYSICAL_ADDRESS End
,
165 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
166 ASSERT (End
> Start
) ;
168 ASSERT_LOCKED (&gMemoryLock
);
170 DEBUG ((DEBUG_PAGE
, "AddRange: %lx-%lx to %d\n", Start
, End
, Type
));
173 // Memory map being altered so updated key
178 // UEFI 2.0 added an event group for notificaiton on memory map changes.
179 // So we need to signal this Event Group every time the memory map changes.
180 // If we are in EFI 1.10 compatability mode no event groups will be
181 // found and nothing will happen we we call this function. These events
182 // will get signaled but since a lock is held around the call to this
183 // function the notificaiton events will only be called after this funciton
184 // returns and the lock is released.
186 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid
);
189 // Look for adjoining memory descriptor
192 // Two memory descriptors can only be merged if they have the same Type
193 // and the same Attribute
196 Link
= gMemoryMap
.ForwardLink
;
197 while (Link
!= &gMemoryMap
) {
198 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
199 Link
= Link
->ForwardLink
;
201 if (Entry
->Type
!= Type
) {
205 if (Entry
->Attribute
!= Attribute
) {
209 if (Entry
->End
+ 1 == Start
) {
211 Start
= Entry
->Start
;
212 RemoveMemoryMapEntry (Entry
);
214 } else if (Entry
->Start
== End
+ 1) {
217 RemoveMemoryMapEntry (Entry
);
225 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
226 mMapStack
[mMapDepth
].FromPages
= FALSE
;
227 mMapStack
[mMapDepth
].Type
= Type
;
228 mMapStack
[mMapDepth
].Start
= Start
;
229 mMapStack
[mMapDepth
].End
= End
;
230 mMapStack
[mMapDepth
].VirtualStart
= 0;
231 mMapStack
[mMapDepth
].Attribute
= Attribute
;
232 InsertTailList (&gMemoryMap
, &mMapStack
[mMapDepth
].Link
);
235 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
241 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
242 If the list is emtry, then allocate a new page to refuel the list.
243 Please Note this algorithm to allocate the memory map descriptor has a property
244 that the memory allocated for memory entries always grows, and will never really be freed
245 For example, if the current boot uses 2000 memory map entries at the maximum point, but
246 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
247 memory map entries is still allocated from EfiBootServicesMemory.
250 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
254 AllocateMemoryMapEntry (
258 MEMORY_MAP
* FreeDescriptorEntries
;
262 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
264 // The list is empty, to allocate one page to refuel the list
266 FreeDescriptorEntries
= CoreAllocatePoolPages (EfiBootServicesData
, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
267 if(FreeDescriptorEntries
!= NULL
) {
269 // Enque the free memmory map entries into the list
271 for (Index
= 0; Index
< DEFAULT_PAGE_ALLOCATION
/ sizeof(MEMORY_MAP
); Index
++) {
272 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
273 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
280 // dequeue the first descriptor from the list
282 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
283 RemoveEntryList (&Entry
->Link
);
290 Internal function. Moves any memory descriptors that are on the
291 temporary descriptor stack to heap.
295 CoreFreeMemoryMapStack (
303 ASSERT_LOCKED (&gMemoryLock
);
306 // If already freeing the map stack, then return
308 if (mFreeMapStack
!= 0) {
313 // Move the temporary memory descriptor stack into pool
317 while (mMapDepth
!= 0) {
319 // Deque an memory map entry from mFreeMemoryMapEntryList
321 Entry
= AllocateMemoryMapEntry ();
326 // Update to proper entry
330 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
333 // Move this entry to general memory
335 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
336 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
338 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
339 Entry
->FromPages
= TRUE
;
342 // Find insertion location
344 for (Link2
= gMemoryMap
.ForwardLink
; Link2
!= &gMemoryMap
; Link2
= Link2
->ForwardLink
) {
345 Entry2
= CR (Link2
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
346 if (Entry2
->FromPages
&& Entry2
->Start
> Entry
->Start
) {
351 InsertTailList (Link2
, &Entry
->Link
);
355 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
356 // so here no need to move it to memory.
358 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
366 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
370 PromoteMemoryResource (
375 EFI_GCD_MAP_ENTRY
*Entry
;
377 DEBUG ((DEBUG_PAGE
, "Promote the memory resource\n"));
379 CoreAcquireGcdMemoryLock ();
381 Link
= mGcdMemorySpaceMap
.ForwardLink
;
382 while (Link
!= &mGcdMemorySpaceMap
) {
384 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
386 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
387 Entry
->EndAddress
< EFI_MAX_ADDRESS
&&
388 (Entry
->Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
389 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)) {
391 // Update the GCD map
393 Entry
->GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
394 Entry
->Capabilities
|= EFI_MEMORY_TESTED
;
395 Entry
->ImageHandle
= gDxeCoreImageHandle
;
396 Entry
->DeviceHandle
= NULL
;
399 // Add to allocable system memory resource
403 EfiConventionalMemory
,
406 Entry
->Capabilities
& ~(EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
| EFI_MEMORY_RUNTIME
)
408 CoreFreeMemoryMapStack ();
412 Link
= Link
->ForwardLink
;
415 CoreReleaseGcdMemoryLock ();
422 Called to initialize the memory map and add descriptors to
423 the current descriptor list.
424 The first descriptor that is added must be general usable
425 memory as the addition allocates heap.
427 @param Type The type of memory to add
428 @param Start The starting address in the memory range Must be
430 @param NumberOfPages The number of pages in the range
431 @param Attribute Attributes of the memory to add
433 @return None. The range is added to the memory map
437 CoreAddMemoryDescriptor (
438 IN EFI_MEMORY_TYPE Type
,
439 IN EFI_PHYSICAL_ADDRESS Start
,
440 IN UINT64 NumberOfPages
,
444 EFI_PHYSICAL_ADDRESS End
;
449 if ((Start
& EFI_PAGE_MASK
) != 0) {
453 if (Type
>= EfiMaxMemoryType
&& Type
<= 0x7fffffff) {
457 CoreAcquireMemoryLock ();
458 End
= Start
+ LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
459 CoreAddRange (Type
, Start
, End
, Attribute
);
460 CoreFreeMemoryMapStack ();
461 CoreReleaseMemoryLock ();
464 // Check to see if the statistics for the different memory types have already been established
466 if (mMemoryTypeInformationInitialized
) {
471 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
473 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
475 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
477 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
478 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
482 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
484 // Allocate pages for the current memory type from the top of available memory
486 Status
= CoreAllocatePages (
489 gMemoryTypeInformation
[Index
].NumberOfPages
,
490 &mMemoryTypeStatistics
[Type
].BaseAddress
492 if (EFI_ERROR (Status
)) {
494 // If an error occurs allocating the pages for the current memory type, then
495 // free all the pages allocates for the previous memory types and return. This
496 // operation with be retied when/if more memory is added to the system
498 for (FreeIndex
= 0; FreeIndex
< Index
; FreeIndex
++) {
500 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
502 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[FreeIndex
].Type
);
503 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
507 if (gMemoryTypeInformation
[FreeIndex
].NumberOfPages
!= 0) {
509 mMemoryTypeStatistics
[Type
].BaseAddress
,
510 gMemoryTypeInformation
[FreeIndex
].NumberOfPages
512 mMemoryTypeStatistics
[Type
].BaseAddress
= 0;
513 mMemoryTypeStatistics
[Type
].MaximumAddress
= EFI_MAX_ADDRESS
;
520 // Compute the address at the top of the current statistics
522 mMemoryTypeStatistics
[Type
].MaximumAddress
=
523 mMemoryTypeStatistics
[Type
].BaseAddress
+
524 LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
) - 1;
527 // If the current base address is the lowest address so far, then update the default
530 if (mMemoryTypeStatistics
[Type
].BaseAddress
< mDefaultMaximumAddress
) {
531 mDefaultMaximumAddress
= mMemoryTypeStatistics
[Type
].BaseAddress
- 1;
537 // There was enough system memory for all the the memory types were allocated. So,
538 // those memory areas can be freed for future allocations, and all future memory
539 // allocations can occur within their respective bins
541 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
543 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
545 Type
= (EFI_MEMORY_TYPE
) (gMemoryTypeInformation
[Index
].Type
);
546 if (Type
< 0 || Type
> EfiMaxMemoryType
) {
550 if (gMemoryTypeInformation
[Index
].NumberOfPages
!= 0) {
552 mMemoryTypeStatistics
[Type
].BaseAddress
,
553 gMemoryTypeInformation
[Index
].NumberOfPages
555 mMemoryTypeStatistics
[Type
].NumberOfPages
= gMemoryTypeInformation
[Index
].NumberOfPages
;
556 gMemoryTypeInformation
[Index
].NumberOfPages
= 0;
561 // If the number of pages reserved for a memory type is 0, then all allocations for that type
562 // should be in the default range.
564 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
565 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
566 if (Type
== (EFI_MEMORY_TYPE
)gMemoryTypeInformation
[Index
].Type
) {
567 mMemoryTypeStatistics
[Type
].InformationIndex
= Index
;
570 mMemoryTypeStatistics
[Type
].CurrentNumberOfPages
= 0;
571 if (mMemoryTypeStatistics
[Type
].MaximumAddress
== EFI_MAX_ADDRESS
) {
572 mMemoryTypeStatistics
[Type
].MaximumAddress
= mDefaultMaximumAddress
;
576 mMemoryTypeInformationInitialized
= TRUE
;
581 Internal function. Converts a memory range to the specified type.
582 The range must exist in the memory map.
584 @param Start The first address of the range Must be page
586 @param NumberOfPages The number of pages to convert
587 @param NewType The new type for the memory range
589 @retval EFI_INVALID_PARAMETER Invalid parameter
590 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
591 range or convertion not allowed.
592 @retval EFI_SUCCESS Successfully converts the memory range to the
599 IN UINT64 NumberOfPages
,
600 IN EFI_MEMORY_TYPE NewType
604 UINT64 NumberOfBytes
;
612 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
613 End
= Start
+ NumberOfBytes
- 1;
615 ASSERT (NumberOfPages
);
616 ASSERT ((Start
& EFI_PAGE_MASK
) == 0);
617 ASSERT (End
> Start
) ;
618 ASSERT_LOCKED (&gMemoryLock
);
620 if (NumberOfPages
== 0 || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
> (Start
+ NumberOfBytes
))) {
621 return EFI_INVALID_PARAMETER
;
625 // Convert the entire range
628 while (Start
< End
) {
631 // Find the entry that the covers the range
633 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
634 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
636 if (Entry
->Start
<= Start
&& Entry
->End
> Start
) {
641 if (Link
== &gMemoryMap
) {
642 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: failed to find range %lx - %lx\n", Start
, End
));
643 return EFI_NOT_FOUND
;
647 // Convert range to the end, or to the end of the descriptor
648 // if that's all we've got
651 if (Entry
->End
< End
) {
652 RangeEnd
= Entry
->End
;
655 DEBUG ((DEBUG_PAGE
, "ConvertRange: %lx-%lx to %d\n", Start
, RangeEnd
, NewType
));
658 // Debug code - verify conversion is allowed
660 if (!(NewType
== EfiConventionalMemory
? 1 : 0) ^ (Entry
->Type
== EfiConventionalMemory
? 1 : 0)) {
661 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "ConvertPages: Incompatible memory types\n"));
662 return EFI_NOT_FOUND
;
666 // Update counters for the number of pages allocated to each memory type
668 if (Entry
->Type
>= 0 && Entry
->Type
< EfiMaxMemoryType
) {
669 if (Start
>= mMemoryTypeStatistics
[Entry
->Type
].BaseAddress
&&
670 Start
<= mMemoryTypeStatistics
[Entry
->Type
].MaximumAddress
) {
671 if (NumberOfPages
> mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
) {
672 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
= 0;
674 mMemoryTypeStatistics
[Entry
->Type
].CurrentNumberOfPages
-= NumberOfPages
;
679 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
) {
680 if (Start
>= mMemoryTypeStatistics
[NewType
].BaseAddress
&& Start
<= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
681 mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
+= NumberOfPages
;
682 if (mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
>
683 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
) {
684 gMemoryTypeInformation
[mMemoryTypeStatistics
[NewType
].InformationIndex
].NumberOfPages
= (UINT32
)mMemoryTypeStatistics
[NewType
].CurrentNumberOfPages
;
690 // Pull range out of descriptor
692 if (Entry
->Start
== Start
) {
697 Entry
->Start
= RangeEnd
+ 1;
699 } else if (Entry
->End
== RangeEnd
) {
704 Entry
->End
= Start
- 1;
709 // Pull it out of the center, clip current
715 mMapStack
[mMapDepth
].Signature
= MEMORY_MAP_SIGNATURE
;
716 mMapStack
[mMapDepth
].FromPages
= FALSE
;
717 mMapStack
[mMapDepth
].Type
= Entry
->Type
;
718 mMapStack
[mMapDepth
].Start
= RangeEnd
+1;
719 mMapStack
[mMapDepth
].End
= Entry
->End
;
722 // Inherit Attribute from the Memory Descriptor that is being clipped
724 mMapStack
[mMapDepth
].Attribute
= Entry
->Attribute
;
726 Entry
->End
= Start
- 1;
727 ASSERT (Entry
->Start
< Entry
->End
);
729 Entry
= &mMapStack
[mMapDepth
];
730 InsertTailList (&gMemoryMap
, &Entry
->Link
);
733 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
737 // The new range inherits the same Attribute as the Entry
738 //it is being cut out of
740 Attribute
= Entry
->Attribute
;
743 // If the descriptor is empty, then remove it from the map
745 if (Entry
->Start
== Entry
->End
+ 1) {
746 RemoveMemoryMapEntry (Entry
);
751 // Add our new range in
753 CoreAddRange (NewType
, Start
, RangeEnd
, Attribute
);
756 // Move any map descriptor stack to general pool
758 CoreFreeMemoryMapStack ();
761 // Bump the starting address, and convert the next range
763 Start
= RangeEnd
+ 1;
767 // Converted the whole range, done
776 Internal function. Finds a consecutive free page range below
777 the requested address.
779 @param MaxAddress The address that the range must be below
780 @param NumberOfPages Number of pages needed
781 @param NewType The type of memory the range is going to be
783 @param Alignment Bits to align with
785 @return The base address of the range, or 0 if the range was not found
790 IN UINT64 MaxAddress
,
791 IN UINT64 NumberOfPages
,
792 IN EFI_MEMORY_TYPE NewType
,
796 UINT64 NumberOfBytes
;
800 UINT64 DescNumberOfBytes
;
804 if ((MaxAddress
< EFI_PAGE_MASK
) ||(NumberOfPages
== 0)) {
808 if ((MaxAddress
& EFI_PAGE_MASK
) != EFI_PAGE_MASK
) {
811 // If MaxAddress is not aligned to the end of a page
815 // Change MaxAddress to be 1 page lower
817 MaxAddress
-= (EFI_PAGE_MASK
+ 1);
820 // Set MaxAddress to a page boundary
822 MaxAddress
&= ~EFI_PAGE_MASK
;
825 // Set MaxAddress to end of the page
827 MaxAddress
|= EFI_PAGE_MASK
;
830 NumberOfBytes
= LShiftU64 (NumberOfPages
, EFI_PAGE_SHIFT
);
833 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
834 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
837 // If it's not a free entry, don't bother with it
839 if (Entry
->Type
!= EfiConventionalMemory
) {
843 DescStart
= Entry
->Start
;
844 DescEnd
= Entry
->End
;
847 // If desc is past max allowed address, skip it
849 if (DescStart
>= MaxAddress
) {
854 // If desc ends past max allowed address, clip the end
856 if (DescEnd
>= MaxAddress
) {
857 DescEnd
= MaxAddress
;
860 DescEnd
= ((DescEnd
+ 1) & (~(Alignment
- 1))) - 1;
863 // Compute the number of bytes we can used from this
864 // descriptor, and see it's enough to satisfy the request
866 DescNumberOfBytes
= DescEnd
- DescStart
+ 1;
868 if (DescNumberOfBytes
>= NumberOfBytes
) {
871 // If this is the best match so far remember it
873 if (DescEnd
> Target
) {
880 // If this is a grow down, adjust target to be the allocation base
882 Target
-= NumberOfBytes
- 1;
885 // If we didn't find a match, return 0
887 if ((Target
& EFI_PAGE_MASK
) != 0) {
896 Internal function. Finds a consecutive free page range below
897 the requested address
899 @param MaxAddress The address that the range must be below
900 @param NoPages Number of pages needed
901 @param NewType The type of memory the range is going to be
903 @param Alignment Bits to align with
905 @return The base address of the range, or 0 if the range was not found.
910 IN UINT64 MaxAddress
,
912 IN EFI_MEMORY_TYPE NewType
,
916 UINT64 NewMaxAddress
;
919 NewMaxAddress
= MaxAddress
;
921 if (NewType
>= 0 && NewType
< EfiMaxMemoryType
&& NewMaxAddress
>= mMemoryTypeStatistics
[NewType
].MaximumAddress
) {
922 NewMaxAddress
= mMemoryTypeStatistics
[NewType
].MaximumAddress
;
924 if (NewMaxAddress
> mDefaultMaximumAddress
) {
925 NewMaxAddress
= mDefaultMaximumAddress
;
929 Start
= CoreFindFreePagesI (NewMaxAddress
, NoPages
, NewType
, Alignment
);
931 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
934 // Here means there may be no enough memory to use, so try to go through
935 // all the memory descript to promote the untested memory directly
937 PromoteMemoryResource ();
940 // Allocate memory again after the memory resource re-arranged
942 Start
= CoreFindFreePagesI (MaxAddress
, NoPages
, NewType
, Alignment
);
952 Allocates pages from the memory map.
954 @param Type The type of allocation to perform
955 @param MemoryType The type of memory to turn the allocated pages
957 @param NumberOfPages The number of pages to allocate
958 @param Memory A pointer to receive the base allocated memory
961 @return Status. On success, Memory is filled in with the base address allocated
962 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
964 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
965 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
966 @retval EFI_SUCCESS Pages successfully allocated.
972 IN EFI_ALLOCATE_TYPE Type
,
973 IN EFI_MEMORY_TYPE MemoryType
,
974 IN UINTN NumberOfPages
,
975 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
983 if (Type
< AllocateAnyPages
|| Type
>= (UINTN
) MaxAllocateType
) {
984 return EFI_INVALID_PARAMETER
;
987 if ((MemoryType
>= EfiMaxMemoryType
&& MemoryType
<= 0x7fffffff) ||
988 MemoryType
== EfiConventionalMemory
) {
989 return EFI_INVALID_PARAMETER
;
992 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
994 if (MemoryType
== EfiACPIReclaimMemory
||
995 MemoryType
== EfiACPIMemoryNVS
||
996 MemoryType
== EfiRuntimeServicesCode
||
997 MemoryType
== EfiRuntimeServicesData
) {
999 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1002 if (Type
== AllocateAddress
) {
1003 if ((*Memory
& (Alignment
- 1)) != 0) {
1004 return EFI_NOT_FOUND
;
1008 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1009 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1012 // If this is for below a particular address, then
1017 // The max address is the max natively addressable address for the processor
1019 MaxAddress
= EFI_MAX_ADDRESS
;
1021 if (Type
== AllocateMaxAddress
) {
1025 CoreAcquireMemoryLock ();
1028 // If not a specific address, then find an address to allocate
1030 if (Type
!= AllocateAddress
) {
1031 Start
= FindFreePages (MaxAddress
, NumberOfPages
, MemoryType
, Alignment
);
1033 Status
= EFI_OUT_OF_RESOURCES
;
1039 // Convert pages from FreeMemory to the requested type
1041 Status
= CoreConvertPages (Start
, NumberOfPages
, MemoryType
);
1044 CoreReleaseMemoryLock ();
1046 if (!EFI_ERROR (Status
)) {
1055 Frees previous allocated pages.
1057 @param Memory Base address of memory being freed
1058 @param NumberOfPages The number of pages to free
1060 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1061 @retval EFI_INVALID_PARAMETER Address not aligned
1062 @return EFI_SUCCESS -Pages successfully freed.
1068 IN EFI_PHYSICAL_ADDRESS Memory
,
1069 IN UINTN NumberOfPages
1080 CoreAcquireMemoryLock ();
1083 // Find the entry that the covers the range
1086 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1087 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1088 if (Entry
->Start
<= Memory
&& Entry
->End
> Memory
) {
1092 if (Link
== &gMemoryMap
) {
1093 CoreReleaseMemoryLock ();
1094 return EFI_NOT_FOUND
;
1097 Alignment
= EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT
;
1099 if (Entry
->Type
== EfiACPIReclaimMemory
||
1100 Entry
->Type
== EfiACPIMemoryNVS
||
1101 Entry
->Type
== EfiRuntimeServicesCode
||
1102 Entry
->Type
== EfiRuntimeServicesData
) {
1104 Alignment
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
1108 if ((Memory
& (Alignment
- 1)) != 0) {
1109 CoreReleaseMemoryLock ();
1110 return EFI_INVALID_PARAMETER
;
1113 NumberOfPages
+= EFI_SIZE_TO_PAGES (Alignment
) - 1;
1114 NumberOfPages
&= ~(EFI_SIZE_TO_PAGES (Alignment
) - 1);
1116 Status
= CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1118 CoreReleaseMemoryLock ();
1120 if (EFI_ERROR (Status
)) {
1125 // Destroy the contents
1127 if (Memory
< EFI_MAX_ADDRESS
) {
1128 DEBUG_CLEAR_MEMORY ((VOID
*)(UINTN
)Memory
, NumberOfPages
<< EFI_PAGE_SHIFT
);
1136 This function returns a copy of the current memory map. The map is an array of
1137 memory descriptors, each of which describes a contiguous block of memory.
1139 @param MemoryMapSize A pointer to the size, in bytes, of the
1140 MemoryMap buffer. On input, this is the size of
1141 the buffer allocated by the caller. On output,
1142 it is the size of the buffer returned by the
1143 firmware if the buffer was large enough, or the
1144 size of the buffer needed to contain the map if
1145 the buffer was too small.
1146 @param MemoryMap A pointer to the buffer in which firmware places
1147 the current memory map.
1148 @param MapKey A pointer to the location in which firmware
1149 returns the key for the current memory map.
1150 @param DescriptorSize A pointer to the location in which firmware
1151 returns the size, in bytes, of an individual
1152 EFI_MEMORY_DESCRIPTOR.
1153 @param DescriptorVersion A pointer to the location in which firmware
1154 returns the version number associated with the
1155 EFI_MEMORY_DESCRIPTOR.
1157 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1159 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1160 buffer size needed to hold the memory map is
1161 returned in MemoryMapSize.
1162 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1168 IN OUT UINTN
*MemoryMapSize
,
1169 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1171 OUT UINTN
*DescriptorSize
,
1172 OUT UINT32
*DescriptorVersion
1178 UINTN NumberOfRuntimeEntries
;
1181 EFI_GCD_MAP_ENTRY
*GcdMapEntry
;
1182 EFI_MEMORY_TYPE Type
;
1185 // Make sure the parameters are valid
1187 if (MemoryMapSize
== NULL
) {
1188 return EFI_INVALID_PARAMETER
;
1191 CoreAcquireGcdMemoryLock ();
1194 // Count the number of Reserved and MMIO entries that are marked for runtime use
1196 NumberOfRuntimeEntries
= 0;
1197 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1198 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1199 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1200 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1201 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1202 NumberOfRuntimeEntries
++;
1207 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1210 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1211 // prevent people from having pointer math bugs in their code.
1212 // now you have to use *DescriptorSize to make things work.
1214 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1216 if (DescriptorSize
!= NULL
) {
1217 *DescriptorSize
= Size
;
1220 if (DescriptorVersion
!= NULL
) {
1221 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1224 CoreAcquireMemoryLock ();
1227 // Compute the buffer size needed to fit the entire map
1229 BufferSize
= Size
* NumberOfRuntimeEntries
;
1230 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1234 if (*MemoryMapSize
< BufferSize
) {
1235 Status
= EFI_BUFFER_TOO_SMALL
;
1239 if (MemoryMap
== NULL
) {
1240 Status
= EFI_INVALID_PARAMETER
;
1247 ZeroMem (MemoryMap
, BufferSize
);
1248 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1249 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1250 ASSERT (Entry
->VirtualStart
== 0);
1253 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1255 MemoryMap
->Type
= Entry
->Type
;
1256 MemoryMap
->PhysicalStart
= Entry
->Start
;
1257 MemoryMap
->VirtualStart
= Entry
->VirtualStart
;
1258 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1260 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1261 // memory type bin and needs to be converted to the same memory type as the rest of the
1262 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1263 // improves the chances for a successful S4 resume in the presence of minor page allocation
1264 // differences across reboots.
1266 if (MemoryMap
->Type
== EfiConventionalMemory
) {
1267 for (Type
= (EFI_MEMORY_TYPE
) 0; Type
< EfiMaxMemoryType
; Type
++) {
1268 if (mMemoryTypeStatistics
[Type
].Special
&&
1269 mMemoryTypeStatistics
[Type
].NumberOfPages
> 0 &&
1270 Entry
->Start
>= mMemoryTypeStatistics
[Type
].BaseAddress
&&
1271 Entry
->End
<= mMemoryTypeStatistics
[Type
].MaximumAddress
) {
1272 MemoryMap
->Type
= Type
;
1276 MemoryMap
->Attribute
= Entry
->Attribute
;
1277 if (mMemoryTypeStatistics
[MemoryMap
->Type
].Runtime
) {
1278 MemoryMap
->Attribute
|= EFI_MEMORY_RUNTIME
;
1281 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1284 for (Link
= mGcdMemorySpaceMap
.ForwardLink
; Link
!= &mGcdMemorySpaceMap
; Link
= Link
->ForwardLink
) {
1285 GcdMapEntry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1286 if ((GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) ||
1287 (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
)) {
1288 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_RUNTIME
) == EFI_MEMORY_RUNTIME
) {
1290 MemoryMap
->PhysicalStart
= GcdMapEntry
->BaseAddress
;
1291 MemoryMap
->VirtualStart
= 0;
1292 MemoryMap
->NumberOfPages
= RShiftU64 ((GcdMapEntry
->EndAddress
- GcdMapEntry
->BaseAddress
+ 1), EFI_PAGE_SHIFT
);
1293 MemoryMap
->Attribute
= GcdMapEntry
->Attributes
& ~EFI_MEMORY_PORT_IO
;
1295 if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeReserved
) {
1296 MemoryMap
->Type
= EfiReservedMemoryType
;
1297 } else if (GcdMapEntry
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
1298 if ((GcdMapEntry
->Attributes
& EFI_MEMORY_PORT_IO
) == EFI_MEMORY_PORT_IO
) {
1299 MemoryMap
->Type
= EfiMemoryMappedIOPortSpace
;
1301 MemoryMap
->Type
= EfiMemoryMappedIO
;
1305 MemoryMap
= NextMemoryDescriptor (MemoryMap
, Size
);
1310 Status
= EFI_SUCCESS
;
1314 CoreReleaseMemoryLock ();
1316 CoreReleaseGcdMemoryLock ();
1319 // Update the map key finally
1321 if (MapKey
!= NULL
) {
1322 *MapKey
= mMemoryMapKey
;
1325 *MemoryMapSize
= BufferSize
;
1332 Internal function. Used by the pool functions to allocate pages
1333 to back pool allocation requests.
1335 @param PoolType The type of memory for the new pool pages
1336 @param NumberOfPages No of pages to allocate
1337 @param Alignment Bits to align.
1339 @return The allocated memory, or NULL
1343 CoreAllocatePoolPages (
1344 IN EFI_MEMORY_TYPE PoolType
,
1345 IN UINTN NumberOfPages
,
1352 // Find the pages to convert
1354 Start
= FindFreePages (EFI_MAX_ADDRESS
, NumberOfPages
, PoolType
, Alignment
);
1357 // Convert it to boot services data
1360 DEBUG ((DEBUG_ERROR
| DEBUG_PAGE
, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages
));
1362 CoreConvertPages (Start
, NumberOfPages
, PoolType
);
1365 return (VOID
*)(UINTN
) Start
;
1370 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1372 @param Memory The base address to free
1373 @param NumberOfPages The number of pages to free
1378 IN EFI_PHYSICAL_ADDRESS Memory
,
1379 IN UINTN NumberOfPages
1382 CoreConvertPages (Memory
, NumberOfPages
, EfiConventionalMemory
);
1388 Make sure the memory map is following all the construction rules,
1389 it is the last time to check memory map error before exit boot services.
1391 @param MapKey Memory map key
1393 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1395 @retval EFI_SUCCESS Valid memory map.
1399 CoreTerminateMemoryMap (
1407 Status
= EFI_SUCCESS
;
1409 CoreAcquireMemoryLock ();
1411 if (MapKey
== mMemoryMapKey
) {
1414 // Make sure the memory map is following all the construction rules
1415 // This is the last chance we will be able to display any messages on
1416 // the console devices.
1419 for (Link
= gMemoryMap
.ForwardLink
; Link
!= &gMemoryMap
; Link
= Link
->ForwardLink
) {
1420 Entry
= CR(Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1421 if (Entry
->Attribute
& EFI_MEMORY_RUNTIME
) {
1422 if (Entry
->Type
== EfiACPIReclaimMemory
|| Entry
->Type
== EfiACPIMemoryNVS
) {
1423 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1424 Status
= EFI_INVALID_PARAMETER
;
1427 if (Entry
->Start
& (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1428 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1429 Status
= EFI_INVALID_PARAMETER
;
1432 if ((Entry
->End
+ 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
- 1)) {
1433 DEBUG((DEBUG_ERROR
| DEBUG_PAGE
, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1434 Status
= EFI_INVALID_PARAMETER
;
1441 // The map key they gave us matches what we expect. Fall through and
1442 // return success. In an ideal world we would clear out all of
1443 // EfiBootServicesCode and EfiBootServicesData. However this function
1444 // is not the last one called by ExitBootServices(), so we have to
1445 // preserve the memory contents.
1448 Status
= EFI_INVALID_PARAMETER
;
1452 CoreReleaseMemoryLock ();