2 UEFI Heap Guard functions.
4 Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 // Global to avoid infinite reentrance of memory allocation when updating
13 // page table attributes, which may need allocating pages for new PDE/PTE.
15 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding
= FALSE
;
18 // Pointer to table tracking the Guarded memory with bitmap, in which '1'
19 // is used to indicate memory guarded. '0' might be free memory or Guard
20 // page itself, depending on status of memory adjacent to it.
22 GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap
= 0;
25 // Current depth level of map table pointed by mGuardedMemoryMap.
26 // mMapLevel must be initialized at least by 1. It will be automatically
27 // updated according to the address of memory just tracked.
29 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel
= 1;
32 // Shift and mask for each level of map table
34 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift
[GUARDED_HEAP_MAP_TABLE_DEPTH
]
35 = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS
;
36 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask
[GUARDED_HEAP_MAP_TABLE_DEPTH
]
37 = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS
;
40 // SMM memory attribute protocol
42 EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*mSmmMemoryAttribute
= NULL
;
45 Set corresponding bits in bitmap table to 1 according to the address.
47 @param[in] Address Start address to set for.
48 @param[in] BitNumber Number of bits to set.
49 @param[in] BitMap Pointer to bitmap which covers the Address.
56 IN EFI_PHYSICAL_ADDRESS Address
,
67 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
68 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
70 if ((StartBit
+ BitNumber
) >= GUARDED_HEAP_MAP_ENTRY_BITS
) {
71 Msbs
= (GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
) %
72 GUARDED_HEAP_MAP_ENTRY_BITS
;
73 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
74 Qwords
= (BitNumber
- Msbs
) / GUARDED_HEAP_MAP_ENTRY_BITS
;
82 *BitMap
|= LShiftU64 (LShiftU64 (1, Msbs
) - 1, StartBit
);
89 Qwords
* GUARDED_HEAP_MAP_ENTRY_BYTES
,
96 *BitMap
|= (LShiftU64 (1, Lsbs
) - 1);
101 Set corresponding bits in bitmap table to 0 according to the address.
103 @param[in] Address Start address to set for.
104 @param[in] BitNumber Number of bits to set.
105 @param[in] BitMap Pointer to bitmap which covers the Address.
112 IN EFI_PHYSICAL_ADDRESS Address
,
123 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
124 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
126 if ((StartBit
+ BitNumber
) >= GUARDED_HEAP_MAP_ENTRY_BITS
) {
127 Msbs
= (GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
) %
128 GUARDED_HEAP_MAP_ENTRY_BITS
;
129 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
130 Qwords
= (BitNumber
- Msbs
) / GUARDED_HEAP_MAP_ENTRY_BITS
;
138 *BitMap
&= ~LShiftU64 (LShiftU64 (1, Msbs
) - 1, StartBit
);
143 SetMem64 ((VOID
*)BitMap
, Qwords
* GUARDED_HEAP_MAP_ENTRY_BYTES
, 0);
148 *BitMap
&= ~(LShiftU64 (1, Lsbs
) - 1);
153 Get corresponding bits in bitmap table according to the address.
155 The value of bit 0 corresponds to the status of memory at given Address.
156 No more than 64 bits can be retrieved in one call.
158 @param[in] Address Start address to retrieve bits for.
159 @param[in] BitNumber Number of bits to get.
160 @param[in] BitMap Pointer to bitmap which covers the Address.
162 @return An integer containing the bits information.
167 IN EFI_PHYSICAL_ADDRESS Address
,
178 ASSERT (BitNumber
<= GUARDED_HEAP_MAP_ENTRY_BITS
);
180 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
181 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
183 if ((StartBit
+ BitNumber
) > GUARDED_HEAP_MAP_ENTRY_BITS
) {
184 Msbs
= GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
;
185 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
191 if ((StartBit
== 0) && (BitNumber
== GUARDED_HEAP_MAP_ENTRY_BITS
)) {
194 Result
= RShiftU64 ((*BitMap
), StartBit
) & (LShiftU64 (1, Msbs
) - 1);
197 Result
|= LShiftU64 ((*BitMap
) & (LShiftU64 (1, Lsbs
) - 1), Msbs
);
205 Helper function to allocate pages without Guard for internal uses.
207 @param[in] Pages Page number.
209 @return Address of memory allocated.
217 EFI_PHYSICAL_ADDRESS Memory
;
219 Status
= SmmInternalAllocatePages (
221 EfiRuntimeServicesData
,
226 if (EFI_ERROR (Status
)) {
230 return (VOID
*)(UINTN
)Memory
;
234 Locate the pointer of bitmap from the guarded memory bitmap tables, which
235 covers the given Address.
237 @param[in] Address Start address to search the bitmap for.
238 @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
239 @param[out] BitMap Pointer to bitmap which covers the Address.
241 @return The bit number from given Address to the end of current map table.
244 FindGuardedMemoryMap (
245 IN EFI_PHYSICAL_ADDRESS Address
,
246 IN BOOLEAN AllocMapUnit
,
258 // Adjust current map table depth according to the address to access
260 while (AllocMapUnit
&&
261 mMapLevel
< GUARDED_HEAP_MAP_TABLE_DEPTH
&&
264 mLevelShift
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1]
267 if (mGuardedMemoryMap
!= 0) {
268 Size
= (mLevelMask
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1] + 1)
269 * GUARDED_HEAP_MAP_ENTRY_BYTES
;
270 MapMemory
= (UINT64
)(UINTN
)PageAlloc (EFI_SIZE_TO_PAGES (Size
));
271 ASSERT (MapMemory
!= 0);
273 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
275 *(UINT64
*)(UINTN
)MapMemory
= mGuardedMemoryMap
;
276 mGuardedMemoryMap
= MapMemory
;
282 GuardMap
= &mGuardedMemoryMap
;
283 for (Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
284 Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
;
287 if (*GuardMap
== 0) {
293 Size
= (mLevelMask
[Level
] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES
;
294 MapMemory
= (UINT64
)(UINTN
)PageAlloc (EFI_SIZE_TO_PAGES (Size
));
295 ASSERT (MapMemory
!= 0);
297 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
298 *GuardMap
= MapMemory
;
301 Index
= (UINTN
)RShiftU64 (Address
, mLevelShift
[Level
]);
302 Index
&= mLevelMask
[Level
];
303 GuardMap
= (UINT64
*)(UINTN
)((*GuardMap
) + Index
* sizeof (UINT64
));
306 BitsToUnitEnd
= GUARDED_HEAP_MAP_BITS
- GUARDED_HEAP_MAP_BIT_INDEX (Address
);
309 return BitsToUnitEnd
;
313 Set corresponding bits in bitmap table to 1 according to given memory range.
315 @param[in] Address Memory address to guard from.
316 @param[in] NumberOfPages Number of pages to guard.
322 SetGuardedMemoryBits (
323 IN EFI_PHYSICAL_ADDRESS Address
,
324 IN UINTN NumberOfPages
331 while (NumberOfPages
> 0) {
332 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, TRUE
, &BitMap
);
333 ASSERT (BitMap
!= NULL
);
335 if (NumberOfPages
> BitsToUnitEnd
) {
337 Bits
= BitsToUnitEnd
;
339 Bits
= NumberOfPages
;
342 SetBits (Address
, Bits
, BitMap
);
344 NumberOfPages
-= Bits
;
345 Address
+= EFI_PAGES_TO_SIZE (Bits
);
350 Clear corresponding bits in bitmap table according to given memory range.
352 @param[in] Address Memory address to unset from.
353 @param[in] NumberOfPages Number of pages to unset guard.
359 ClearGuardedMemoryBits (
360 IN EFI_PHYSICAL_ADDRESS Address
,
361 IN UINTN NumberOfPages
368 while (NumberOfPages
> 0) {
369 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, TRUE
, &BitMap
);
370 ASSERT (BitMap
!= NULL
);
372 if (NumberOfPages
> BitsToUnitEnd
) {
374 Bits
= BitsToUnitEnd
;
376 Bits
= NumberOfPages
;
379 ClearBits (Address
, Bits
, BitMap
);
381 NumberOfPages
-= Bits
;
382 Address
+= EFI_PAGES_TO_SIZE (Bits
);
387 Retrieve corresponding bits in bitmap table according to given memory range.
389 @param[in] Address Memory address to retrieve from.
390 @param[in] NumberOfPages Number of pages to retrieve.
392 @return An integer containing the guarded memory bitmap.
395 GetGuardedMemoryBits (
396 IN EFI_PHYSICAL_ADDRESS Address
,
397 IN UINTN NumberOfPages
406 ASSERT (NumberOfPages
<= GUARDED_HEAP_MAP_ENTRY_BITS
);
410 while (NumberOfPages
> 0) {
411 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, FALSE
, &BitMap
);
413 if (NumberOfPages
> BitsToUnitEnd
) {
415 Bits
= BitsToUnitEnd
;
417 Bits
= NumberOfPages
;
420 if (BitMap
!= NULL
) {
421 Result
|= LShiftU64 (GetBits (Address
, Bits
, BitMap
), Shift
);
425 NumberOfPages
-= Bits
;
426 Address
+= EFI_PAGES_TO_SIZE (Bits
);
433 Get bit value in bitmap table for the given address.
435 @param[in] Address The address to retrieve for.
442 IN EFI_PHYSICAL_ADDRESS Address
447 FindGuardedMemoryMap (Address
, FALSE
, &GuardMap
);
448 if (GuardMap
!= NULL
) {
451 GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
)
462 Check to see if the page at the given address is a Guard page or not.
464 @param[in] Address The address to check for.
466 @return TRUE The page at Address is a Guard page.
467 @return FALSE The page at Address is not a Guard page.
472 IN EFI_PHYSICAL_ADDRESS Address
478 // There must be at least one guarded page before and/or after given
479 // address if it's a Guard page. The bitmap pattern should be one of
482 BitMap
= GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 3);
483 return ((BitMap
== BIT0
) || (BitMap
== BIT2
) || (BitMap
== (BIT2
| BIT0
)));
487 Check to see if the page at the given address is guarded or not.
489 @param[in] Address The address to check for.
491 @return TRUE The page at Address is guarded.
492 @return FALSE The page at Address is not guarded.
497 IN EFI_PHYSICAL_ADDRESS Address
500 return (GetGuardMapBit (Address
) == 1);
504 Set the page at the given address to be a Guard page.
506 This is done by changing the page table attribute to be NOT PRESENT.
508 @param[in] BaseAddress Page address to Guard at.
515 IN EFI_PHYSICAL_ADDRESS BaseAddress
520 if (mSmmMemoryAttribute
!= NULL
) {
522 Status
= mSmmMemoryAttribute
->SetMemoryAttributes (
528 ASSERT_EFI_ERROR (Status
);
534 Unset the Guard page at the given address to the normal memory.
536 This is done by changing the page table attribute to be PRESENT.
538 @param[in] BaseAddress Page address to Guard at.
545 IN EFI_PHYSICAL_ADDRESS BaseAddress
550 if (mSmmMemoryAttribute
!= NULL
) {
552 Status
= mSmmMemoryAttribute
->ClearMemoryAttributes (
558 ASSERT_EFI_ERROR (Status
);
564 Check to see if the memory at the given address should be guarded or not.
566 @param[in] MemoryType Memory type to check.
567 @param[in] AllocateType Allocation type to check.
568 @param[in] PageOrPool Indicate a page allocation or pool allocation.
571 @return TRUE The given type of memory should be guarded.
572 @return FALSE The given type of memory should not be guarded.
575 IsMemoryTypeToGuard (
576 IN EFI_MEMORY_TYPE MemoryType
,
577 IN EFI_ALLOCATE_TYPE AllocateType
,
584 if ( ((PcdGet8 (PcdHeapGuardPropertyMask
) & PageOrPool
) == 0)
586 || (AllocateType
== AllocateAddress
))
592 if ((PageOrPool
& GUARD_HEAP_TYPE_POOL
) != 0) {
593 ConfigBit
|= PcdGet64 (PcdHeapGuardPoolType
);
596 if ((PageOrPool
& GUARD_HEAP_TYPE_PAGE
) != 0) {
597 ConfigBit
|= PcdGet64 (PcdHeapGuardPageType
);
600 if ((MemoryType
== EfiRuntimeServicesData
) ||
601 (MemoryType
== EfiRuntimeServicesCode
))
603 TestBit
= LShiftU64 (1, MemoryType
);
604 } else if (MemoryType
== EfiMaxMemoryType
) {
605 TestBit
= (UINT64
)-1;
610 return ((ConfigBit
& TestBit
) != 0);
614 Check to see if the pool at the given address should be guarded or not.
616 @param[in] MemoryType Pool type to check.
619 @return TRUE The given type of pool should be guarded.
620 @return FALSE The given type of pool should not be guarded.
624 IN EFI_MEMORY_TYPE MemoryType
627 return IsMemoryTypeToGuard (
635 Check to see if the page at the given address should be guarded or not.
637 @param[in] MemoryType Page type to check.
638 @param[in] AllocateType Allocation type to check.
640 @return TRUE The given type of page should be guarded.
641 @return FALSE The given type of page should not be guarded.
645 IN EFI_MEMORY_TYPE MemoryType
,
646 IN EFI_ALLOCATE_TYPE AllocateType
649 return IsMemoryTypeToGuard (MemoryType
, AllocateType
, GUARD_HEAP_TYPE_PAGE
);
653 Check to see if the heap guard is enabled for page and/or pool allocation.
662 return IsMemoryTypeToGuard (
665 GUARD_HEAP_TYPE_POOL
|GUARD_HEAP_TYPE_PAGE
670 Set head Guard and tail Guard for the given memory range.
672 @param[in] Memory Base address of memory to set guard for.
673 @param[in] NumberOfPages Memory size in pages.
679 IN EFI_PHYSICAL_ADDRESS Memory
,
680 IN UINTN NumberOfPages
683 EFI_PHYSICAL_ADDRESS GuardPage
;
688 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
689 if (!IsGuardPage (GuardPage
)) {
690 SetGuardPage (GuardPage
);
694 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
695 if (!IsGuardPage (GuardPage
)) {
696 SetGuardPage (GuardPage
);
700 // Mark the memory range as Guarded
702 SetGuardedMemoryBits (Memory
, NumberOfPages
);
706 Unset head Guard and tail Guard for the given memory range.
708 @param[in] Memory Base address of memory to unset guard for.
709 @param[in] NumberOfPages Memory size in pages.
714 UnsetGuardForMemory (
715 IN EFI_PHYSICAL_ADDRESS Memory
,
716 IN UINTN NumberOfPages
719 EFI_PHYSICAL_ADDRESS GuardPage
;
722 if (NumberOfPages
== 0) {
727 // Head Guard must be one page before, if any.
730 // -------------------
731 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
732 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
733 // 1 X -> Don't free first page (need a new Guard)
734 // (it'll be turned into a Guard page later)
735 // -------------------
738 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
739 GuardBitmap
= GetGuardedMemoryBits (Memory
- EFI_PAGES_TO_SIZE (2), 2);
740 if ((GuardBitmap
& BIT1
) == 0) {
742 // Head Guard exists.
744 if ((GuardBitmap
& BIT0
) == 0) {
746 // If the head Guard is not a tail Guard of adjacent memory block,
749 UnsetGuardPage (GuardPage
);
753 // Pages before memory to free are still in Guard. It's a partial free
754 // case. Turn first page of memory block to free into a new Guard.
756 SetGuardPage (Memory
);
760 // Tail Guard must be the page after this memory block to free, if any.
763 // --------------------
764 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
765 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
766 // X 1 -> Don't free last page (need a new Guard)
767 // (it'll be turned into a Guard page later)
768 // --------------------
771 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
772 GuardBitmap
= GetGuardedMemoryBits (GuardPage
, 2);
773 if ((GuardBitmap
& BIT0
) == 0) {
775 // Tail Guard exists.
777 if ((GuardBitmap
& BIT1
) == 0) {
779 // If the tail Guard is not a head Guard of adjacent memory block,
780 // free it; otherwise, keep it.
782 UnsetGuardPage (GuardPage
);
786 // Pages after memory to free are still in Guard. It's a partial free
787 // case. We need to keep one page to be a head Guard.
789 SetGuardPage (GuardPage
- EFI_PAGES_TO_SIZE (1));
793 // No matter what, we just clear the mark of the Guarded memory.
795 ClearGuardedMemoryBits (Memory
, NumberOfPages
);
799 Adjust the start address and number of pages to free according to Guard.
801 The purpose of this function is to keep the shared Guard page with adjacent
802 memory block if it's still in guard, or free it if no more sharing. Another
803 is to reserve pages as Guard pages in partial page free situation.
805 @param[in,out] Memory Base address of memory to free.
806 @param[in,out] NumberOfPages Size of memory to free.
812 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
813 IN OUT UINTN
*NumberOfPages
816 EFI_PHYSICAL_ADDRESS Start
;
817 EFI_PHYSICAL_ADDRESS MemoryToTest
;
822 if ((Memory
== NULL
) || (NumberOfPages
== NULL
) || (*NumberOfPages
== 0)) {
827 PagesToFree
= *NumberOfPages
;
830 // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).
832 if (mSmmMemoryAttribute
!= NULL
) {
834 mSmmMemoryAttribute
->GetMemoryAttributes (
837 EFI_PAGES_TO_SIZE (PagesToFree
),
840 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
841 mSmmMemoryAttribute
->ClearMemoryAttributes (
844 EFI_PAGES_TO_SIZE (PagesToFree
),
851 // Head Guard must be one page before, if any.
854 // -------------------
855 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
856 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
857 // 1 X -> Don't free first page (need a new Guard)
858 // (it'll be turned into a Guard page later)
859 // -------------------
862 MemoryToTest
= Start
- EFI_PAGES_TO_SIZE (2);
863 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
864 if ((GuardBitmap
& BIT1
) == 0) {
866 // Head Guard exists.
868 if ((GuardBitmap
& BIT0
) == 0) {
870 // If the head Guard is not a tail Guard of adjacent memory block,
871 // free it; otherwise, keep it.
873 Start
-= EFI_PAGES_TO_SIZE (1);
878 // No Head Guard, and pages before memory to free are still in Guard. It's a
879 // partial free case. We need to keep one page to be a tail Guard.
881 Start
+= EFI_PAGES_TO_SIZE (1);
886 // Tail Guard must be the page after this memory block to free, if any.
889 // --------------------
890 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
891 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
892 // X 1 -> Don't free last page (need a new Guard)
893 // (it'll be turned into a Guard page later)
894 // --------------------
897 MemoryToTest
= Start
+ EFI_PAGES_TO_SIZE (PagesToFree
);
898 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
899 if ((GuardBitmap
& BIT0
) == 0) {
901 // Tail Guard exists.
903 if ((GuardBitmap
& BIT1
) == 0) {
905 // If the tail Guard is not a head Guard of adjacent memory block,
906 // free it; otherwise, keep it.
910 } else if (PagesToFree
> 0) {
912 // No Tail Guard, and pages after memory to free are still in Guard. It's a
913 // partial free case. We need to keep one page to be a head Guard.
919 *NumberOfPages
= PagesToFree
;
923 Adjust the pool head position to make sure the Guard page is adjavent to
924 pool tail or pool head.
926 @param[in] Memory Base address of memory allocated.
927 @param[in] NoPages Number of pages actually allocated.
928 @param[in] Size Size of memory requested.
929 (plus pool head/tail overhead)
931 @return Address of pool head
935 IN EFI_PHYSICAL_ADDRESS Memory
,
940 if ((Memory
== 0) || ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0)) {
942 // Pool head is put near the head Guard
944 return (VOID
*)(UINTN
)Memory
;
948 // Pool head is put near the tail Guard
950 Size
= ALIGN_VALUE (Size
, 8);
951 return (VOID
*)(UINTN
)(Memory
+ EFI_PAGES_TO_SIZE (NoPages
) - Size
);
955 Get the page base address according to pool head address.
957 @param[in] Memory Head address of pool to free.
959 @return Address of pool head.
963 IN EFI_PHYSICAL_ADDRESS Memory
966 if ((Memory
== 0) || ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0)) {
968 // Pool head is put near the head Guard
970 return (VOID
*)(UINTN
)Memory
;
974 // Pool head is put near the tail Guard
976 return (VOID
*)(UINTN
)(Memory
& ~EFI_PAGE_MASK
);
980 Helper function of memory allocation with Guard pages.
982 @param FreePageList The free page node.
983 @param NumberOfPages Number of pages to be allocated.
984 @param MaxAddress Request to allocate memory below this address.
985 @param MemoryType Type of memory requested.
987 @return Memory address of allocated pages.
990 InternalAllocMaxAddressWithGuard (
991 IN OUT LIST_ENTRY
*FreePageList
,
992 IN UINTN NumberOfPages
,
994 IN EFI_MEMORY_TYPE MemoryType
999 FREE_PAGE_LIST
*Pages
;
1005 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
;
1006 Node
= Node
->BackLink
)
1008 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
1009 if ((Pages
->NumberOfPages
>= NumberOfPages
) &&
1010 ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
))
1013 // We may need 1 or 2 more pages for Guard. Check it out.
1015 PagesToAlloc
= NumberOfPages
;
1016 TailGuard
= (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
);
1017 if (!IsGuardPage (TailGuard
)) {
1019 // Add one if no Guard at the end of current free memory block.
1025 HeadGuard
= (UINTN
)Pages
+
1026 EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
- PagesToAlloc
) -
1028 if (!IsGuardPage (HeadGuard
)) {
1030 // Add one if no Guard at the page before the address to allocate
1036 if (Pages
->NumberOfPages
< PagesToAlloc
) {
1037 // Not enough space to allocate memory with Guards? Try next block.
1041 Address
= InternalAllocPagesOnOneNode (Pages
, PagesToAlloc
, MaxAddress
);
1042 ConvertSmmMemoryMapEntry (MemoryType
, Address
, PagesToAlloc
, FALSE
);
1043 CoreFreeMemoryMapStack ();
1044 if (HeadGuard
== 0) {
1045 // Don't pass the Guard page to user.
1046 Address
+= EFI_PAGE_SIZE
;
1049 SetGuardForMemory (Address
, NumberOfPages
);
1058 Helper function of memory free with Guard pages.
1060 @param[in] Memory Base address of memory being freed.
1061 @param[in] NumberOfPages The number of pages to free.
1062 @param[in] AddRegion If this memory is new added region.
1064 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
1065 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
1066 @return EFI_SUCCESS Pages successfully freed.
1069 SmmInternalFreePagesExWithGuard (
1070 IN EFI_PHYSICAL_ADDRESS Memory
,
1071 IN UINTN NumberOfPages
,
1072 IN BOOLEAN AddRegion
1075 EFI_PHYSICAL_ADDRESS MemoryToFree
;
1078 if (((Memory
& EFI_PAGE_MASK
) != 0) || (Memory
== 0) || (NumberOfPages
== 0)) {
1079 return EFI_INVALID_PARAMETER
;
1082 MemoryToFree
= Memory
;
1083 PagesToFree
= NumberOfPages
;
1085 AdjustMemoryF (&MemoryToFree
, &PagesToFree
);
1086 UnsetGuardForMemory (Memory
, NumberOfPages
);
1087 if (PagesToFree
== 0) {
1091 return SmmInternalFreePagesEx (MemoryToFree
, PagesToFree
, AddRegion
);
1095 Set all Guard pages which cannot be set during the non-SMM mode time.
1102 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1103 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1104 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1105 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1106 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1114 if ((mGuardedMemoryMap
== 0) ||
1116 (mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
))
1121 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1122 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1124 SetMem (Tables
, sizeof (Tables
), 0);
1125 SetMem (Addresses
, sizeof (Addresses
), 0);
1126 SetMem (Indices
, sizeof (Indices
), 0);
1128 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1129 Tables
[Level
] = mGuardedMemoryMap
;
1134 DumpGuardedMemoryBitmap ();
1138 if (Indices
[Level
] > Entries
[Level
]) {
1142 TableEntry
= ((UINT64
*)(UINTN
)(Tables
[Level
]))[Indices
[Level
]];
1143 Address
= Addresses
[Level
];
1145 if (TableEntry
== 0) {
1147 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1149 Tables
[Level
] = TableEntry
;
1150 Addresses
[Level
] = Address
;
1156 while (Index
< GUARDED_HEAP_MAP_ENTRY_BITS
) {
1157 if ((TableEntry
& 1) == 1) {
1161 GuardPage
= Address
- EFI_PAGE_SIZE
;
1167 GuardPage
= Address
;
1175 if (GuardPage
!= 0) {
1176 SetGuardPage (GuardPage
);
1179 if (TableEntry
== 0) {
1183 TableEntry
= RShiftU64 (TableEntry
, 1);
1184 Address
+= EFI_PAGE_SIZE
;
1190 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1194 Indices
[Level
] += 1;
1195 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1196 Addresses
[Level
] = Address
| LShiftU64 (Indices
[Level
], Shifts
[Level
]);
1201 Hook function used to set all Guard pages after entering SMM mode.
1204 SmmEntryPointMemoryManagementHook (
1210 if (mSmmMemoryAttribute
== NULL
) {
1211 Status
= SmmLocateProtocol (
1212 &gEdkiiSmmMemoryAttributeProtocolGuid
,
1214 (VOID
**)&mSmmMemoryAttribute
1216 if (!EFI_ERROR (Status
)) {
1217 SetAllGuardPages ();
1223 Helper function to convert a UINT64 value in binary to a string.
1225 @param[in] Value Value of a UINT64 integer.
1226 @param[out] BinString String buffer to contain the conversion result.
1233 OUT CHAR8
*BinString
1238 if (BinString
== NULL
) {
1242 for (Index
= 64; Index
> 0; --Index
) {
1243 BinString
[Index
- 1] = '0' + (Value
& 1);
1244 Value
= RShiftU64 (Value
, 1);
1247 BinString
[64] = '\0';
1251 Dump the guarded memory bit map.
1255 DumpGuardedMemoryBitmap (
1259 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1260 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1261 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1262 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1263 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1268 CHAR8 String
[GUARDED_HEAP_MAP_ENTRY_BITS
+ 1];
1272 if ((mGuardedMemoryMap
== 0) ||
1274 (mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
))
1279 Ruler1
= " 3 2 1 0";
1280 Ruler2
= "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1283 HEAP_GUARD_DEBUG_LEVEL
,
1284 "============================="
1285 " Guarded Memory Bitmap "
1286 "==============================\r\n"
1288 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler1
));
1289 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler2
));
1291 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1292 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1294 SetMem (Indices
, sizeof (Indices
), 0);
1295 SetMem (Tables
, sizeof (Tables
), 0);
1296 SetMem (Addresses
, sizeof (Addresses
), 0);
1298 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1299 Tables
[Level
] = mGuardedMemoryMap
;
1304 if (Indices
[Level
] > Entries
[Level
]) {
1310 HEAP_GUARD_DEBUG_LEVEL
,
1311 "========================================="
1312 "=========================================\r\n"
1315 TableEntry
= ((UINT64
*)(UINTN
)Tables
[Level
])[Indices
[Level
]];
1316 Address
= Addresses
[Level
];
1318 if (TableEntry
== 0) {
1319 if (Level
== GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1320 if (RepeatZero
== 0) {
1321 Uint64ToBinString (TableEntry
, String
);
1322 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1323 } else if (RepeatZero
== 1) {
1324 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "... : ...\r\n"));
1329 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1331 Tables
[Level
] = TableEntry
;
1332 Addresses
[Level
] = Address
;
1339 Uint64ToBinString (TableEntry
, String
);
1340 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1344 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1348 Indices
[Level
] += 1;
1349 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1350 Addresses
[Level
] = Address
| LShiftU64 (Indices
[Level
], Shifts
[Level
]);
1355 Debug function used to verify if the Guard page is well set or not.
1357 @param[in] BaseAddress Address of memory to check.
1358 @param[in] NumberOfPages Size of memory in pages.
1360 @return TRUE The head Guard and tail Guard are both well set.
1361 @return FALSE The head Guard and/or tail Guard are not well set.
1365 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1366 IN UINTN NumberOfPages
1371 EFI_PHYSICAL_ADDRESS Address
;
1373 if (mSmmMemoryAttribute
== NULL
) {
1378 Address
= BaseAddress
- EFI_PAGE_SIZE
;
1379 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1380 mSmmMemoryAttribute
,
1385 if (EFI_ERROR (Status
) || ((Attribute
& EFI_MEMORY_RP
) == 0)) {
1388 "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
1392 DumpGuardedMemoryBitmap ();
1397 Address
= BaseAddress
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
1398 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1399 mSmmMemoryAttribute
,
1404 if (EFI_ERROR (Status
) || ((Attribute
& EFI_MEMORY_RP
) == 0)) {
1407 "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
1411 DumpGuardedMemoryBitmap ();