2 SMM Memory page management functions.
4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 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.
15 #include "PiSmmCore.h"
16 #include <Library/SmmServicesTableLib.h>
18 #define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
20 LIST_ENTRY mSmmMemoryMap
= INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap
);
26 #define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')
38 LIST_ENTRY gMemoryMap
= INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap
);
41 #define MAX_MAP_DEPTH 6
44 /// mMapDepth - depth of new descriptor stack
48 /// mMapStack - space to use as temp storage to build new map descriptors
50 MEMORY_MAP mMapStack
[MAX_MAP_DEPTH
];
51 UINTN mFreeMapStack
= 0;
53 /// This list maintain the free memory map list
55 LIST_ENTRY mFreeMemoryMapEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList
);
58 Allocates pages from the memory map.
60 @param[in] Type The type of allocation to perform.
61 @param[in] MemoryType The type of memory to turn the allocated pages
63 @param[in] NumberOfPages The number of pages to allocate.
64 @param[out] Memory A pointer to receive the base allocated memory
66 @param[in] AddRegion If this memory is new added region.
67 @param[in] NeedGuard Flag to indicate Guard page is needed
70 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
71 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
72 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
73 @retval EFI_SUCCESS Pages successfully allocated.
77 SmmInternalAllocatePagesEx (
78 IN EFI_ALLOCATE_TYPE Type
,
79 IN EFI_MEMORY_TYPE MemoryType
,
80 IN UINTN NumberOfPages
,
81 OUT EFI_PHYSICAL_ADDRESS
*Memory
,
87 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
88 If the list is emtry, then allocate a new page to refuel the list.
89 Please Note this algorithm to allocate the memory map descriptor has a property
90 that the memory allocated for memory entries always grows, and will never really be freed.
92 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
96 AllocateMemoryMapEntry (
100 EFI_PHYSICAL_ADDRESS Mem
;
102 MEMORY_MAP
* FreeDescriptorEntries
;
106 //DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));
108 if (IsListEmpty (&mFreeMemoryMapEntryList
)) {
109 //DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));
111 // The list is empty, to allocate one page to refuel the list
113 Status
= SmmInternalAllocatePagesEx (
115 EfiRuntimeServicesData
,
116 EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY
),
121 ASSERT_EFI_ERROR (Status
);
122 if(!EFI_ERROR (Status
)) {
123 FreeDescriptorEntries
= (MEMORY_MAP
*)(UINTN
)Mem
;
124 //DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));
126 // Enque the free memmory map entries into the list
128 for (Index
= 0; Index
< RUNTIME_PAGE_ALLOCATION_GRANULARITY
/ sizeof(MEMORY_MAP
); Index
++) {
129 FreeDescriptorEntries
[Index
].Signature
= MEMORY_MAP_SIGNATURE
;
130 InsertTailList (&mFreeMemoryMapEntryList
, &FreeDescriptorEntries
[Index
].Link
);
137 // dequeue the first descriptor from the list
139 Entry
= CR (mFreeMemoryMapEntryList
.ForwardLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
140 RemoveEntryList (&Entry
->Link
);
147 Internal function. Moves any memory descriptors that are on the
148 temporary descriptor stack to heap.
152 CoreFreeMemoryMapStack (
159 // If already freeing the map stack, then return
161 if (mFreeMapStack
!= 0) {
167 // Move the temporary memory descriptor stack into pool
171 while (mMapDepth
!= 0) {
173 // Deque an memory map entry from mFreeMemoryMapEntryList
175 Entry
= AllocateMemoryMapEntry ();
179 // Update to proper entry
183 if (mMapStack
[mMapDepth
].Link
.ForwardLink
!= NULL
) {
185 CopyMem (Entry
, &mMapStack
[mMapDepth
], sizeof (MEMORY_MAP
));
186 Entry
->FromStack
= FALSE
;
189 // Move this entry to general memory
191 InsertTailList (&mMapStack
[mMapDepth
].Link
, &Entry
->Link
);
192 RemoveEntryList (&mMapStack
[mMapDepth
].Link
);
193 mMapStack
[mMapDepth
].Link
.ForwardLink
= NULL
;
201 Insert new entry from memory map.
203 @param[in] Link The old memory map entry to be linked.
204 @param[in] Start The start address of new memory map entry.
205 @param[in] End The end address of new memory map entry.
206 @param[in] Type The type of new memory map entry.
207 @param[in] Next If new entry is inserted to the next of old entry.
208 @param[in] AddRegion If this memory is new added region.
215 IN EFI_MEMORY_TYPE Type
,
222 Entry
= &mMapStack
[mMapDepth
];
224 ASSERT (mMapDepth
< MAX_MAP_DEPTH
);
225 Entry
->FromStack
= TRUE
;
227 Entry
->Signature
= MEMORY_MAP_SIGNATURE
;
229 Entry
->Start
= Start
;
232 InsertHeadList (Link
, &Entry
->Link
);
234 InsertTailList (Link
, &Entry
->Link
);
239 Remove old entry from memory map.
241 @param[in] Entry Memory map entry to be removed.
248 RemoveEntryList (&Entry
->Link
);
249 if (!Entry
->FromStack
) {
250 InsertTailList (&mFreeMemoryMapEntryList
, &Entry
->Link
);
255 Update SMM memory map entry.
257 @param[in] Type The type of allocation to perform.
258 @param[in] Memory The base of memory address.
259 @param[in] NumberOfPages The number of pages to allocate.
260 @param[in] AddRegion If this memory is new added region.
263 ConvertSmmMemoryMapEntry (
264 IN EFI_MEMORY_TYPE Type
,
265 IN EFI_PHYSICAL_ADDRESS Memory
,
266 IN UINTN NumberOfPages
,
272 MEMORY_MAP
*NextEntry
;
273 LIST_ENTRY
*NextLink
;
274 MEMORY_MAP
*PreviousEntry
;
275 LIST_ENTRY
*PreviousLink
;
276 EFI_PHYSICAL_ADDRESS Start
;
277 EFI_PHYSICAL_ADDRESS End
;
280 End
= Memory
+ EFI_PAGES_TO_SIZE(NumberOfPages
) - 1;
283 // Exclude memory region
285 Link
= gMemoryMap
.ForwardLink
;
286 while (Link
!= &gMemoryMap
) {
287 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
288 Link
= Link
->ForwardLink
;
291 // ---------------------------------------------------
292 // | +----------+ +------+ +------+ +------+ |
293 // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
294 // +----------+ ^ +------+ +------+ +------+
300 if (Entry
->Start
> End
) {
301 if ((Entry
->Start
== End
+ 1) && (Entry
->Type
== Type
)) {
302 Entry
->Start
= Start
;
316 if ((Entry
->Start
<= Start
) && (Entry
->End
>= End
)) {
317 if (Entry
->Type
!= Type
) {
318 if (Entry
->Start
< Start
) {
320 // ---------------------------------------------------
321 // | +----------+ +------+ +------+ +------+ |
322 // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
323 // +----------+ +------+ ^ +------+ +------+
338 if (Entry
->End
> End
) {
340 // ---------------------------------------------------
341 // | +----------+ +------+ +------+ +------+ |
342 // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
343 // +----------+ +------+ +------+ ^ +------+
361 Entry
->Start
= Start
;
368 NextLink
= Entry
->Link
.ForwardLink
;
369 if (NextLink
!= &gMemoryMap
) {
370 NextEntry
= CR (NextLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
372 // ---------------------------------------------------
373 // | +----------+ +------+ +-----------------+ |
374 // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|---
375 // +----------+ +------+ +-----------------+
377 if ((Entry
->Type
== NextEntry
->Type
) && (Entry
->End
+ 1 == NextEntry
->Start
)) {
378 Entry
->End
= NextEntry
->End
;
379 RemoveOldEntry (NextEntry
);
382 PreviousLink
= Entry
->Link
.BackLink
;
383 if (PreviousLink
!= &gMemoryMap
) {
384 PreviousEntry
= CR (PreviousLink
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
386 // ---------------------------------------------------
387 // | +----------+ +-----------------+ +------+ |
388 // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|---
389 // +----------+ +-----------------+ +------+
391 if ((PreviousEntry
->Type
== Entry
->Type
) && (PreviousEntry
->End
+ 1 == Entry
->Start
)) {
392 PreviousEntry
->End
= Entry
->End
;
393 RemoveOldEntry (Entry
);
402 // ---------------------------------------------------
403 // | +----------+ +------+ +------+ +------+ |
404 // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
405 // +----------+ +------+ +------+ +------+ ^
411 Link
= gMemoryMap
.BackLink
;
412 if (Link
!= &gMemoryMap
) {
413 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
414 if ((Entry
->End
+ 1 == Start
) && (Entry
->Type
== Type
)) {
431 Return the count of Smm memory map entry.
433 @return The count of Smm memory map entry.
436 GetSmmMemoryMapEntryCount (
444 Link
= gMemoryMap
.ForwardLink
;
445 while (Link
!= &gMemoryMap
) {
446 Link
= Link
->ForwardLink
;
453 Dump Smm memory map entry.
456 DumpSmmMemoryMapEntry (
462 EFI_PHYSICAL_ADDRESS Last
;
465 DEBUG ((DEBUG_INFO
, "DumpSmmMemoryMapEntry:\n"));
466 Link
= gMemoryMap
.ForwardLink
;
467 while (Link
!= &gMemoryMap
) {
468 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
469 Link
= Link
->ForwardLink
;
471 if ((Last
!= 0) && (Last
!= (UINT64
)-1)) {
472 if (Last
+ 1 != Entry
->Start
) {
477 } else if (Last
== 0) {
481 DEBUG ((DEBUG_INFO
, "Entry (Link - 0x%x)\n", &Entry
->Link
));
482 DEBUG ((DEBUG_INFO
, " Signature - 0x%x\n", Entry
->Signature
));
483 DEBUG ((DEBUG_INFO
, " Link.ForwardLink - 0x%x\n", Entry
->Link
.ForwardLink
));
484 DEBUG ((DEBUG_INFO
, " Link.BackLink - 0x%x\n", Entry
->Link
.BackLink
));
485 DEBUG ((DEBUG_INFO
, " Type - 0x%x\n", Entry
->Type
));
486 DEBUG ((DEBUG_INFO
, " Start - 0x%016lx\n", Entry
->Start
));
487 DEBUG ((DEBUG_INFO
, " End - 0x%016lx\n", Entry
->End
));
490 ASSERT (Last
!= (UINT64
)-1);
502 FREE_PAGE_LIST
*Pages
;
504 DEBUG ((DEBUG_INFO
, "DumpSmmMemoryMap\n"));
507 Node
= mSmmMemoryMap
.ForwardLink
;
508 while (Node
!= &mSmmMemoryMap
) {
509 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
510 DEBUG ((DEBUG_INFO
, "Pages - 0x%x\n", Pages
));
511 DEBUG ((DEBUG_INFO
, "Pages->NumberOfPages - 0x%x\n", Pages
->NumberOfPages
));
512 Node
= Node
->ForwardLink
;
517 Check if a Smm base~length is in Smm memory map.
519 @param[in] Base The base address of Smm memory to be checked.
520 @param[in] Length THe length of Smm memory to be checked.
522 @retval TRUE Smm base~length is in smm memory map.
523 @retval FALSE Smm base~length is in smm memory map.
526 SmmMemoryMapConsistencyCheckRange (
527 IN EFI_PHYSICAL_ADDRESS Base
,
536 Link
= gMemoryMap
.ForwardLink
;
537 while (Link
!= &gMemoryMap
) {
538 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
539 Link
= Link
->ForwardLink
;
541 if (Entry
->Type
!= EfiConventionalMemory
) {
544 if (Entry
->Start
== Base
&& Entry
->End
== Base
+ Length
- 1) {
554 Check the consistency of Smm memory map.
557 SmmMemoryMapConsistencyCheck (
562 FREE_PAGE_LIST
*Pages
;
566 Node
= mSmmMemoryMap
.ForwardLink
;
567 while (Node
!= &mSmmMemoryMap
) {
568 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
569 Result
= SmmMemoryMapConsistencyCheckRange ((EFI_PHYSICAL_ADDRESS
)(UINTN
)Pages
, (UINTN
)EFI_PAGES_TO_SIZE(Pages
->NumberOfPages
));
571 Node
= Node
->ForwardLink
;
576 Internal Function. Allocate n pages from given free page node.
578 @param Pages The free page node.
579 @param NumberOfPages Number of pages to be allocated.
580 @param MaxAddress Request to allocate memory below this address.
582 @return Memory address of allocated pages.
586 InternalAllocPagesOnOneNode (
587 IN OUT FREE_PAGE_LIST
*Pages
,
588 IN UINTN NumberOfPages
,
594 FREE_PAGE_LIST
*Node
;
596 Top
= TRUNCATE_TO_PAGES (MaxAddress
+ 1 - (UINTN
)Pages
);
597 if (Top
> Pages
->NumberOfPages
) {
598 Top
= Pages
->NumberOfPages
;
600 Bottom
= Top
- NumberOfPages
;
602 if (Top
< Pages
->NumberOfPages
) {
603 Node
= (FREE_PAGE_LIST
*)((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Top
));
604 Node
->NumberOfPages
= Pages
->NumberOfPages
- Top
;
605 InsertHeadList (&Pages
->Link
, &Node
->Link
);
609 Pages
->NumberOfPages
= Bottom
;
611 RemoveEntryList (&Pages
->Link
);
614 return (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Bottom
);
618 Internal Function. Allocate n pages from free page list below MaxAddress.
620 @param FreePageList The free page node.
621 @param NumberOfPages Number of pages to be allocated.
622 @param MaxAddress Request to allocate memory below this address.
624 @return Memory address of allocated pages.
628 InternalAllocMaxAddress (
629 IN OUT LIST_ENTRY
*FreePageList
,
630 IN UINTN NumberOfPages
,
635 FREE_PAGE_LIST
*Pages
;
637 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
638 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
639 if (Pages
->NumberOfPages
>= NumberOfPages
&&
640 (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
) {
641 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, MaxAddress
);
648 Internal Function. Allocate n pages from free page list at given address.
650 @param FreePageList The free page node.
651 @param NumberOfPages Number of pages to be allocated.
652 @param MaxAddress Request to allocate memory below this address.
654 @return Memory address of allocated pages.
658 InternalAllocAddress (
659 IN OUT LIST_ENTRY
*FreePageList
,
660 IN UINTN NumberOfPages
,
666 FREE_PAGE_LIST
*Pages
;
668 if ((Address
& EFI_PAGE_MASK
) != 0) {
672 EndAddress
= Address
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
673 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
674 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
675 if ((UINTN
)Pages
<= Address
) {
676 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) < EndAddress
) {
679 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, EndAddress
);
686 Allocates pages from the memory map.
688 @param[in] Type The type of allocation to perform.
689 @param[in] MemoryType The type of memory to turn the allocated pages
691 @param[in] NumberOfPages The number of pages to allocate.
692 @param[out] Memory A pointer to receive the base allocated memory
694 @param[in] AddRegion If this memory is new added region.
695 @param[in] NeedGuard Flag to indicate Guard page is needed
698 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
699 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
700 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
701 @retval EFI_SUCCESS Pages successfully allocated.
705 SmmInternalAllocatePagesEx (
706 IN EFI_ALLOCATE_TYPE Type
,
707 IN EFI_MEMORY_TYPE MemoryType
,
708 IN UINTN NumberOfPages
,
709 OUT EFI_PHYSICAL_ADDRESS
*Memory
,
710 IN BOOLEAN AddRegion
,
714 UINTN RequestedAddress
;
716 if (MemoryType
!= EfiRuntimeServicesCode
&&
717 MemoryType
!= EfiRuntimeServicesData
) {
718 return EFI_INVALID_PARAMETER
;
721 if (NumberOfPages
> TRUNCATE_TO_PAGES ((UINTN
)-1) + 1) {
722 return EFI_OUT_OF_RESOURCES
;
726 // We don't track memory type in SMM
728 RequestedAddress
= (UINTN
)*Memory
;
730 case AllocateAnyPages
:
731 RequestedAddress
= (UINTN
)(-1);
732 case AllocateMaxAddress
:
734 *Memory
= InternalAllocMaxAddressWithGuard (
740 if (*Memory
== (UINTN
)-1) {
741 return EFI_OUT_OF_RESOURCES
;
743 ASSERT (VerifyMemoryGuard (*Memory
, NumberOfPages
) == TRUE
);
748 *Memory
= InternalAllocMaxAddress (
753 if (*Memory
== (UINTN
)-1) {
754 return EFI_OUT_OF_RESOURCES
;
757 case AllocateAddress
:
758 *Memory
= InternalAllocAddress (
763 if (*Memory
!= RequestedAddress
) {
764 return EFI_NOT_FOUND
;
768 return EFI_INVALID_PARAMETER
;
772 // Update SmmMemoryMap here.
774 ConvertSmmMemoryMapEntry (MemoryType
, *Memory
, NumberOfPages
, AddRegion
);
776 CoreFreeMemoryMapStack();
783 Allocates pages from the memory map.
785 @param[in] Type The type of allocation to perform.
786 @param[in] MemoryType The type of memory to turn the allocated pages
788 @param[in] NumberOfPages The number of pages to allocate.
789 @param[out] Memory A pointer to receive the base allocated memory
791 @param[in] NeedGuard Flag to indicate Guard page is needed
794 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
795 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
796 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
797 @retval EFI_SUCCESS Pages successfully allocated.
802 SmmInternalAllocatePages (
803 IN EFI_ALLOCATE_TYPE Type
,
804 IN EFI_MEMORY_TYPE MemoryType
,
805 IN UINTN NumberOfPages
,
806 OUT EFI_PHYSICAL_ADDRESS
*Memory
,
810 return SmmInternalAllocatePagesEx (Type
, MemoryType
, NumberOfPages
, Memory
,
815 Allocates pages from the memory map.
817 @param Type The type of allocation to perform.
818 @param MemoryType The type of memory to turn the allocated pages
820 @param NumberOfPages The number of pages to allocate.
821 @param Memory A pointer to receive the base allocated memory
824 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
825 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
826 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
827 @retval EFI_SUCCESS Pages successfully allocated.
833 IN EFI_ALLOCATE_TYPE Type
,
834 IN EFI_MEMORY_TYPE MemoryType
,
835 IN UINTN NumberOfPages
,
836 OUT EFI_PHYSICAL_ADDRESS
*Memory
842 NeedGuard
= IsPageTypeToGuard (MemoryType
, Type
);
843 Status
= SmmInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
,
845 if (!EFI_ERROR (Status
)) {
846 SmmCoreUpdateProfile (
847 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
848 MemoryProfileActionAllocatePages
,
850 EFI_PAGES_TO_SIZE (NumberOfPages
),
851 (VOID
*) (UINTN
) *Memory
,
859 Internal Function. Merge two adjacent nodes.
861 @param First The first of two nodes to merge.
863 @return Pointer to node after merge (if success) or pointer to next node (if fail).
868 IN FREE_PAGE_LIST
*First
871 FREE_PAGE_LIST
*Next
;
873 Next
= BASE_CR (First
->Link
.ForwardLink
, FREE_PAGE_LIST
, Link
);
875 TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) >= First
->NumberOfPages
);
877 if (TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) == First
->NumberOfPages
) {
878 First
->NumberOfPages
+= Next
->NumberOfPages
;
879 RemoveEntryList (&Next
->Link
);
886 Frees previous allocated pages.
888 @param[in] Memory Base address of memory being freed.
889 @param[in] NumberOfPages The number of pages to free.
890 @param[in] AddRegion If this memory is new added region.
892 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
893 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
894 @return EFI_SUCCESS Pages successfully freed.
898 SmmInternalFreePagesEx (
899 IN EFI_PHYSICAL_ADDRESS Memory
,
900 IN UINTN NumberOfPages
,
905 FREE_PAGE_LIST
*Pages
;
907 if (((Memory
& EFI_PAGE_MASK
) != 0) || (Memory
== 0) || (NumberOfPages
== 0)) {
908 return EFI_INVALID_PARAMETER
;
912 Node
= mSmmMemoryMap
.ForwardLink
;
913 while (Node
!= &mSmmMemoryMap
) {
914 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
915 if (Memory
< (UINTN
)Pages
) {
918 Node
= Node
->ForwardLink
;
921 if (Node
!= &mSmmMemoryMap
&&
922 Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
) > (UINTN
)Pages
) {
923 return EFI_INVALID_PARAMETER
;
926 if (Node
->BackLink
!= &mSmmMemoryMap
) {
927 Pages
= BASE_CR (Node
->BackLink
, FREE_PAGE_LIST
, Link
);
928 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) > Memory
) {
929 return EFI_INVALID_PARAMETER
;
933 Pages
= (FREE_PAGE_LIST
*)(UINTN
)Memory
;
934 Pages
->NumberOfPages
= NumberOfPages
;
935 InsertTailList (Node
, &Pages
->Link
);
937 if (Pages
->Link
.BackLink
!= &mSmmMemoryMap
) {
938 Pages
= InternalMergeNodes (
939 BASE_CR (Pages
->Link
.BackLink
, FREE_PAGE_LIST
, Link
)
943 if (Node
!= &mSmmMemoryMap
) {
944 InternalMergeNodes (Pages
);
948 // Update SmmMemoryMap here.
950 ConvertSmmMemoryMapEntry (EfiConventionalMemory
, Memory
, NumberOfPages
, AddRegion
);
952 CoreFreeMemoryMapStack();
959 Frees previous allocated pages.
961 @param[in] Memory Base address of memory being freed.
962 @param[in] NumberOfPages The number of pages to free.
963 @param[in] IsGuarded Is the memory to free guarded or not.
965 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
966 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
967 @return EFI_SUCCESS Pages successfully freed.
972 SmmInternalFreePages (
973 IN EFI_PHYSICAL_ADDRESS Memory
,
974 IN UINTN NumberOfPages
,
979 return SmmInternalFreePagesExWithGuard (Memory
, NumberOfPages
, FALSE
);
981 return SmmInternalFreePagesEx (Memory
, NumberOfPages
, FALSE
);
985 Frees previous allocated pages.
987 @param Memory Base address of memory being freed.
988 @param NumberOfPages The number of pages to free.
990 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
991 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
992 @return EFI_SUCCESS Pages successfully freed.
998 IN EFI_PHYSICAL_ADDRESS Memory
,
999 IN UINTN NumberOfPages
1005 IsGuarded
= IsHeapGuardEnabled () && IsMemoryGuarded (Memory
);
1006 Status
= SmmInternalFreePages (Memory
, NumberOfPages
, IsGuarded
);
1007 if (!EFI_ERROR (Status
)) {
1008 SmmCoreUpdateProfile (
1009 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
1010 MemoryProfileActionFreePages
,
1012 EFI_PAGES_TO_SIZE (NumberOfPages
),
1013 (VOID
*) (UINTN
) Memory
,
1021 Add free SMRAM region for use by memory service.
1023 @param MemBase Base address of memory region.
1024 @param MemLength Length of the memory region.
1025 @param Type Memory type.
1026 @param Attributes Memory region state.
1030 SmmAddMemoryRegion (
1031 IN EFI_PHYSICAL_ADDRESS MemBase
,
1032 IN UINT64 MemLength
,
1033 IN EFI_MEMORY_TYPE Type
,
1034 IN UINT64 Attributes
1037 UINTN AlignedMemBase
;
1040 // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization
1042 if ((Attributes
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
1043 Type
= EfiRuntimeServicesData
;
1045 Type
= EfiConventionalMemory
;
1048 DEBUG ((DEBUG_INFO
, "SmmAddMemoryRegion\n"));
1049 DEBUG ((DEBUG_INFO
, " MemBase - 0x%lx\n", MemBase
));
1050 DEBUG ((DEBUG_INFO
, " MemLength - 0x%lx\n", MemLength
));
1051 DEBUG ((DEBUG_INFO
, " Type - 0x%x\n", Type
));
1052 DEBUG ((DEBUG_INFO
, " Attributes - 0x%lx\n", Attributes
));
1055 // Align range on an EFI_PAGE_SIZE boundary
1057 AlignedMemBase
= (UINTN
)(MemBase
+ EFI_PAGE_MASK
) & ~EFI_PAGE_MASK
;
1058 MemLength
-= AlignedMemBase
- MemBase
;
1059 if (Type
== EfiConventionalMemory
) {
1060 SmmInternalFreePagesEx (AlignedMemBase
, TRUNCATE_TO_PAGES ((UINTN
)MemLength
), TRUE
);
1062 ConvertSmmMemoryMapEntry (EfiRuntimeServicesData
, AlignedMemBase
, TRUNCATE_TO_PAGES ((UINTN
)MemLength
), TRUE
);
1065 CoreFreeMemoryMapStack ();
1069 This function returns a copy of the current memory map. The map is an array of
1070 memory descriptors, each of which describes a contiguous block of memory.
1072 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
1073 MemoryMap buffer. On input, this is the size of
1074 the buffer allocated by the caller. On output,
1075 it is the size of the buffer returned by the
1076 firmware if the buffer was large enough, or the
1077 size of the buffer needed to contain the map if
1078 the buffer was too small.
1079 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
1080 the current memory map.
1081 @param[out] MapKey A pointer to the location in which firmware
1082 returns the key for the current memory map.
1083 @param[out] DescriptorSize A pointer to the location in which firmware
1084 returns the size, in bytes, of an individual
1085 EFI_MEMORY_DESCRIPTOR.
1086 @param[out] DescriptorVersion A pointer to the location in which firmware
1087 returns the version number associated with the
1088 EFI_MEMORY_DESCRIPTOR.
1090 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1092 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1093 buffer size needed to hold the memory map is
1094 returned in MemoryMapSize.
1095 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1100 SmmCoreGetMemoryMap (
1101 IN OUT UINTN
*MemoryMapSize
,
1102 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1104 OUT UINTN
*DescriptorSize
,
1105 OUT UINT32
*DescriptorVersion
1114 Size
= sizeof (EFI_MEMORY_DESCRIPTOR
);
1117 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1118 // prevent people from having pointer math bugs in their code.
1119 // now you have to use *DescriptorSize to make things work.
1121 Size
+= sizeof(UINT64
) - (Size
% sizeof (UINT64
));
1123 if (DescriptorSize
!= NULL
) {
1124 *DescriptorSize
= Size
;
1127 if (DescriptorVersion
!= NULL
) {
1128 *DescriptorVersion
= EFI_MEMORY_DESCRIPTOR_VERSION
;
1131 Count
= GetSmmMemoryMapEntryCount ();
1132 BufferSize
= Size
* Count
;
1133 if (*MemoryMapSize
< BufferSize
) {
1134 *MemoryMapSize
= BufferSize
;
1135 return EFI_BUFFER_TOO_SMALL
;
1138 *MemoryMapSize
= BufferSize
;
1139 if (MemoryMap
== NULL
) {
1140 return EFI_INVALID_PARAMETER
;
1143 ZeroMem (MemoryMap
, BufferSize
);
1144 Link
= gMemoryMap
.ForwardLink
;
1145 while (Link
!= &gMemoryMap
) {
1146 Entry
= CR (Link
, MEMORY_MAP
, Link
, MEMORY_MAP_SIGNATURE
);
1147 Link
= Link
->ForwardLink
;
1149 MemoryMap
->Type
= Entry
->Type
;
1150 MemoryMap
->PhysicalStart
= Entry
->Start
;
1151 MemoryMap
->NumberOfPages
= RShiftU64 (Entry
->End
- Entry
->Start
+ 1, EFI_PAGE_SHIFT
);
1153 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, Size
);