2 UEFI Heap Guard functions.
4 Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
5 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.
15 #include "HeapGuard.h"
18 // Global to avoid infinite reentrance of memory allocation when updating
19 // page table attributes, which may need allocating pages for new PDE/PTE.
21 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding
= FALSE
;
24 // Pointer to table tracking the Guarded memory with bitmap, in which '1'
25 // is used to indicate memory guarded. '0' might be free memory or Guard
26 // page itself, depending on status of memory adjacent to it.
28 GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap
= 0;
31 // Current depth level of map table pointed by mGuardedMemoryMap.
32 // mMapLevel must be initialized at least by 1. It will be automatically
33 // updated according to the address of memory just tracked.
35 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel
= 1;
38 // Shift and mask for each level of map table
40 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift
[GUARDED_HEAP_MAP_TABLE_DEPTH
]
41 = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS
;
42 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask
[GUARDED_HEAP_MAP_TABLE_DEPTH
]
43 = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS
;
46 // SMM memory attribute protocol
48 EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*mSmmMemoryAttribute
= NULL
;
51 Set corresponding bits in bitmap table to 1 according to the address.
53 @param[in] Address Start address to set for.
54 @param[in] BitNumber Number of bits to set.
55 @param[in] BitMap Pointer to bitmap which covers the Address.
62 IN EFI_PHYSICAL_ADDRESS Address
,
73 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
74 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
76 if ((StartBit
+ BitNumber
) >= GUARDED_HEAP_MAP_ENTRY_BITS
) {
77 Msbs
= (GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
) %
78 GUARDED_HEAP_MAP_ENTRY_BITS
;
79 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
80 Qwords
= (BitNumber
- Msbs
) / GUARDED_HEAP_MAP_ENTRY_BITS
;
88 *BitMap
|= LShiftU64 (LShiftU64 (1, Msbs
) - 1, StartBit
);
93 SetMem64 ((VOID
*)BitMap
, Qwords
* GUARDED_HEAP_MAP_ENTRY_BYTES
,
99 *BitMap
|= (LShiftU64 (1, Lsbs
) - 1);
104 Set corresponding bits in bitmap table to 0 according to the address.
106 @param[in] Address Start address to set for.
107 @param[in] BitNumber Number of bits to set.
108 @param[in] BitMap Pointer to bitmap which covers the Address.
115 IN EFI_PHYSICAL_ADDRESS Address
,
126 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
127 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
129 if ((StartBit
+ BitNumber
) >= GUARDED_HEAP_MAP_ENTRY_BITS
) {
130 Msbs
= (GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
) %
131 GUARDED_HEAP_MAP_ENTRY_BITS
;
132 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
133 Qwords
= (BitNumber
- Msbs
) / GUARDED_HEAP_MAP_ENTRY_BITS
;
141 *BitMap
&= ~LShiftU64 (LShiftU64 (1, Msbs
) - 1, StartBit
);
146 SetMem64 ((VOID
*)BitMap
, Qwords
* GUARDED_HEAP_MAP_ENTRY_BYTES
, 0);
151 *BitMap
&= ~(LShiftU64 (1, Lsbs
) - 1);
156 Get corresponding bits in bitmap table according to the address.
158 The value of bit 0 corresponds to the status of memory at given Address.
159 No more than 64 bits can be retrieved in one call.
161 @param[in] Address Start address to retrieve bits for.
162 @param[in] BitNumber Number of bits to get.
163 @param[in] BitMap Pointer to bitmap which covers the Address.
165 @return An integer containing the bits information.
170 IN EFI_PHYSICAL_ADDRESS Address
,
181 ASSERT (BitNumber
<= GUARDED_HEAP_MAP_ENTRY_BITS
);
183 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
184 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
186 if ((StartBit
+ BitNumber
) > GUARDED_HEAP_MAP_ENTRY_BITS
) {
187 Msbs
= GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
;
188 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
194 if (StartBit
== 0 && BitNumber
== GUARDED_HEAP_MAP_ENTRY_BITS
) {
197 Result
= RShiftU64((*BitMap
), StartBit
) & (LShiftU64(1, Msbs
) - 1);
200 Result
|= LShiftU64 ((*BitMap
) & (LShiftU64 (1, Lsbs
) - 1), Msbs
);
208 Helper function to allocate pages without Guard for internal uses.
210 @param[in] Pages Page number.
212 @return Address of memory allocated.
220 EFI_PHYSICAL_ADDRESS Memory
;
222 Status
= SmmInternalAllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
,
223 Pages
, &Memory
, FALSE
);
224 if (EFI_ERROR (Status
)) {
228 return (VOID
*)(UINTN
)Memory
;
232 Locate the pointer of bitmap from the guarded memory bitmap tables, which
233 covers the given Address.
235 @param[in] Address Start address to search the bitmap for.
236 @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
237 @param[out] BitMap Pointer to bitmap which covers the Address.
239 @return The bit number from given Address to the end of current map table.
242 FindGuardedMemoryMap (
243 IN EFI_PHYSICAL_ADDRESS Address
,
244 IN BOOLEAN AllocMapUnit
,
256 // Adjust current map table depth according to the address to access
258 while (AllocMapUnit
&&
259 mMapLevel
< GUARDED_HEAP_MAP_TABLE_DEPTH
&&
262 mLevelShift
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1]
265 if (mGuardedMemoryMap
!= 0) {
266 Size
= (mLevelMask
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1] + 1)
267 * GUARDED_HEAP_MAP_ENTRY_BYTES
;
268 MapMemory
= (UINT64
)(UINTN
)PageAlloc (EFI_SIZE_TO_PAGES (Size
));
269 ASSERT (MapMemory
!= 0);
271 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
273 *(UINT64
*)(UINTN
)MapMemory
= mGuardedMemoryMap
;
274 mGuardedMemoryMap
= MapMemory
;
281 GuardMap
= &mGuardedMemoryMap
;
282 for (Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
283 Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
;
286 if (*GuardMap
== 0) {
292 Size
= (mLevelMask
[Level
] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES
;
293 MapMemory
= (UINT64
)(UINTN
)PageAlloc (EFI_SIZE_TO_PAGES (Size
));
294 ASSERT (MapMemory
!= 0);
296 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
297 *GuardMap
= MapMemory
;
300 Index
= (UINTN
)RShiftU64 (Address
, mLevelShift
[Level
]);
301 Index
&= mLevelMask
[Level
];
302 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
) {
449 if (RShiftU64 (*GuardMap
,
450 GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
)) & 1) {
459 Set the bit in bitmap table for the given address.
461 @param[in] Address The address to set for.
468 IN EFI_PHYSICAL_ADDRESS Address
474 FindGuardedMemoryMap (Address
, TRUE
, &GuardMap
);
475 if (GuardMap
!= NULL
) {
476 BitMask
= LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
));
477 *GuardMap
|= BitMask
;
482 Clear the bit in bitmap table for the given address.
484 @param[in] Address The address to clear for.
491 IN EFI_PHYSICAL_ADDRESS Address
497 FindGuardedMemoryMap (Address
, TRUE
, &GuardMap
);
498 if (GuardMap
!= NULL
) {
499 BitMask
= LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
));
500 *GuardMap
&= ~BitMask
;
505 Check to see if the page at the given address is a Guard page or not.
507 @param[in] Address The address to check for.
509 @return TRUE The page at Address is a Guard page.
510 @return FALSE The page at Address is not a Guard page.
515 IN EFI_PHYSICAL_ADDRESS Address
521 // There must be at least one guarded page before and/or after given
522 // address if it's a Guard page. The bitmap pattern should be one of
525 BitMap
= GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 3);
526 return ((BitMap
== BIT0
) || (BitMap
== BIT2
) || (BitMap
== (BIT2
| BIT0
)));
530 Check to see if the page at the given address is a head Guard page or not.
532 @param[in] Address The address to check for.
534 @return TRUE The page at Address is a head Guard page.
535 @return FALSE The page at Address is not a head Guard page.
540 IN EFI_PHYSICAL_ADDRESS Address
543 return (GetGuardedMemoryBits (Address
, 2) == BIT1
);
547 Check to see if the page at the given address is a tail Guard page or not.
549 @param[in] Address The address to check for.
551 @return TRUE The page at Address is a tail Guard page.
552 @return FALSE The page at Address is not a tail Guard page.
557 IN EFI_PHYSICAL_ADDRESS Address
560 return (GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 2) == BIT0
);
564 Check to see if the page at the given address is guarded or not.
566 @param[in] Address The address to check for.
568 @return TRUE The page at Address is guarded.
569 @return FALSE The page at Address is not guarded.
574 IN EFI_PHYSICAL_ADDRESS Address
577 return (GetGuardMapBit (Address
) == 1);
581 Set the page at the given address to be a Guard page.
583 This is done by changing the page table attribute to be NOT PRSENT.
585 @param[in] BaseAddress Page address to Guard at.
592 IN EFI_PHYSICAL_ADDRESS BaseAddress
597 if (mSmmMemoryAttribute
!= NULL
) {
599 Status
= mSmmMemoryAttribute
->SetMemoryAttributes (
605 ASSERT_EFI_ERROR (Status
);
611 Unset the Guard page at the given address to the normal memory.
613 This is done by changing the page table attribute to be PRSENT.
615 @param[in] BaseAddress Page address to Guard at.
622 IN EFI_PHYSICAL_ADDRESS BaseAddress
627 if (mSmmMemoryAttribute
!= NULL
) {
629 Status
= mSmmMemoryAttribute
->ClearMemoryAttributes (
635 ASSERT_EFI_ERROR (Status
);
641 Check to see if the memory at the given address should be guarded or not.
643 @param[in] MemoryType Memory type to check.
644 @param[in] AllocateType Allocation type to check.
645 @param[in] PageOrPool Indicate a page allocation or pool allocation.
648 @return TRUE The given type of memory should be guarded.
649 @return FALSE The given type of memory should not be guarded.
652 IsMemoryTypeToGuard (
653 IN EFI_MEMORY_TYPE MemoryType
,
654 IN EFI_ALLOCATE_TYPE AllocateType
,
661 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & PageOrPool
) == 0
663 || AllocateType
== AllocateAddress
) {
668 if ((PageOrPool
& GUARD_HEAP_TYPE_POOL
) != 0) {
669 ConfigBit
|= PcdGet64 (PcdHeapGuardPoolType
);
672 if ((PageOrPool
& GUARD_HEAP_TYPE_PAGE
) != 0) {
673 ConfigBit
|= PcdGet64 (PcdHeapGuardPageType
);
676 if (MemoryType
== EfiRuntimeServicesData
||
677 MemoryType
== EfiRuntimeServicesCode
) {
678 TestBit
= LShiftU64 (1, MemoryType
);
679 } else if (MemoryType
== EfiMaxMemoryType
) {
680 TestBit
= (UINT64
)-1;
685 return ((ConfigBit
& TestBit
) != 0);
689 Check to see if the pool at the given address should be guarded or not.
691 @param[in] MemoryType Pool type to check.
694 @return TRUE The given type of pool should be guarded.
695 @return FALSE The given type of pool should not be guarded.
699 IN EFI_MEMORY_TYPE MemoryType
702 return IsMemoryTypeToGuard (MemoryType
, AllocateAnyPages
,
703 GUARD_HEAP_TYPE_POOL
);
707 Check to see if the page at the given address should be guarded or not.
709 @param[in] MemoryType Page type to check.
710 @param[in] AllocateType Allocation type to check.
712 @return TRUE The given type of page should be guarded.
713 @return FALSE The given type of page should not be guarded.
717 IN EFI_MEMORY_TYPE MemoryType
,
718 IN EFI_ALLOCATE_TYPE AllocateType
721 return IsMemoryTypeToGuard (MemoryType
, AllocateType
, GUARD_HEAP_TYPE_PAGE
);
725 Check to see if the heap guard is enabled for page and/or pool allocation.
734 return IsMemoryTypeToGuard (EfiMaxMemoryType
, AllocateAnyPages
,
735 GUARD_HEAP_TYPE_POOL
|GUARD_HEAP_TYPE_PAGE
);
739 Set head Guard and tail Guard for the given memory range.
741 @param[in] Memory Base address of memory to set guard for.
742 @param[in] NumberOfPages Memory size in pages.
748 IN EFI_PHYSICAL_ADDRESS Memory
,
749 IN UINTN NumberOfPages
752 EFI_PHYSICAL_ADDRESS GuardPage
;
757 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
758 if (!IsGuardPage (GuardPage
)) {
759 SetGuardPage (GuardPage
);
763 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
764 if (!IsGuardPage (GuardPage
)) {
765 SetGuardPage (GuardPage
);
769 // Mark the memory range as Guarded
771 SetGuardedMemoryBits (Memory
, NumberOfPages
);
775 Unset head Guard and tail Guard for the given memory range.
777 @param[in] Memory Base address of memory to unset guard for.
778 @param[in] NumberOfPages Memory size in pages.
783 UnsetGuardForMemory (
784 IN EFI_PHYSICAL_ADDRESS Memory
,
785 IN UINTN NumberOfPages
788 EFI_PHYSICAL_ADDRESS GuardPage
;
791 if (NumberOfPages
== 0) {
796 // Head Guard must be one page before, if any.
799 // -------------------
800 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
801 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
802 // 1 X -> Don't free first page (need a new Guard)
803 // (it'll be turned into a Guard page later)
804 // -------------------
807 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
808 GuardBitmap
= GetGuardedMemoryBits (Memory
- EFI_PAGES_TO_SIZE (2), 2);
809 if ((GuardBitmap
& BIT1
) == 0) {
811 // Head Guard exists.
813 if ((GuardBitmap
& BIT0
) == 0) {
815 // If the head Guard is not a tail Guard of adjacent memory block,
818 UnsetGuardPage (GuardPage
);
822 // Pages before memory to free are still in Guard. It's a partial free
823 // case. Turn first page of memory block to free into a new Guard.
825 SetGuardPage (Memory
);
829 // Tail Guard must be the page after this memory block to free, if any.
832 // --------------------
833 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
834 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
835 // X 1 -> Don't free last page (need a new Guard)
836 // (it'll be turned into a Guard page later)
837 // --------------------
840 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
841 GuardBitmap
= GetGuardedMemoryBits (GuardPage
, 2);
842 if ((GuardBitmap
& BIT0
) == 0) {
844 // Tail Guard exists.
846 if ((GuardBitmap
& BIT1
) == 0) {
848 // If the tail Guard is not a head Guard of adjacent memory block,
849 // free it; otherwise, keep it.
851 UnsetGuardPage (GuardPage
);
855 // Pages after memory to free are still in Guard. It's a partial free
856 // case. We need to keep one page to be a head Guard.
858 SetGuardPage (GuardPage
- EFI_PAGES_TO_SIZE (1));
862 // No matter what, we just clear the mark of the Guarded memory.
864 ClearGuardedMemoryBits(Memory
, NumberOfPages
);
868 Adjust address of free memory according to existing and/or required Guard.
870 This function will check if there're existing Guard pages of adjacent
871 memory blocks, and try to use it as the Guard page of the memory to be
874 @param[in] Start Start address of free memory block.
875 @param[in] Size Size of free memory block.
876 @param[in] SizeRequested Size of memory to allocate.
878 @return The end address of memory block found.
879 @return 0 if no enough space for the required size of memory and its Guard.
885 IN UINT64 SizeRequested
891 // UEFI spec requires that allocated pool must be 8-byte aligned. If it's
892 // indicated to put the pool near the Tail Guard, we need extra bytes to
893 // make sure alignment of the returned pool address.
895 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) == 0) {
896 SizeRequested
= ALIGN_VALUE(SizeRequested
, 8);
899 Target
= Start
+ Size
- SizeRequested
;
900 ASSERT (Target
>= Start
);
905 if (!IsGuardPage (Start
+ Size
)) {
906 // No Guard at tail to share. One more page is needed.
907 Target
-= EFI_PAGES_TO_SIZE (1);
911 if (Target
< Start
) {
916 if (Target
== Start
) {
917 if (!IsGuardPage (Target
- EFI_PAGES_TO_SIZE (1))) {
918 // No enough space for a new head Guard if no Guard at head to share.
923 // OK, we have enough pages for memory and its Guards. Return the End of the
925 return Target
+ SizeRequested
- 1;
929 Adjust the start address and number of pages to free according to Guard.
931 The purpose of this function is to keep the shared Guard page with adjacent
932 memory block if it's still in guard, or free it if no more sharing. Another
933 is to reserve pages as Guard pages in partial page free situation.
935 @param[in,out] Memory Base address of memory to free.
936 @param[in,out] NumberOfPages Size of memory to free.
942 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
943 IN OUT UINTN
*NumberOfPages
946 EFI_PHYSICAL_ADDRESS Start
;
947 EFI_PHYSICAL_ADDRESS MemoryToTest
;
952 if (Memory
== NULL
|| NumberOfPages
== NULL
|| *NumberOfPages
== 0) {
957 PagesToFree
= *NumberOfPages
;
960 // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).
962 if (mSmmMemoryAttribute
!= NULL
) {
964 mSmmMemoryAttribute
->GetMemoryAttributes (
967 EFI_PAGES_TO_SIZE (PagesToFree
),
970 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
971 mSmmMemoryAttribute
->ClearMemoryAttributes (
974 EFI_PAGES_TO_SIZE (PagesToFree
),
981 // Head Guard must be one page before, if any.
984 // -------------------
985 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
986 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
987 // 1 X -> Don't free first page (need a new Guard)
988 // (it'll be turned into a Guard page later)
989 // -------------------
992 MemoryToTest
= Start
- EFI_PAGES_TO_SIZE (2);
993 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
994 if ((GuardBitmap
& BIT1
) == 0) {
996 // Head Guard exists.
998 if ((GuardBitmap
& BIT0
) == 0) {
1000 // If the head Guard is not a tail Guard of adjacent memory block,
1001 // free it; otherwise, keep it.
1003 Start
-= EFI_PAGES_TO_SIZE (1);
1008 // No Head Guard, and pages before memory to free are still in Guard. It's a
1009 // partial free case. We need to keep one page to be a tail Guard.
1011 Start
+= EFI_PAGES_TO_SIZE (1);
1016 // Tail Guard must be the page after this memory block to free, if any.
1019 // --------------------
1020 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
1021 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
1022 // X 1 -> Don't free last page (need a new Guard)
1023 // (it'll be turned into a Guard page later)
1024 // --------------------
1027 MemoryToTest
= Start
+ EFI_PAGES_TO_SIZE (PagesToFree
);
1028 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
1029 if ((GuardBitmap
& BIT0
) == 0) {
1031 // Tail Guard exists.
1033 if ((GuardBitmap
& BIT1
) == 0) {
1035 // If the tail Guard is not a head Guard of adjacent memory block,
1036 // free it; otherwise, keep it.
1040 } else if (PagesToFree
> 0) {
1042 // No Tail Guard, and pages after memory to free are still in Guard. It's a
1043 // partial free case. We need to keep one page to be a head Guard.
1049 *NumberOfPages
= PagesToFree
;
1053 Adjust the base and number of pages to really allocate according to Guard.
1055 @param[in,out] Memory Base address of free memory.
1056 @param[in,out] NumberOfPages Size of memory to allocate.
1062 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
1063 IN OUT UINTN
*NumberOfPages
1067 // FindFreePages() has already taken the Guard into account. It's safe to
1068 // adjust the start address and/or number of pages here, to make sure that
1069 // the Guards are also "allocated".
1071 if (!IsGuardPage (*Memory
+ EFI_PAGES_TO_SIZE (*NumberOfPages
))) {
1072 // No tail Guard, add one.
1073 *NumberOfPages
+= 1;
1076 if (!IsGuardPage (*Memory
- EFI_PAGE_SIZE
)) {
1077 // No head Guard, add one.
1078 *Memory
-= EFI_PAGE_SIZE
;
1079 *NumberOfPages
+= 1;
1084 Adjust the pool head position to make sure the Guard page is adjavent to
1085 pool tail or pool head.
1087 @param[in] Memory Base address of memory allocated.
1088 @param[in] NoPages Number of pages actually allocated.
1089 @param[in] Size Size of memory requested.
1090 (plus pool head/tail overhead)
1092 @return Address of pool head
1096 IN EFI_PHYSICAL_ADDRESS Memory
,
1101 if (Memory
== 0 || (PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
1103 // Pool head is put near the head Guard
1105 return (VOID
*)(UINTN
)Memory
;
1109 // Pool head is put near the tail Guard
1111 Size
= ALIGN_VALUE (Size
, 8);
1112 return (VOID
*)(UINTN
)(Memory
+ EFI_PAGES_TO_SIZE (NoPages
) - Size
);
1116 Get the page base address according to pool head address.
1118 @param[in] Memory Head address of pool to free.
1120 @return Address of pool head.
1124 IN EFI_PHYSICAL_ADDRESS Memory
1127 if (Memory
== 0 || (PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
1129 // Pool head is put near the head Guard
1131 return (VOID
*)(UINTN
)Memory
;
1135 // Pool head is put near the tail Guard
1137 return (VOID
*)(UINTN
)(Memory
& ~EFI_PAGE_MASK
);
1141 Helper function of memory allocation with Guard pages.
1143 @param FreePageList The free page node.
1144 @param NumberOfPages Number of pages to be allocated.
1145 @param MaxAddress Request to allocate memory below this address.
1146 @param MemoryType Type of memory requested.
1148 @return Memory address of allocated pages.
1151 InternalAllocMaxAddressWithGuard (
1152 IN OUT LIST_ENTRY
*FreePageList
,
1153 IN UINTN NumberOfPages
,
1154 IN UINTN MaxAddress
,
1155 IN EFI_MEMORY_TYPE MemoryType
1160 FREE_PAGE_LIST
*Pages
;
1166 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
;
1167 Node
= Node
->BackLink
) {
1168 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
1169 if (Pages
->NumberOfPages
>= NumberOfPages
&&
1170 (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
) {
1173 // We may need 1 or 2 more pages for Guard. Check it out.
1175 PagesToAlloc
= NumberOfPages
;
1176 TailGuard
= (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
);
1177 if (!IsGuardPage (TailGuard
)) {
1179 // Add one if no Guard at the end of current free memory block.
1185 HeadGuard
= (UINTN
)Pages
+
1186 EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
- PagesToAlloc
) -
1188 if (!IsGuardPage (HeadGuard
)) {
1190 // Add one if no Guard at the page before the address to allocate
1196 if (Pages
->NumberOfPages
< PagesToAlloc
) {
1197 // Not enough space to allocate memory with Guards? Try next block.
1201 Address
= InternalAllocPagesOnOneNode (Pages
, PagesToAlloc
, MaxAddress
);
1202 ConvertSmmMemoryMapEntry(MemoryType
, Address
, PagesToAlloc
, FALSE
);
1203 CoreFreeMemoryMapStack();
1204 if (HeadGuard
== 0) {
1205 // Don't pass the Guard page to user.
1206 Address
+= EFI_PAGE_SIZE
;
1208 SetGuardForMemory (Address
, NumberOfPages
);
1217 Helper function of memory free with Guard pages.
1219 @param[in] Memory Base address of memory being freed.
1220 @param[in] NumberOfPages The number of pages to free.
1221 @param[in] AddRegion If this memory is new added region.
1223 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
1224 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
1225 @return EFI_SUCCESS Pages successfully freed.
1228 SmmInternalFreePagesExWithGuard (
1229 IN EFI_PHYSICAL_ADDRESS Memory
,
1230 IN UINTN NumberOfPages
,
1231 IN BOOLEAN AddRegion
1234 EFI_PHYSICAL_ADDRESS MemoryToFree
;
1237 if (((Memory
& EFI_PAGE_MASK
) != 0) || (Memory
== 0) || (NumberOfPages
== 0)) {
1238 return EFI_INVALID_PARAMETER
;
1241 MemoryToFree
= Memory
;
1242 PagesToFree
= NumberOfPages
;
1244 AdjustMemoryF (&MemoryToFree
, &PagesToFree
);
1245 UnsetGuardForMemory (Memory
, NumberOfPages
);
1246 if (PagesToFree
== 0) {
1250 return SmmInternalFreePagesEx (MemoryToFree
, PagesToFree
, AddRegion
);
1254 Set all Guard pages which cannot be set during the non-SMM mode time.
1261 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1262 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1263 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1264 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1265 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1273 if (mGuardedMemoryMap
== 0 ||
1275 mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
) {
1279 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1280 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1282 SetMem (Tables
, sizeof(Tables
), 0);
1283 SetMem (Addresses
, sizeof(Addresses
), 0);
1284 SetMem (Indices
, sizeof(Indices
), 0);
1286 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1287 Tables
[Level
] = mGuardedMemoryMap
;
1292 DumpGuardedMemoryBitmap ();
1296 if (Indices
[Level
] > Entries
[Level
]) {
1301 TableEntry
= ((UINT64
*)(UINTN
)(Tables
[Level
]))[Indices
[Level
]];
1302 Address
= Addresses
[Level
];
1304 if (TableEntry
== 0) {
1308 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1311 Tables
[Level
] = TableEntry
;
1312 Addresses
[Level
] = Address
;
1320 while (Index
< GUARDED_HEAP_MAP_ENTRY_BITS
) {
1321 if ((TableEntry
& 1) == 1) {
1325 GuardPage
= Address
- EFI_PAGE_SIZE
;
1330 GuardPage
= Address
;
1337 if (GuardPage
!= 0) {
1338 SetGuardPage (GuardPage
);
1341 if (TableEntry
== 0) {
1345 TableEntry
= RShiftU64 (TableEntry
, 1);
1346 Address
+= EFI_PAGE_SIZE
;
1352 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1356 Indices
[Level
] += 1;
1357 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1358 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);
1364 Hook function used to set all Guard pages after entering SMM mode.
1367 SmmEntryPointMemoryManagementHook (
1373 if (mSmmMemoryAttribute
== NULL
) {
1374 Status
= SmmLocateProtocol (
1375 &gEdkiiSmmMemoryAttributeProtocolGuid
,
1377 (VOID
**)&mSmmMemoryAttribute
1379 if (!EFI_ERROR(Status
)) {
1380 SetAllGuardPages ();
1386 Helper function to convert a UINT64 value in binary to a string.
1388 @param[in] Value Value of a UINT64 integer.
1389 @param[out] BinString String buffer to contain the conversion result.
1396 OUT CHAR8
*BinString
1401 if (BinString
== NULL
) {
1405 for (Index
= 64; Index
> 0; --Index
) {
1406 BinString
[Index
- 1] = '0' + (Value
& 1);
1407 Value
= RShiftU64 (Value
, 1);
1409 BinString
[64] = '\0';
1413 Dump the guarded memory bit map.
1417 DumpGuardedMemoryBitmap (
1421 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1422 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1423 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1424 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1425 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1430 CHAR8 String
[GUARDED_HEAP_MAP_ENTRY_BITS
+ 1];
1434 if (mGuardedMemoryMap
== 0 ||
1436 mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
) {
1440 Ruler1
= " 3 2 1 0";
1441 Ruler2
= "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1443 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "============================="
1444 " Guarded Memory Bitmap "
1445 "==============================\r\n"));
1446 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler1
));
1447 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler2
));
1449 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1450 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1452 SetMem (Indices
, sizeof(Indices
), 0);
1453 SetMem (Tables
, sizeof(Tables
), 0);
1454 SetMem (Addresses
, sizeof(Addresses
), 0);
1456 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1457 Tables
[Level
] = mGuardedMemoryMap
;
1462 if (Indices
[Level
] > Entries
[Level
]) {
1469 HEAP_GUARD_DEBUG_LEVEL
,
1470 "========================================="
1471 "=========================================\r\n"
1476 TableEntry
= ((UINT64
*)(UINTN
)Tables
[Level
])[Indices
[Level
]];
1477 Address
= Addresses
[Level
];
1479 if (TableEntry
== 0) {
1481 if (Level
== GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1482 if (RepeatZero
== 0) {
1483 Uint64ToBinString(TableEntry
, String
);
1484 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1485 } else if (RepeatZero
== 1) {
1486 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "... : ...\r\n"));
1491 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1494 Tables
[Level
] = TableEntry
;
1495 Addresses
[Level
] = Address
;
1504 Uint64ToBinString(TableEntry
, String
);
1505 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1510 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1514 Indices
[Level
] += 1;
1515 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1516 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);
1522 Debug function used to verify if the Guard page is well set or not.
1524 @param[in] BaseAddress Address of memory to check.
1525 @param[in] NumberOfPages Size of memory in pages.
1527 @return TRUE The head Guard and tail Guard are both well set.
1528 @return FALSE The head Guard and/or tail Guard are not well set.
1532 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1533 IN UINTN NumberOfPages
1538 EFI_PHYSICAL_ADDRESS Address
;
1540 if (mSmmMemoryAttribute
== NULL
) {
1545 Address
= BaseAddress
- EFI_PAGE_SIZE
;
1546 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1547 mSmmMemoryAttribute
,
1552 if (EFI_ERROR (Status
) || (Attribute
& EFI_MEMORY_RP
) == 0) {
1553 DEBUG ((DEBUG_ERROR
, "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
1554 Address
, Attribute
));
1555 DumpGuardedMemoryBitmap ();
1560 Address
= BaseAddress
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
1561 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1562 mSmmMemoryAttribute
,
1567 if (EFI_ERROR (Status
) || (Attribute
& EFI_MEMORY_RP
) == 0) {
1568 DEBUG ((DEBUG_ERROR
, "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
1569 Address
, Attribute
));
1570 DumpGuardedMemoryBitmap ();