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.
17 #include "HeapGuard.h"
20 // Global to avoid infinite reentrance of memory allocation when updating
21 // page table attributes, which may need allocate pages for new PDE/PTE.
23 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding
= FALSE
;
26 // Pointer to table tracking the Guarded memory with bitmap, in which '1'
27 // is used to indicate memory guarded. '0' might be free memory or Guard
28 // page itself, depending on status of memory adjacent to it.
30 GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap
= 0;
33 // Current depth level of map table pointed by mGuardedMemoryMap.
34 // mMapLevel must be initialized at least by 1. It will be automatically
35 // updated according to the address of memory just tracked.
37 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel
= 1;
40 // Shift and mask for each level of map table
42 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift
[GUARDED_HEAP_MAP_TABLE_DEPTH
]
43 = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS
;
44 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask
[GUARDED_HEAP_MAP_TABLE_DEPTH
]
45 = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS
;
48 Set corresponding bits in bitmap table to 1 according to the address.
50 @param[in] Address Start address to set for.
51 @param[in] BitNumber Number of bits to set.
52 @param[in] BitMap Pointer to bitmap which covers the Address.
59 IN EFI_PHYSICAL_ADDRESS Address
,
70 StartBit
= (UINTN
)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
);
71 EndBit
= (StartBit
+ BitNumber
- 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
73 if ((StartBit
+ BitNumber
) >= GUARDED_HEAP_MAP_ENTRY_BITS
) {
74 Msbs
= (GUARDED_HEAP_MAP_ENTRY_BITS
- StartBit
) %
75 GUARDED_HEAP_MAP_ENTRY_BITS
;
76 Lsbs
= (EndBit
+ 1) % GUARDED_HEAP_MAP_ENTRY_BITS
;
77 Qwords
= (BitNumber
- Msbs
) / GUARDED_HEAP_MAP_ENTRY_BITS
;
85 *BitMap
|= LShiftU64 (LShiftU64 (1, Msbs
) - 1, StartBit
);
90 SetMem64 ((VOID
*)BitMap
, 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 Locate the pointer of bitmap from the guarded memory bitmap tables, which
206 covers the given Address.
208 @param[in] Address Start address to search the bitmap for.
209 @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
210 @param[out] BitMap Pointer to bitmap which covers the Address.
212 @return The bit number from given Address to the end of current map table.
215 FindGuardedMemoryMap (
216 IN EFI_PHYSICAL_ADDRESS Address
,
217 IN BOOLEAN AllocMapUnit
,
230 // Adjust current map table depth according to the address to access
232 while (AllocMapUnit
&&
233 mMapLevel
< GUARDED_HEAP_MAP_TABLE_DEPTH
&&
236 mLevelShift
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1]
239 if (mGuardedMemoryMap
!= 0) {
240 Size
= (mLevelMask
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1] + 1)
241 * GUARDED_HEAP_MAP_ENTRY_BYTES
;
242 Status
= CoreInternalAllocatePages (
245 EFI_SIZE_TO_PAGES (Size
),
249 ASSERT_EFI_ERROR (Status
);
250 ASSERT (MapMemory
!= 0);
252 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
254 *(UINT64
*)(UINTN
)MapMemory
= mGuardedMemoryMap
;
255 mGuardedMemoryMap
= MapMemory
;
262 GuardMap
= &mGuardedMemoryMap
;
263 for (Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
264 Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
;
267 if (*GuardMap
== 0) {
273 Size
= (mLevelMask
[Level
] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES
;
274 Status
= CoreInternalAllocatePages (
277 EFI_SIZE_TO_PAGES (Size
),
281 ASSERT_EFI_ERROR (Status
);
282 ASSERT (MapMemory
!= 0);
284 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
285 *GuardMap
= MapMemory
;
288 Index
= (UINTN
)RShiftU64 (Address
, mLevelShift
[Level
]);
289 Index
&= mLevelMask
[Level
];
290 GuardMap
= (UINT64
*)(UINTN
)((*GuardMap
) + Index
* sizeof (UINT64
));
294 BitsToUnitEnd
= GUARDED_HEAP_MAP_BITS
- GUARDED_HEAP_MAP_BIT_INDEX (Address
);
297 return BitsToUnitEnd
;
301 Set corresponding bits in bitmap table to 1 according to given memory range.
303 @param[in] Address Memory address to guard from.
304 @param[in] NumberOfPages Number of pages to guard.
310 SetGuardedMemoryBits (
311 IN EFI_PHYSICAL_ADDRESS Address
,
312 IN UINTN NumberOfPages
319 while (NumberOfPages
> 0) {
320 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, TRUE
, &BitMap
);
321 ASSERT (BitMap
!= NULL
);
323 if (NumberOfPages
> BitsToUnitEnd
) {
325 Bits
= BitsToUnitEnd
;
327 Bits
= NumberOfPages
;
330 SetBits (Address
, Bits
, BitMap
);
332 NumberOfPages
-= Bits
;
333 Address
+= EFI_PAGES_TO_SIZE (Bits
);
338 Clear corresponding bits in bitmap table according to given memory range.
340 @param[in] Address Memory address to unset from.
341 @param[in] NumberOfPages Number of pages to unset guard.
347 ClearGuardedMemoryBits (
348 IN EFI_PHYSICAL_ADDRESS Address
,
349 IN UINTN NumberOfPages
356 while (NumberOfPages
> 0) {
357 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, TRUE
, &BitMap
);
358 ASSERT (BitMap
!= NULL
);
360 if (NumberOfPages
> BitsToUnitEnd
) {
362 Bits
= BitsToUnitEnd
;
364 Bits
= NumberOfPages
;
367 ClearBits (Address
, Bits
, BitMap
);
369 NumberOfPages
-= Bits
;
370 Address
+= EFI_PAGES_TO_SIZE (Bits
);
375 Retrieve corresponding bits in bitmap table according to given memory range.
377 @param[in] Address Memory address to retrieve from.
378 @param[in] NumberOfPages Number of pages to retrieve.
380 @return An integer containing the guarded memory bitmap.
383 GetGuardedMemoryBits (
384 IN EFI_PHYSICAL_ADDRESS Address
,
385 IN UINTN NumberOfPages
394 ASSERT (NumberOfPages
<= GUARDED_HEAP_MAP_ENTRY_BITS
);
398 while (NumberOfPages
> 0) {
399 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, FALSE
, &BitMap
);
401 if (NumberOfPages
> BitsToUnitEnd
) {
403 Bits
= BitsToUnitEnd
;
405 Bits
= NumberOfPages
;
408 if (BitMap
!= NULL
) {
409 Result
|= LShiftU64 (GetBits (Address
, Bits
, BitMap
), Shift
);
413 NumberOfPages
-= Bits
;
414 Address
+= EFI_PAGES_TO_SIZE (Bits
);
421 Get bit value in bitmap table for the given address.
423 @param[in] Address The address to retrieve for.
430 IN EFI_PHYSICAL_ADDRESS Address
435 FindGuardedMemoryMap (Address
, FALSE
, &GuardMap
);
436 if (GuardMap
!= NULL
) {
437 if (RShiftU64 (*GuardMap
,
438 GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
)) & 1) {
447 Set the bit in bitmap table for the given address.
449 @param[in] Address The address to set for.
456 IN EFI_PHYSICAL_ADDRESS Address
462 FindGuardedMemoryMap (Address
, TRUE
, &GuardMap
);
463 if (GuardMap
!= NULL
) {
464 BitMask
= LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
));
465 *GuardMap
|= BitMask
;
470 Clear the bit in bitmap table for the given address.
472 @param[in] Address The address to clear for.
479 IN EFI_PHYSICAL_ADDRESS Address
485 FindGuardedMemoryMap (Address
, TRUE
, &GuardMap
);
486 if (GuardMap
!= NULL
) {
487 BitMask
= LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
));
488 *GuardMap
&= ~BitMask
;
493 Check to see if the page at the given address is a Guard page or not.
495 @param[in] Address The address to check for.
497 @return TRUE The page at Address is a Guard page.
498 @return FALSE The page at Address is not a Guard page.
503 IN EFI_PHYSICAL_ADDRESS Address
509 // There must be at least one guarded page before and/or after given
510 // address if it's a Guard page. The bitmap pattern should be one of
513 BitMap
= GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 3);
514 return ((BitMap
== BIT0
) || (BitMap
== BIT2
) || (BitMap
== (BIT2
| BIT0
)));
518 Check to see if the page at the given address is a head Guard page or not.
520 @param[in] Address The address to check for
522 @return TRUE The page at Address is a head Guard page
523 @return FALSE The page at Address is not a head Guard page
528 IN EFI_PHYSICAL_ADDRESS Address
531 return (GetGuardedMemoryBits (Address
, 2) == BIT1
);
535 Check to see if the page at the given address is a tail Guard page or not.
537 @param[in] Address The address to check for.
539 @return TRUE The page at Address is a tail Guard page.
540 @return FALSE The page at Address is not a tail Guard page.
545 IN EFI_PHYSICAL_ADDRESS Address
548 return (GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 2) == BIT0
);
552 Check to see if the page at the given address is guarded or not.
554 @param[in] Address The address to check for.
556 @return TRUE The page at Address is guarded.
557 @return FALSE The page at Address is not guarded.
562 IN EFI_PHYSICAL_ADDRESS Address
565 return (GetGuardMapBit (Address
) == 1);
569 Set the page at the given address to be a Guard page.
571 This is done by changing the page table attribute to be NOT PRSENT.
573 @param[in] BaseAddress Page address to Guard at
580 IN EFI_PHYSICAL_ADDRESS BaseAddress
590 // Set flag to make sure allocating memory without GUARD for page table
591 // operation; otherwise infinite loops could be caused.
595 // Note: This might overwrite other attributes needed by other features,
596 // such as NX memory protection.
598 Status
= gCpu
->SetMemoryAttributes (gCpu
, BaseAddress
, EFI_PAGE_SIZE
, EFI_MEMORY_RP
);
599 ASSERT_EFI_ERROR (Status
);
604 Unset the Guard page at the given address to the normal memory.
606 This is done by changing the page table attribute to be PRSENT.
608 @param[in] BaseAddress Page address to Guard at.
615 IN EFI_PHYSICAL_ADDRESS BaseAddress
626 // Once the Guard page is unset, it will be freed back to memory pool. NX
627 // memory protection must be restored for this page if NX is enabled for free
631 if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy
) & (1 << EfiConventionalMemory
)) != 0) {
632 Attributes
|= EFI_MEMORY_XP
;
636 // Set flag to make sure allocating memory without GUARD for page table
637 // operation; otherwise infinite loops could be caused.
641 // Note: This might overwrite other attributes needed by other features,
642 // such as memory protection (NX). Please make sure they are not enabled
645 Status
= gCpu
->SetMemoryAttributes (gCpu
, BaseAddress
, EFI_PAGE_SIZE
, Attributes
);
646 ASSERT_EFI_ERROR (Status
);
651 Check to see if the memory at the given address should be guarded or not.
653 @param[in] MemoryType Memory type to check.
654 @param[in] AllocateType Allocation type to check.
655 @param[in] PageOrPool Indicate a page allocation or pool allocation.
658 @return TRUE The given type of memory should be guarded.
659 @return FALSE The given type of memory should not be guarded.
662 IsMemoryTypeToGuard (
663 IN EFI_MEMORY_TYPE MemoryType
,
664 IN EFI_ALLOCATE_TYPE AllocateType
,
672 if (AllocateType
== AllocateAddress
) {
677 if (gSmmBase2
!= NULL
) {
678 gSmmBase2
->InSmm (gSmmBase2
, &InSmm
);
685 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & PageOrPool
) == 0) {
689 if (PageOrPool
== GUARD_HEAP_TYPE_POOL
) {
690 ConfigBit
= PcdGet64 (PcdHeapGuardPoolType
);
691 } else if (PageOrPool
== GUARD_HEAP_TYPE_PAGE
) {
692 ConfigBit
= PcdGet64 (PcdHeapGuardPageType
);
694 ConfigBit
= (UINT64
)-1;
697 if ((UINT32
)MemoryType
>= MEMORY_TYPE_OS_RESERVED_MIN
) {
699 } else if ((UINT32
) MemoryType
>= MEMORY_TYPE_OEM_RESERVED_MIN
) {
701 } else if (MemoryType
< EfiMaxMemoryType
) {
702 TestBit
= LShiftU64 (1, MemoryType
);
703 } else if (MemoryType
== EfiMaxMemoryType
) {
704 TestBit
= (UINT64
)-1;
709 return ((ConfigBit
& TestBit
) != 0);
713 Check to see if the pool at the given address should be guarded or not.
715 @param[in] MemoryType Pool type to check.
718 @return TRUE The given type of pool should be guarded.
719 @return FALSE The given type of pool should not be guarded.
723 IN EFI_MEMORY_TYPE MemoryType
726 return IsMemoryTypeToGuard (MemoryType
, AllocateAnyPages
,
727 GUARD_HEAP_TYPE_POOL
);
731 Check to see if the page at the given address should be guarded or not.
733 @param[in] MemoryType Page type to check.
734 @param[in] AllocateType Allocation type to check.
736 @return TRUE The given type of page should be guarded.
737 @return FALSE The given type of page should not be guarded.
741 IN EFI_MEMORY_TYPE MemoryType
,
742 IN EFI_ALLOCATE_TYPE AllocateType
745 return IsMemoryTypeToGuard (MemoryType
, AllocateType
, GUARD_HEAP_TYPE_PAGE
);
749 Check to see if the heap guard is enabled for page and/or pool allocation.
758 return IsMemoryTypeToGuard (EfiMaxMemoryType
, AllocateAnyPages
,
759 GUARD_HEAP_TYPE_POOL
|GUARD_HEAP_TYPE_PAGE
);
763 Set head Guard and tail Guard for the given memory range.
765 @param[in] Memory Base address of memory to set guard for.
766 @param[in] NumberOfPages Memory size in pages.
772 IN EFI_PHYSICAL_ADDRESS Memory
,
773 IN UINTN NumberOfPages
776 EFI_PHYSICAL_ADDRESS GuardPage
;
781 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
782 if (!IsGuardPage (GuardPage
)) {
783 SetGuardPage (GuardPage
);
787 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
788 if (!IsGuardPage (GuardPage
)) {
789 SetGuardPage (GuardPage
);
793 // Mark the memory range as Guarded
795 SetGuardedMemoryBits (Memory
, NumberOfPages
);
799 Unset head Guard and tail Guard for the given memory range.
801 @param[in] Memory Base address of memory to unset guard for.
802 @param[in] NumberOfPages Memory size in pages.
807 UnsetGuardForMemory (
808 IN EFI_PHYSICAL_ADDRESS Memory
,
809 IN UINTN NumberOfPages
812 EFI_PHYSICAL_ADDRESS GuardPage
;
815 if (NumberOfPages
== 0) {
820 // Head Guard must be one page before, if any.
823 // -------------------
824 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
825 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
826 // 1 X -> Don't free first page (need a new Guard)
827 // (it'll be turned into a Guard page later)
828 // -------------------
831 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
832 GuardBitmap
= GetGuardedMemoryBits (Memory
- EFI_PAGES_TO_SIZE (2), 2);
833 if ((GuardBitmap
& BIT1
) == 0) {
835 // Head Guard exists.
837 if ((GuardBitmap
& BIT0
) == 0) {
839 // If the head Guard is not a tail Guard of adjacent memory block,
842 UnsetGuardPage (GuardPage
);
846 // Pages before memory to free are still in Guard. It's a partial free
847 // case. Turn first page of memory block to free into a new Guard.
849 SetGuardPage (Memory
);
853 // Tail Guard must be the page after this memory block to free, if any.
856 // --------------------
857 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
858 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
859 // X 1 -> Don't free last page (need a new Guard)
860 // (it'll be turned into a Guard page later)
861 // --------------------
864 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
865 GuardBitmap
= GetGuardedMemoryBits (GuardPage
, 2);
866 if ((GuardBitmap
& BIT0
) == 0) {
868 // Tail Guard exists.
870 if ((GuardBitmap
& BIT1
) == 0) {
872 // If the tail Guard is not a head Guard of adjacent memory block,
873 // free it; otherwise, keep it.
875 UnsetGuardPage (GuardPage
);
879 // Pages after memory to free are still in Guard. It's a partial free
880 // case. We need to keep one page to be a head Guard.
882 SetGuardPage (GuardPage
- EFI_PAGES_TO_SIZE (1));
886 // No matter what, we just clear the mark of the Guarded memory.
888 ClearGuardedMemoryBits(Memory
, NumberOfPages
);
892 Adjust address of free memory according to existing and/or required Guard.
894 This function will check if there're existing Guard pages of adjacent
895 memory blocks, and try to use it as the Guard page of the memory to be
898 @param[in] Start Start address of free memory block.
899 @param[in] Size Size of free memory block.
900 @param[in] SizeRequested Size of memory to allocate.
902 @return The end address of memory block found.
903 @return 0 if no enough space for the required size of memory and its Guard.
909 IN UINT64 SizeRequested
915 // UEFI spec requires that allocated pool must be 8-byte aligned. If it's
916 // indicated to put the pool near the Tail Guard, we need extra bytes to
917 // make sure alignment of the returned pool address.
919 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) == 0) {
920 SizeRequested
= ALIGN_VALUE(SizeRequested
, 8);
923 Target
= Start
+ Size
- SizeRequested
;
924 ASSERT (Target
>= Start
);
929 if (!IsGuardPage (Start
+ Size
)) {
930 // No Guard at tail to share. One more page is needed.
931 Target
-= EFI_PAGES_TO_SIZE (1);
935 if (Target
< Start
) {
940 if (Target
== Start
) {
941 if (!IsGuardPage (Target
- EFI_PAGES_TO_SIZE (1))) {
942 // No enough space for a new head Guard if no Guard at head to share.
947 // OK, we have enough pages for memory and its Guards. Return the End of the
949 return Target
+ SizeRequested
- 1;
953 Adjust the start address and number of pages to free according to Guard.
955 The purpose of this function is to keep the shared Guard page with adjacent
956 memory block if it's still in guard, or free it if no more sharing. Another
957 is to reserve pages as Guard pages in partial page free situation.
959 @param[in,out] Memory Base address of memory to free.
960 @param[in,out] NumberOfPages Size of memory to free.
966 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
967 IN OUT UINTN
*NumberOfPages
970 EFI_PHYSICAL_ADDRESS Start
;
971 EFI_PHYSICAL_ADDRESS MemoryToTest
;
975 if (Memory
== NULL
|| NumberOfPages
== NULL
|| *NumberOfPages
== 0) {
980 PagesToFree
= *NumberOfPages
;
983 // Head Guard must be one page before, if any.
986 // -------------------
987 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
988 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
989 // 1 X -> Don't free first page (need a new Guard)
990 // (it'll be turned into a Guard page later)
991 // -------------------
994 MemoryToTest
= Start
- EFI_PAGES_TO_SIZE (2);
995 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
996 if ((GuardBitmap
& BIT1
) == 0) {
998 // Head Guard exists.
1000 if ((GuardBitmap
& BIT0
) == 0) {
1002 // If the head Guard is not a tail Guard of adjacent memory block,
1003 // free it; otherwise, keep it.
1005 Start
-= EFI_PAGES_TO_SIZE (1);
1010 // No Head Guard, and pages before memory to free are still in Guard. It's a
1011 // partial free case. We need to keep one page to be a tail Guard.
1013 Start
+= EFI_PAGES_TO_SIZE (1);
1018 // Tail Guard must be the page after this memory block to free, if any.
1021 // --------------------
1022 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
1023 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
1024 // X 1 -> Don't free last page (need a new Guard)
1025 // (it'll be turned into a Guard page later)
1026 // --------------------
1029 MemoryToTest
= Start
+ EFI_PAGES_TO_SIZE (PagesToFree
);
1030 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
1031 if ((GuardBitmap
& BIT0
) == 0) {
1033 // Tail Guard exists.
1035 if ((GuardBitmap
& BIT1
) == 0) {
1037 // If the tail Guard is not a head Guard of adjacent memory block,
1038 // free it; otherwise, keep it.
1042 } else if (PagesToFree
> 0) {
1044 // No Tail Guard, and pages after memory to free are still in Guard. It's a
1045 // partial free case. We need to keep one page to be a head Guard.
1051 *NumberOfPages
= PagesToFree
;
1055 Adjust the base and number of pages to really allocate according to Guard.
1057 @param[in,out] Memory Base address of free memory.
1058 @param[in,out] NumberOfPages Size of memory to allocate.
1064 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
1065 IN OUT UINTN
*NumberOfPages
1069 // FindFreePages() has already taken the Guard into account. It's safe to
1070 // adjust the start address and/or number of pages here, to make sure that
1071 // the Guards are also "allocated".
1073 if (!IsGuardPage (*Memory
+ EFI_PAGES_TO_SIZE (*NumberOfPages
))) {
1074 // No tail Guard, add one.
1075 *NumberOfPages
+= 1;
1078 if (!IsGuardPage (*Memory
- EFI_PAGE_SIZE
)) {
1079 // No head Guard, add one.
1080 *Memory
-= EFI_PAGE_SIZE
;
1081 *NumberOfPages
+= 1;
1086 Adjust the pool head position to make sure the Guard page is adjavent to
1087 pool tail or pool head.
1089 @param[in] Memory Base address of memory allocated.
1090 @param[in] NoPages Number of pages actually allocated.
1091 @param[in] Size Size of memory requested.
1092 (plus pool head/tail overhead)
1094 @return Address of pool head.
1098 IN EFI_PHYSICAL_ADDRESS Memory
,
1103 if (Memory
== 0 || (PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
1105 // Pool head is put near the head Guard
1107 return (VOID
*)(UINTN
)Memory
;
1111 // Pool head is put near the tail Guard
1113 Size
= ALIGN_VALUE (Size
, 8);
1114 return (VOID
*)(UINTN
)(Memory
+ EFI_PAGES_TO_SIZE (NoPages
) - Size
);
1118 Get the page base address according to pool head address.
1120 @param[in] Memory Head address of pool to free.
1122 @return Address of pool head.
1126 IN EFI_PHYSICAL_ADDRESS Memory
1129 if (Memory
== 0 || (PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
1131 // Pool head is put near the head Guard
1133 return (VOID
*)(UINTN
)Memory
;
1137 // Pool head is put near the tail Guard
1139 return (VOID
*)(UINTN
)(Memory
& ~EFI_PAGE_MASK
);
1143 Allocate or free guarded memory.
1145 @param[in] Start Start address of memory to allocate or free.
1146 @param[in] NumberOfPages Memory size in pages.
1147 @param[in] NewType Memory type to convert to.
1152 CoreConvertPagesWithGuard (
1154 IN UINTN NumberOfPages
,
1155 IN EFI_MEMORY_TYPE NewType
1161 if (NewType
== EfiConventionalMemory
) {
1163 OldPages
= NumberOfPages
;
1165 AdjustMemoryF (&Start
, &NumberOfPages
);
1167 // It's safe to unset Guard page inside memory lock because there should
1168 // be no memory allocation occurred in updating memory page attribute at
1169 // this point. And unsetting Guard page before free will prevent Guard
1170 // page just freed back to pool from being allocated right away before
1171 // marking it usable (from non-present to present).
1173 UnsetGuardForMemory (OldStart
, OldPages
);
1174 if (NumberOfPages
== 0) {
1178 AdjustMemoryA (&Start
, &NumberOfPages
);
1181 return CoreConvertPages (Start
, NumberOfPages
, NewType
);
1185 Set all Guard pages which cannot be set before CPU Arch Protocol installed.
1192 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1193 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1194 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1195 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1196 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1204 if (mGuardedMemoryMap
== 0 ||
1206 mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
) {
1210 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1211 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1213 SetMem (Tables
, sizeof(Tables
), 0);
1214 SetMem (Addresses
, sizeof(Addresses
), 0);
1215 SetMem (Indices
, sizeof(Indices
), 0);
1217 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1218 Tables
[Level
] = mGuardedMemoryMap
;
1223 DumpGuardedMemoryBitmap ();
1227 if (Indices
[Level
] > Entries
[Level
]) {
1232 TableEntry
= ((UINT64
*)(UINTN
)(Tables
[Level
]))[Indices
[Level
]];
1233 Address
= Addresses
[Level
];
1235 if (TableEntry
== 0) {
1239 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1242 Tables
[Level
] = TableEntry
;
1243 Addresses
[Level
] = Address
;
1251 while (Index
< GUARDED_HEAP_MAP_ENTRY_BITS
) {
1252 if ((TableEntry
& 1) == 1) {
1256 GuardPage
= Address
- EFI_PAGE_SIZE
;
1261 GuardPage
= Address
;
1268 if (GuardPage
!= 0) {
1269 SetGuardPage (GuardPage
);
1272 if (TableEntry
== 0) {
1276 TableEntry
= RShiftU64 (TableEntry
, 1);
1277 Address
+= EFI_PAGE_SIZE
;
1283 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1287 Indices
[Level
] += 1;
1288 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1289 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);
1295 Notify function used to set all Guard pages before CPU Arch Protocol installed.
1298 HeapGuardCpuArchProtocolNotify (
1302 ASSERT (gCpu
!= NULL
);
1303 SetAllGuardPages ();
1307 Helper function to convert a UINT64 value in binary to a string.
1309 @param[in] Value Value of a UINT64 integer.
1310 @param[out] BinString String buffer to contain the conversion result.
1317 OUT CHAR8
*BinString
1322 if (BinString
== NULL
) {
1326 for (Index
= 64; Index
> 0; --Index
) {
1327 BinString
[Index
- 1] = '0' + (Value
& 1);
1328 Value
= RShiftU64 (Value
, 1);
1330 BinString
[64] = '\0';
1334 Dump the guarded memory bit map.
1338 DumpGuardedMemoryBitmap (
1342 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1343 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1344 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1345 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1346 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1351 CHAR8 String
[GUARDED_HEAP_MAP_ENTRY_BITS
+ 1];
1355 if (mGuardedMemoryMap
== 0 ||
1357 mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
) {
1361 Ruler1
= " 3 2 1 0";
1362 Ruler2
= "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1364 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "============================="
1365 " Guarded Memory Bitmap "
1366 "==============================\r\n"));
1367 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler1
));
1368 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler2
));
1370 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1371 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1373 SetMem (Indices
, sizeof(Indices
), 0);
1374 SetMem (Tables
, sizeof(Tables
), 0);
1375 SetMem (Addresses
, sizeof(Addresses
), 0);
1377 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1378 Tables
[Level
] = mGuardedMemoryMap
;
1383 if (Indices
[Level
] > Entries
[Level
]) {
1390 HEAP_GUARD_DEBUG_LEVEL
,
1391 "========================================="
1392 "=========================================\r\n"
1397 TableEntry
= ((UINT64
*)(UINTN
)Tables
[Level
])[Indices
[Level
]];
1398 Address
= Addresses
[Level
];
1400 if (TableEntry
== 0) {
1402 if (Level
== GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1403 if (RepeatZero
== 0) {
1404 Uint64ToBinString(TableEntry
, String
);
1405 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1406 } else if (RepeatZero
== 1) {
1407 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "... : ...\r\n"));
1412 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1415 Tables
[Level
] = TableEntry
;
1416 Addresses
[Level
] = Address
;
1425 Uint64ToBinString(TableEntry
, String
);
1426 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1431 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1435 Indices
[Level
] += 1;
1436 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1437 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);