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
);
87 SetMem64 ((VOID
*)BitMap
, Qwords
* GUARDED_HEAP_MAP_ENTRY_BYTES
,
93 *BitMap
|= (LShiftU64 (1, Lsbs
) - 1);
98 Set corresponding bits in bitmap table to 0 according to the address.
100 @param[in] Address Start address to set for.
101 @param[in] BitNumber Number of bits to set.
102 @param[in] BitMap Pointer to bitmap which covers the Address.
109 IN EFI_PHYSICAL_ADDRESS Address
,
120 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
121 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
123 if ((StartBit
+ BitNumber
) >= GUARDED_HEAP_MAP_ENTRY_BITS
) {
124 Msbs
= (GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
) %
125 GUARDED_HEAP_MAP_ENTRY_BITS
;
126 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
127 Qwords
= (BitNumber
- Msbs
) / GUARDED_HEAP_MAP_ENTRY_BITS
;
135 *BitMap
&= ~LShiftU64 (LShiftU64 (1, Msbs
) - 1, StartBit
);
140 SetMem64 ((VOID
*)BitMap
, Qwords
* GUARDED_HEAP_MAP_ENTRY_BYTES
, 0);
145 *BitMap
&= ~(LShiftU64 (1, Lsbs
) - 1);
150 Get corresponding bits in bitmap table according to the address.
152 The value of bit 0 corresponds to the status of memory at given Address.
153 No more than 64 bits can be retrieved in one call.
155 @param[in] Address Start address to retrieve bits for.
156 @param[in] BitNumber Number of bits to get.
157 @param[in] BitMap Pointer to bitmap which covers the Address.
159 @return An integer containing the bits information.
164 IN EFI_PHYSICAL_ADDRESS Address
,
175 ASSERT (BitNumber
<= GUARDED_HEAP_MAP_ENTRY_BITS
);
177 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
178 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
180 if ((StartBit
+ BitNumber
) > GUARDED_HEAP_MAP_ENTRY_BITS
) {
181 Msbs
= GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
;
182 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
188 if (StartBit
== 0 && BitNumber
== GUARDED_HEAP_MAP_ENTRY_BITS
) {
191 Result
= RShiftU64((*BitMap
), StartBit
) & (LShiftU64(1, Msbs
) - 1);
194 Result
|= LShiftU64 ((*BitMap
) & (LShiftU64 (1, Lsbs
) - 1), Msbs
);
202 Helper function to allocate pages without Guard for internal uses.
204 @param[in] Pages Page number.
206 @return Address of memory allocated.
214 EFI_PHYSICAL_ADDRESS Memory
;
216 Status
= SmmInternalAllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
,
217 Pages
, &Memory
, FALSE
);
218 if (EFI_ERROR (Status
)) {
222 return (VOID
*)(UINTN
)Memory
;
226 Locate the pointer of bitmap from the guarded memory bitmap tables, which
227 covers the given Address.
229 @param[in] Address Start address to search the bitmap for.
230 @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
231 @param[out] BitMap Pointer to bitmap which covers the Address.
233 @return The bit number from given Address to the end of current map table.
236 FindGuardedMemoryMap (
237 IN EFI_PHYSICAL_ADDRESS Address
,
238 IN BOOLEAN AllocMapUnit
,
250 // Adjust current map table depth according to the address to access
252 while (AllocMapUnit
&&
253 mMapLevel
< GUARDED_HEAP_MAP_TABLE_DEPTH
&&
256 mLevelShift
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1]
259 if (mGuardedMemoryMap
!= 0) {
260 Size
= (mLevelMask
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1] + 1)
261 * GUARDED_HEAP_MAP_ENTRY_BYTES
;
262 MapMemory
= (UINT64
)(UINTN
)PageAlloc (EFI_SIZE_TO_PAGES (Size
));
263 ASSERT (MapMemory
!= 0);
265 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
267 *(UINT64
*)(UINTN
)MapMemory
= mGuardedMemoryMap
;
268 mGuardedMemoryMap
= MapMemory
;
275 GuardMap
= &mGuardedMemoryMap
;
276 for (Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
277 Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
;
280 if (*GuardMap
== 0) {
286 Size
= (mLevelMask
[Level
] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES
;
287 MapMemory
= (UINT64
)(UINTN
)PageAlloc (EFI_SIZE_TO_PAGES (Size
));
288 ASSERT (MapMemory
!= 0);
290 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
291 *GuardMap
= MapMemory
;
294 Index
= (UINTN
)RShiftU64 (Address
, mLevelShift
[Level
]);
295 Index
&= mLevelMask
[Level
];
296 GuardMap
= (UINT64
*)(UINTN
)((*GuardMap
) + Index
* sizeof (UINT64
));
300 BitsToUnitEnd
= GUARDED_HEAP_MAP_BITS
- GUARDED_HEAP_MAP_BIT_INDEX (Address
);
303 return BitsToUnitEnd
;
307 Set corresponding bits in bitmap table to 1 according to given memory range.
309 @param[in] Address Memory address to guard from.
310 @param[in] NumberOfPages Number of pages to guard.
316 SetGuardedMemoryBits (
317 IN EFI_PHYSICAL_ADDRESS Address
,
318 IN UINTN NumberOfPages
325 while (NumberOfPages
> 0) {
326 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, TRUE
, &BitMap
);
327 ASSERT (BitMap
!= NULL
);
329 if (NumberOfPages
> BitsToUnitEnd
) {
331 Bits
= BitsToUnitEnd
;
333 Bits
= NumberOfPages
;
336 SetBits (Address
, Bits
, BitMap
);
338 NumberOfPages
-= Bits
;
339 Address
+= EFI_PAGES_TO_SIZE (Bits
);
344 Clear corresponding bits in bitmap table according to given memory range.
346 @param[in] Address Memory address to unset from.
347 @param[in] NumberOfPages Number of pages to unset guard.
353 ClearGuardedMemoryBits (
354 IN EFI_PHYSICAL_ADDRESS Address
,
355 IN UINTN NumberOfPages
362 while (NumberOfPages
> 0) {
363 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, TRUE
, &BitMap
);
364 ASSERT (BitMap
!= NULL
);
366 if (NumberOfPages
> BitsToUnitEnd
) {
368 Bits
= BitsToUnitEnd
;
370 Bits
= NumberOfPages
;
373 ClearBits (Address
, Bits
, BitMap
);
375 NumberOfPages
-= Bits
;
376 Address
+= EFI_PAGES_TO_SIZE (Bits
);
381 Retrieve corresponding bits in bitmap table according to given memory range.
383 @param[in] Address Memory address to retrieve from.
384 @param[in] NumberOfPages Number of pages to retrieve.
386 @return An integer containing the guarded memory bitmap.
389 GetGuardedMemoryBits (
390 IN EFI_PHYSICAL_ADDRESS Address
,
391 IN UINTN NumberOfPages
400 ASSERT (NumberOfPages
<= GUARDED_HEAP_MAP_ENTRY_BITS
);
404 while (NumberOfPages
> 0) {
405 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, FALSE
, &BitMap
);
407 if (NumberOfPages
> BitsToUnitEnd
) {
409 Bits
= BitsToUnitEnd
;
411 Bits
= NumberOfPages
;
414 if (BitMap
!= NULL
) {
415 Result
|= LShiftU64 (GetBits (Address
, Bits
, BitMap
), Shift
);
419 NumberOfPages
-= Bits
;
420 Address
+= EFI_PAGES_TO_SIZE (Bits
);
427 Get bit value in bitmap table for the given address.
429 @param[in] Address The address to retrieve for.
436 IN EFI_PHYSICAL_ADDRESS Address
441 FindGuardedMemoryMap (Address
, FALSE
, &GuardMap
);
442 if (GuardMap
!= NULL
) {
443 if (RShiftU64 (*GuardMap
,
444 GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
)) & 1) {
454 Check to see if the page at the given address is a Guard page or not.
456 @param[in] Address The address to check for.
458 @return TRUE The page at Address is a Guard page.
459 @return FALSE The page at Address is not a Guard page.
464 IN EFI_PHYSICAL_ADDRESS Address
470 // There must be at least one guarded page before and/or after given
471 // address if it's a Guard page. The bitmap pattern should be one of
474 BitMap
= GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 3);
475 return ((BitMap
== BIT0
) || (BitMap
== BIT2
) || (BitMap
== (BIT2
| BIT0
)));
481 Check to see if the page at the given address is guarded or not.
483 @param[in] Address The address to check for.
485 @return TRUE The page at Address is guarded.
486 @return FALSE The page at Address is not guarded.
491 IN EFI_PHYSICAL_ADDRESS Address
494 return (GetGuardMapBit (Address
) == 1);
498 Set the page at the given address to be a Guard page.
500 This is done by changing the page table attribute to be NOT PRSENT.
502 @param[in] BaseAddress Page address to Guard at.
509 IN EFI_PHYSICAL_ADDRESS BaseAddress
514 if (mSmmMemoryAttribute
!= NULL
) {
516 Status
= mSmmMemoryAttribute
->SetMemoryAttributes (
522 ASSERT_EFI_ERROR (Status
);
528 Unset the Guard page at the given address to the normal memory.
530 This is done by changing the page table attribute to be PRSENT.
532 @param[in] BaseAddress Page address to Guard at.
539 IN EFI_PHYSICAL_ADDRESS BaseAddress
544 if (mSmmMemoryAttribute
!= NULL
) {
546 Status
= mSmmMemoryAttribute
->ClearMemoryAttributes (
552 ASSERT_EFI_ERROR (Status
);
558 Check to see if the memory at the given address should be guarded or not.
560 @param[in] MemoryType Memory type to check.
561 @param[in] AllocateType Allocation type to check.
562 @param[in] PageOrPool Indicate a page allocation or pool allocation.
565 @return TRUE The given type of memory should be guarded.
566 @return FALSE The given type of memory should not be guarded.
569 IsMemoryTypeToGuard (
570 IN EFI_MEMORY_TYPE MemoryType
,
571 IN EFI_ALLOCATE_TYPE AllocateType
,
578 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & PageOrPool
) == 0
580 || AllocateType
== AllocateAddress
) {
585 if ((PageOrPool
& GUARD_HEAP_TYPE_POOL
) != 0) {
586 ConfigBit
|= PcdGet64 (PcdHeapGuardPoolType
);
589 if ((PageOrPool
& GUARD_HEAP_TYPE_PAGE
) != 0) {
590 ConfigBit
|= PcdGet64 (PcdHeapGuardPageType
);
593 if (MemoryType
== EfiRuntimeServicesData
||
594 MemoryType
== EfiRuntimeServicesCode
) {
595 TestBit
= LShiftU64 (1, MemoryType
);
596 } else if (MemoryType
== EfiMaxMemoryType
) {
597 TestBit
= (UINT64
)-1;
602 return ((ConfigBit
& TestBit
) != 0);
606 Check to see if the pool at the given address should be guarded or not.
608 @param[in] MemoryType Pool type to check.
611 @return TRUE The given type of pool should be guarded.
612 @return FALSE The given type of pool should not be guarded.
616 IN EFI_MEMORY_TYPE MemoryType
619 return IsMemoryTypeToGuard (MemoryType
, AllocateAnyPages
,
620 GUARD_HEAP_TYPE_POOL
);
624 Check to see if the page at the given address should be guarded or not.
626 @param[in] MemoryType Page type to check.
627 @param[in] AllocateType Allocation type to check.
629 @return TRUE The given type of page should be guarded.
630 @return FALSE The given type of page should not be guarded.
634 IN EFI_MEMORY_TYPE MemoryType
,
635 IN EFI_ALLOCATE_TYPE AllocateType
638 return IsMemoryTypeToGuard (MemoryType
, AllocateType
, GUARD_HEAP_TYPE_PAGE
);
642 Check to see if the heap guard is enabled for page and/or pool allocation.
651 return IsMemoryTypeToGuard (EfiMaxMemoryType
, AllocateAnyPages
,
652 GUARD_HEAP_TYPE_POOL
|GUARD_HEAP_TYPE_PAGE
);
656 Set head Guard and tail Guard for the given memory range.
658 @param[in] Memory Base address of memory to set guard for.
659 @param[in] NumberOfPages Memory size in pages.
665 IN EFI_PHYSICAL_ADDRESS Memory
,
666 IN UINTN NumberOfPages
669 EFI_PHYSICAL_ADDRESS GuardPage
;
674 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
675 if (!IsGuardPage (GuardPage
)) {
676 SetGuardPage (GuardPage
);
680 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
681 if (!IsGuardPage (GuardPage
)) {
682 SetGuardPage (GuardPage
);
686 // Mark the memory range as Guarded
688 SetGuardedMemoryBits (Memory
, NumberOfPages
);
692 Unset head Guard and tail Guard for the given memory range.
694 @param[in] Memory Base address of memory to unset guard for.
695 @param[in] NumberOfPages Memory size in pages.
700 UnsetGuardForMemory (
701 IN EFI_PHYSICAL_ADDRESS Memory
,
702 IN UINTN NumberOfPages
705 EFI_PHYSICAL_ADDRESS GuardPage
;
708 if (NumberOfPages
== 0) {
713 // Head Guard must be one page before, if any.
716 // -------------------
717 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
718 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
719 // 1 X -> Don't free first page (need a new Guard)
720 // (it'll be turned into a Guard page later)
721 // -------------------
724 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
725 GuardBitmap
= GetGuardedMemoryBits (Memory
- EFI_PAGES_TO_SIZE (2), 2);
726 if ((GuardBitmap
& BIT1
) == 0) {
728 // Head Guard exists.
730 if ((GuardBitmap
& BIT0
) == 0) {
732 // If the head Guard is not a tail Guard of adjacent memory block,
735 UnsetGuardPage (GuardPage
);
739 // Pages before memory to free are still in Guard. It's a partial free
740 // case. Turn first page of memory block to free into a new Guard.
742 SetGuardPage (Memory
);
746 // Tail Guard must be the page after this memory block to free, if any.
749 // --------------------
750 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
751 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
752 // X 1 -> Don't free last page (need a new Guard)
753 // (it'll be turned into a Guard page later)
754 // --------------------
757 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
758 GuardBitmap
= GetGuardedMemoryBits (GuardPage
, 2);
759 if ((GuardBitmap
& BIT0
) == 0) {
761 // Tail Guard exists.
763 if ((GuardBitmap
& BIT1
) == 0) {
765 // If the tail Guard is not a head Guard of adjacent memory block,
766 // free it; otherwise, keep it.
768 UnsetGuardPage (GuardPage
);
772 // Pages after memory to free are still in Guard. It's a partial free
773 // case. We need to keep one page to be a head Guard.
775 SetGuardPage (GuardPage
- EFI_PAGES_TO_SIZE (1));
779 // No matter what, we just clear the mark of the Guarded memory.
781 ClearGuardedMemoryBits(Memory
, NumberOfPages
);
787 Adjust the start address and number of pages to free according to Guard.
789 The purpose of this function is to keep the shared Guard page with adjacent
790 memory block if it's still in guard, or free it if no more sharing. Another
791 is to reserve pages as Guard pages in partial page free situation.
793 @param[in,out] Memory Base address of memory to free.
794 @param[in,out] NumberOfPages Size of memory to free.
800 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
801 IN OUT UINTN
*NumberOfPages
804 EFI_PHYSICAL_ADDRESS Start
;
805 EFI_PHYSICAL_ADDRESS MemoryToTest
;
810 if (Memory
== NULL
|| NumberOfPages
== NULL
|| *NumberOfPages
== 0) {
815 PagesToFree
= *NumberOfPages
;
818 // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).
820 if (mSmmMemoryAttribute
!= NULL
) {
822 mSmmMemoryAttribute
->GetMemoryAttributes (
825 EFI_PAGES_TO_SIZE (PagesToFree
),
828 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
829 mSmmMemoryAttribute
->ClearMemoryAttributes (
832 EFI_PAGES_TO_SIZE (PagesToFree
),
839 // Head Guard must be one page before, if any.
842 // -------------------
843 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
844 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
845 // 1 X -> Don't free first page (need a new Guard)
846 // (it'll be turned into a Guard page later)
847 // -------------------
850 MemoryToTest
= Start
- EFI_PAGES_TO_SIZE (2);
851 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
852 if ((GuardBitmap
& BIT1
) == 0) {
854 // Head Guard exists.
856 if ((GuardBitmap
& BIT0
) == 0) {
858 // If the head Guard is not a tail Guard of adjacent memory block,
859 // free it; otherwise, keep it.
861 Start
-= EFI_PAGES_TO_SIZE (1);
866 // No Head Guard, and pages before memory to free are still in Guard. It's a
867 // partial free case. We need to keep one page to be a tail Guard.
869 Start
+= EFI_PAGES_TO_SIZE (1);
874 // Tail Guard must be the page after this memory block to free, if any.
877 // --------------------
878 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
879 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
880 // X 1 -> Don't free last page (need a new Guard)
881 // (it'll be turned into a Guard page later)
882 // --------------------
885 MemoryToTest
= Start
+ EFI_PAGES_TO_SIZE (PagesToFree
);
886 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
887 if ((GuardBitmap
& BIT0
) == 0) {
889 // Tail Guard exists.
891 if ((GuardBitmap
& BIT1
) == 0) {
893 // If the tail Guard is not a head Guard of adjacent memory block,
894 // free it; otherwise, keep it.
898 } else if (PagesToFree
> 0) {
900 // No Tail Guard, and pages after memory to free are still in Guard. It's a
901 // partial free case. We need to keep one page to be a head Guard.
907 *NumberOfPages
= PagesToFree
;
912 Adjust the pool head position to make sure the Guard page is adjavent to
913 pool tail or pool head.
915 @param[in] Memory Base address of memory allocated.
916 @param[in] NoPages Number of pages actually allocated.
917 @param[in] Size Size of memory requested.
918 (plus pool head/tail overhead)
920 @return Address of pool head
924 IN EFI_PHYSICAL_ADDRESS Memory
,
929 if (Memory
== 0 || (PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
931 // Pool head is put near the head Guard
933 return (VOID
*)(UINTN
)Memory
;
937 // Pool head is put near the tail Guard
939 Size
= ALIGN_VALUE (Size
, 8);
940 return (VOID
*)(UINTN
)(Memory
+ EFI_PAGES_TO_SIZE (NoPages
) - Size
);
944 Get the page base address according to pool head address.
946 @param[in] Memory Head address of pool to free.
948 @return Address of pool head.
952 IN EFI_PHYSICAL_ADDRESS Memory
955 if (Memory
== 0 || (PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
957 // Pool head is put near the head Guard
959 return (VOID
*)(UINTN
)Memory
;
963 // Pool head is put near the tail Guard
965 return (VOID
*)(UINTN
)(Memory
& ~EFI_PAGE_MASK
);
969 Helper function of memory allocation with Guard pages.
971 @param FreePageList The free page node.
972 @param NumberOfPages Number of pages to be allocated.
973 @param MaxAddress Request to allocate memory below this address.
974 @param MemoryType Type of memory requested.
976 @return Memory address of allocated pages.
979 InternalAllocMaxAddressWithGuard (
980 IN OUT LIST_ENTRY
*FreePageList
,
981 IN UINTN NumberOfPages
,
983 IN EFI_MEMORY_TYPE MemoryType
988 FREE_PAGE_LIST
*Pages
;
994 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
;
995 Node
= Node
->BackLink
) {
996 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
997 if (Pages
->NumberOfPages
>= NumberOfPages
&&
998 (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
) {
1001 // We may need 1 or 2 more pages for Guard. Check it out.
1003 PagesToAlloc
= NumberOfPages
;
1004 TailGuard
= (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
);
1005 if (!IsGuardPage (TailGuard
)) {
1007 // Add one if no Guard at the end of current free memory block.
1013 HeadGuard
= (UINTN
)Pages
+
1014 EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
- PagesToAlloc
) -
1016 if (!IsGuardPage (HeadGuard
)) {
1018 // Add one if no Guard at the page before the address to allocate
1024 if (Pages
->NumberOfPages
< PagesToAlloc
) {
1025 // Not enough space to allocate memory with Guards? Try next block.
1029 Address
= InternalAllocPagesOnOneNode (Pages
, PagesToAlloc
, MaxAddress
);
1030 ConvertSmmMemoryMapEntry(MemoryType
, Address
, PagesToAlloc
, FALSE
);
1031 CoreFreeMemoryMapStack();
1032 if (HeadGuard
== 0) {
1033 // Don't pass the Guard page to user.
1034 Address
+= EFI_PAGE_SIZE
;
1036 SetGuardForMemory (Address
, NumberOfPages
);
1045 Helper function of memory free with Guard pages.
1047 @param[in] Memory Base address of memory being freed.
1048 @param[in] NumberOfPages The number of pages to free.
1049 @param[in] AddRegion If this memory is new added region.
1051 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
1052 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
1053 @return EFI_SUCCESS Pages successfully freed.
1056 SmmInternalFreePagesExWithGuard (
1057 IN EFI_PHYSICAL_ADDRESS Memory
,
1058 IN UINTN NumberOfPages
,
1059 IN BOOLEAN AddRegion
1062 EFI_PHYSICAL_ADDRESS MemoryToFree
;
1065 if (((Memory
& EFI_PAGE_MASK
) != 0) || (Memory
== 0) || (NumberOfPages
== 0)) {
1066 return EFI_INVALID_PARAMETER
;
1069 MemoryToFree
= Memory
;
1070 PagesToFree
= NumberOfPages
;
1072 AdjustMemoryF (&MemoryToFree
, &PagesToFree
);
1073 UnsetGuardForMemory (Memory
, NumberOfPages
);
1074 if (PagesToFree
== 0) {
1078 return SmmInternalFreePagesEx (MemoryToFree
, PagesToFree
, AddRegion
);
1082 Set all Guard pages which cannot be set during the non-SMM mode time.
1089 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1090 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1091 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1092 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1093 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1101 if (mGuardedMemoryMap
== 0 ||
1103 mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
) {
1107 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1108 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1110 SetMem (Tables
, sizeof(Tables
), 0);
1111 SetMem (Addresses
, sizeof(Addresses
), 0);
1112 SetMem (Indices
, sizeof(Indices
), 0);
1114 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1115 Tables
[Level
] = mGuardedMemoryMap
;
1120 DumpGuardedMemoryBitmap ();
1124 if (Indices
[Level
] > Entries
[Level
]) {
1129 TableEntry
= ((UINT64
*)(UINTN
)(Tables
[Level
]))[Indices
[Level
]];
1130 Address
= Addresses
[Level
];
1132 if (TableEntry
== 0) {
1136 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1139 Tables
[Level
] = TableEntry
;
1140 Addresses
[Level
] = Address
;
1148 while (Index
< GUARDED_HEAP_MAP_ENTRY_BITS
) {
1149 if ((TableEntry
& 1) == 1) {
1153 GuardPage
= Address
- EFI_PAGE_SIZE
;
1158 GuardPage
= Address
;
1165 if (GuardPage
!= 0) {
1166 SetGuardPage (GuardPage
);
1169 if (TableEntry
== 0) {
1173 TableEntry
= RShiftU64 (TableEntry
, 1);
1174 Address
+= EFI_PAGE_SIZE
;
1180 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1184 Indices
[Level
] += 1;
1185 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1186 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);
1192 Hook function used to set all Guard pages after entering SMM mode.
1195 SmmEntryPointMemoryManagementHook (
1201 if (mSmmMemoryAttribute
== NULL
) {
1202 Status
= SmmLocateProtocol (
1203 &gEdkiiSmmMemoryAttributeProtocolGuid
,
1205 (VOID
**)&mSmmMemoryAttribute
1207 if (!EFI_ERROR(Status
)) {
1208 SetAllGuardPages ();
1214 Helper function to convert a UINT64 value in binary to a string.
1216 @param[in] Value Value of a UINT64 integer.
1217 @param[out] BinString String buffer to contain the conversion result.
1224 OUT CHAR8
*BinString
1229 if (BinString
== NULL
) {
1233 for (Index
= 64; Index
> 0; --Index
) {
1234 BinString
[Index
- 1] = '0' + (Value
& 1);
1235 Value
= RShiftU64 (Value
, 1);
1237 BinString
[64] = '\0';
1241 Dump the guarded memory bit map.
1245 DumpGuardedMemoryBitmap (
1249 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1250 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1251 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1252 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1253 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1258 CHAR8 String
[GUARDED_HEAP_MAP_ENTRY_BITS
+ 1];
1262 if (mGuardedMemoryMap
== 0 ||
1264 mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
) {
1268 Ruler1
= " 3 2 1 0";
1269 Ruler2
= "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1271 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "============================="
1272 " Guarded Memory Bitmap "
1273 "==============================\r\n"));
1274 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler1
));
1275 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler2
));
1277 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1278 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1280 SetMem (Indices
, sizeof(Indices
), 0);
1281 SetMem (Tables
, sizeof(Tables
), 0);
1282 SetMem (Addresses
, sizeof(Addresses
), 0);
1284 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1285 Tables
[Level
] = mGuardedMemoryMap
;
1290 if (Indices
[Level
] > Entries
[Level
]) {
1297 HEAP_GUARD_DEBUG_LEVEL
,
1298 "========================================="
1299 "=========================================\r\n"
1304 TableEntry
= ((UINT64
*)(UINTN
)Tables
[Level
])[Indices
[Level
]];
1305 Address
= Addresses
[Level
];
1307 if (TableEntry
== 0) {
1309 if (Level
== GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1310 if (RepeatZero
== 0) {
1311 Uint64ToBinString(TableEntry
, String
);
1312 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1313 } else if (RepeatZero
== 1) {
1314 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "... : ...\r\n"));
1319 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1322 Tables
[Level
] = TableEntry
;
1323 Addresses
[Level
] = Address
;
1332 Uint64ToBinString(TableEntry
, String
);
1333 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1338 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1342 Indices
[Level
] += 1;
1343 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1344 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);
1350 Debug function used to verify if the Guard page is well set or not.
1352 @param[in] BaseAddress Address of memory to check.
1353 @param[in] NumberOfPages Size of memory in pages.
1355 @return TRUE The head Guard and tail Guard are both well set.
1356 @return FALSE The head Guard and/or tail Guard are not well set.
1360 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1361 IN UINTN NumberOfPages
1366 EFI_PHYSICAL_ADDRESS Address
;
1368 if (mSmmMemoryAttribute
== NULL
) {
1373 Address
= BaseAddress
- EFI_PAGE_SIZE
;
1374 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1375 mSmmMemoryAttribute
,
1380 if (EFI_ERROR (Status
) || (Attribute
& EFI_MEMORY_RP
) == 0) {
1381 DEBUG ((DEBUG_ERROR
, "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
1382 Address
, Attribute
));
1383 DumpGuardedMemoryBitmap ();
1388 Address
= BaseAddress
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
1389 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1390 mSmmMemoryAttribute
,
1395 if (EFI_ERROR (Status
) || (Attribute
& EFI_MEMORY_RP
) == 0) {
1396 DEBUG ((DEBUG_ERROR
, "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
1397 Address
, Attribute
));
1398 DumpGuardedMemoryBitmap ();