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) {
460 Check to see if the page at the given address is a Guard page or not.
462 @param[in] Address The address to check for.
464 @return TRUE The page at Address is a Guard page.
465 @return FALSE The page at Address is not a Guard page.
470 IN EFI_PHYSICAL_ADDRESS Address
476 // There must be at least one guarded page before and/or after given
477 // address if it's a Guard page. The bitmap pattern should be one of
480 BitMap
= GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 3);
481 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 PRSENT.
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 PRSENT.
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
) {
591 if ((PageOrPool
& GUARD_HEAP_TYPE_POOL
) != 0) {
592 ConfigBit
|= PcdGet64 (PcdHeapGuardPoolType
);
595 if ((PageOrPool
& GUARD_HEAP_TYPE_PAGE
) != 0) {
596 ConfigBit
|= PcdGet64 (PcdHeapGuardPageType
);
599 if (MemoryType
== EfiRuntimeServicesData
||
600 MemoryType
== EfiRuntimeServicesCode
) {
601 TestBit
= LShiftU64 (1, MemoryType
);
602 } else if (MemoryType
== EfiMaxMemoryType
) {
603 TestBit
= (UINT64
)-1;
608 return ((ConfigBit
& TestBit
) != 0);
612 Check to see if the pool at the given address should be guarded or not.
614 @param[in] MemoryType Pool type to check.
617 @return TRUE The given type of pool should be guarded.
618 @return FALSE The given type of pool should not be guarded.
622 IN EFI_MEMORY_TYPE MemoryType
625 return IsMemoryTypeToGuard (MemoryType
, AllocateAnyPages
,
626 GUARD_HEAP_TYPE_POOL
);
630 Check to see if the page at the given address should be guarded or not.
632 @param[in] MemoryType Page type to check.
633 @param[in] AllocateType Allocation type to check.
635 @return TRUE The given type of page should be guarded.
636 @return FALSE The given type of page should not be guarded.
640 IN EFI_MEMORY_TYPE MemoryType
,
641 IN EFI_ALLOCATE_TYPE AllocateType
644 return IsMemoryTypeToGuard (MemoryType
, AllocateType
, GUARD_HEAP_TYPE_PAGE
);
648 Check to see if the heap guard is enabled for page and/or pool allocation.
657 return IsMemoryTypeToGuard (EfiMaxMemoryType
, AllocateAnyPages
,
658 GUARD_HEAP_TYPE_POOL
|GUARD_HEAP_TYPE_PAGE
);
662 Set head Guard and tail Guard for the given memory range.
664 @param[in] Memory Base address of memory to set guard for.
665 @param[in] NumberOfPages Memory size in pages.
671 IN EFI_PHYSICAL_ADDRESS Memory
,
672 IN UINTN NumberOfPages
675 EFI_PHYSICAL_ADDRESS GuardPage
;
680 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
681 if (!IsGuardPage (GuardPage
)) {
682 SetGuardPage (GuardPage
);
686 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
687 if (!IsGuardPage (GuardPage
)) {
688 SetGuardPage (GuardPage
);
692 // Mark the memory range as Guarded
694 SetGuardedMemoryBits (Memory
, NumberOfPages
);
698 Unset head Guard and tail Guard for the given memory range.
700 @param[in] Memory Base address of memory to unset guard for.
701 @param[in] NumberOfPages Memory size in pages.
706 UnsetGuardForMemory (
707 IN EFI_PHYSICAL_ADDRESS Memory
,
708 IN UINTN NumberOfPages
711 EFI_PHYSICAL_ADDRESS GuardPage
;
714 if (NumberOfPages
== 0) {
719 // Head Guard must be one page before, if any.
722 // -------------------
723 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
724 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
725 // 1 X -> Don't free first page (need a new Guard)
726 // (it'll be turned into a Guard page later)
727 // -------------------
730 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
731 GuardBitmap
= GetGuardedMemoryBits (Memory
- EFI_PAGES_TO_SIZE (2), 2);
732 if ((GuardBitmap
& BIT1
) == 0) {
734 // Head Guard exists.
736 if ((GuardBitmap
& BIT0
) == 0) {
738 // If the head Guard is not a tail Guard of adjacent memory block,
741 UnsetGuardPage (GuardPage
);
745 // Pages before memory to free are still in Guard. It's a partial free
746 // case. Turn first page of memory block to free into a new Guard.
748 SetGuardPage (Memory
);
752 // Tail Guard must be the page after this memory block to free, if any.
755 // --------------------
756 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
757 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
758 // X 1 -> Don't free last page (need a new Guard)
759 // (it'll be turned into a Guard page later)
760 // --------------------
763 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
764 GuardBitmap
= GetGuardedMemoryBits (GuardPage
, 2);
765 if ((GuardBitmap
& BIT0
) == 0) {
767 // Tail Guard exists.
769 if ((GuardBitmap
& BIT1
) == 0) {
771 // If the tail Guard is not a head Guard of adjacent memory block,
772 // free it; otherwise, keep it.
774 UnsetGuardPage (GuardPage
);
778 // Pages after memory to free are still in Guard. It's a partial free
779 // case. We need to keep one page to be a head Guard.
781 SetGuardPage (GuardPage
- EFI_PAGES_TO_SIZE (1));
785 // No matter what, we just clear the mark of the Guarded memory.
787 ClearGuardedMemoryBits(Memory
, NumberOfPages
);
793 Adjust the start address and number of pages to free according to Guard.
795 The purpose of this function is to keep the shared Guard page with adjacent
796 memory block if it's still in guard, or free it if no more sharing. Another
797 is to reserve pages as Guard pages in partial page free situation.
799 @param[in,out] Memory Base address of memory to free.
800 @param[in,out] NumberOfPages Size of memory to free.
806 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
807 IN OUT UINTN
*NumberOfPages
810 EFI_PHYSICAL_ADDRESS Start
;
811 EFI_PHYSICAL_ADDRESS MemoryToTest
;
816 if (Memory
== NULL
|| NumberOfPages
== NULL
|| *NumberOfPages
== 0) {
821 PagesToFree
= *NumberOfPages
;
824 // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).
826 if (mSmmMemoryAttribute
!= NULL
) {
828 mSmmMemoryAttribute
->GetMemoryAttributes (
831 EFI_PAGES_TO_SIZE (PagesToFree
),
834 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
835 mSmmMemoryAttribute
->ClearMemoryAttributes (
838 EFI_PAGES_TO_SIZE (PagesToFree
),
845 // Head Guard must be one page before, if any.
848 // -------------------
849 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
850 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
851 // 1 X -> Don't free first page (need a new Guard)
852 // (it'll be turned into a Guard page later)
853 // -------------------
856 MemoryToTest
= Start
- EFI_PAGES_TO_SIZE (2);
857 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
858 if ((GuardBitmap
& BIT1
) == 0) {
860 // Head Guard exists.
862 if ((GuardBitmap
& BIT0
) == 0) {
864 // If the head Guard is not a tail Guard of adjacent memory block,
865 // free it; otherwise, keep it.
867 Start
-= EFI_PAGES_TO_SIZE (1);
872 // No Head Guard, and pages before memory to free are still in Guard. It's a
873 // partial free case. We need to keep one page to be a tail Guard.
875 Start
+= EFI_PAGES_TO_SIZE (1);
880 // Tail Guard must be the page after this memory block to free, if any.
883 // --------------------
884 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
885 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
886 // X 1 -> Don't free last page (need a new Guard)
887 // (it'll be turned into a Guard page later)
888 // --------------------
891 MemoryToTest
= Start
+ EFI_PAGES_TO_SIZE (PagesToFree
);
892 GuardBitmap
= GetGuardedMemoryBits (MemoryToTest
, 2);
893 if ((GuardBitmap
& BIT0
) == 0) {
895 // Tail Guard exists.
897 if ((GuardBitmap
& BIT1
) == 0) {
899 // If the tail Guard is not a head Guard of adjacent memory block,
900 // free it; otherwise, keep it.
904 } else if (PagesToFree
> 0) {
906 // No Tail Guard, and pages after memory to free are still in Guard. It's a
907 // partial free case. We need to keep one page to be a head Guard.
913 *NumberOfPages
= PagesToFree
;
918 Adjust the pool head position to make sure the Guard page is adjavent to
919 pool tail or pool head.
921 @param[in] Memory Base address of memory allocated.
922 @param[in] NoPages Number of pages actually allocated.
923 @param[in] Size Size of memory requested.
924 (plus pool head/tail overhead)
926 @return Address of pool head
930 IN EFI_PHYSICAL_ADDRESS Memory
,
935 if (Memory
== 0 || (PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
937 // Pool head is put near the head Guard
939 return (VOID
*)(UINTN
)Memory
;
943 // Pool head is put near the tail Guard
945 Size
= ALIGN_VALUE (Size
, 8);
946 return (VOID
*)(UINTN
)(Memory
+ EFI_PAGES_TO_SIZE (NoPages
) - Size
);
950 Get the page base address according to pool head address.
952 @param[in] Memory Head address of pool to free.
954 @return Address of pool head.
958 IN EFI_PHYSICAL_ADDRESS Memory
961 if (Memory
== 0 || (PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
963 // Pool head is put near the head Guard
965 return (VOID
*)(UINTN
)Memory
;
969 // Pool head is put near the tail Guard
971 return (VOID
*)(UINTN
)(Memory
& ~EFI_PAGE_MASK
);
975 Helper function of memory allocation with Guard pages.
977 @param FreePageList The free page node.
978 @param NumberOfPages Number of pages to be allocated.
979 @param MaxAddress Request to allocate memory below this address.
980 @param MemoryType Type of memory requested.
982 @return Memory address of allocated pages.
985 InternalAllocMaxAddressWithGuard (
986 IN OUT LIST_ENTRY
*FreePageList
,
987 IN UINTN NumberOfPages
,
989 IN EFI_MEMORY_TYPE MemoryType
994 FREE_PAGE_LIST
*Pages
;
1000 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
;
1001 Node
= Node
->BackLink
) {
1002 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
1003 if (Pages
->NumberOfPages
>= NumberOfPages
&&
1004 (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
) {
1007 // We may need 1 or 2 more pages for Guard. Check it out.
1009 PagesToAlloc
= NumberOfPages
;
1010 TailGuard
= (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
);
1011 if (!IsGuardPage (TailGuard
)) {
1013 // Add one if no Guard at the end of current free memory block.
1019 HeadGuard
= (UINTN
)Pages
+
1020 EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
- PagesToAlloc
) -
1022 if (!IsGuardPage (HeadGuard
)) {
1024 // Add one if no Guard at the page before the address to allocate
1030 if (Pages
->NumberOfPages
< PagesToAlloc
) {
1031 // Not enough space to allocate memory with Guards? Try next block.
1035 Address
= InternalAllocPagesOnOneNode (Pages
, PagesToAlloc
, MaxAddress
);
1036 ConvertSmmMemoryMapEntry(MemoryType
, Address
, PagesToAlloc
, FALSE
);
1037 CoreFreeMemoryMapStack();
1038 if (HeadGuard
== 0) {
1039 // Don't pass the Guard page to user.
1040 Address
+= EFI_PAGE_SIZE
;
1042 SetGuardForMemory (Address
, NumberOfPages
);
1051 Helper function of memory free with Guard pages.
1053 @param[in] Memory Base address of memory being freed.
1054 @param[in] NumberOfPages The number of pages to free.
1055 @param[in] AddRegion If this memory is new added region.
1057 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
1058 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
1059 @return EFI_SUCCESS Pages successfully freed.
1062 SmmInternalFreePagesExWithGuard (
1063 IN EFI_PHYSICAL_ADDRESS Memory
,
1064 IN UINTN NumberOfPages
,
1065 IN BOOLEAN AddRegion
1068 EFI_PHYSICAL_ADDRESS MemoryToFree
;
1071 if (((Memory
& EFI_PAGE_MASK
) != 0) || (Memory
== 0) || (NumberOfPages
== 0)) {
1072 return EFI_INVALID_PARAMETER
;
1075 MemoryToFree
= Memory
;
1076 PagesToFree
= NumberOfPages
;
1078 AdjustMemoryF (&MemoryToFree
, &PagesToFree
);
1079 UnsetGuardForMemory (Memory
, NumberOfPages
);
1080 if (PagesToFree
== 0) {
1084 return SmmInternalFreePagesEx (MemoryToFree
, PagesToFree
, AddRegion
);
1088 Set all Guard pages which cannot be set during the non-SMM mode time.
1095 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1096 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1097 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1098 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1099 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1107 if (mGuardedMemoryMap
== 0 ||
1109 mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
) {
1113 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1114 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1116 SetMem (Tables
, sizeof(Tables
), 0);
1117 SetMem (Addresses
, sizeof(Addresses
), 0);
1118 SetMem (Indices
, sizeof(Indices
), 0);
1120 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1121 Tables
[Level
] = mGuardedMemoryMap
;
1126 DumpGuardedMemoryBitmap ();
1130 if (Indices
[Level
] > Entries
[Level
]) {
1135 TableEntry
= ((UINT64
*)(UINTN
)(Tables
[Level
]))[Indices
[Level
]];
1136 Address
= Addresses
[Level
];
1138 if (TableEntry
== 0) {
1142 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1145 Tables
[Level
] = TableEntry
;
1146 Addresses
[Level
] = Address
;
1154 while (Index
< GUARDED_HEAP_MAP_ENTRY_BITS
) {
1155 if ((TableEntry
& 1) == 1) {
1159 GuardPage
= Address
- EFI_PAGE_SIZE
;
1164 GuardPage
= Address
;
1171 if (GuardPage
!= 0) {
1172 SetGuardPage (GuardPage
);
1175 if (TableEntry
== 0) {
1179 TableEntry
= RShiftU64 (TableEntry
, 1);
1180 Address
+= EFI_PAGE_SIZE
;
1186 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1190 Indices
[Level
] += 1;
1191 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1192 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);
1198 Hook function used to set all Guard pages after entering SMM mode.
1201 SmmEntryPointMemoryManagementHook (
1207 if (mSmmMemoryAttribute
== NULL
) {
1208 Status
= SmmLocateProtocol (
1209 &gEdkiiSmmMemoryAttributeProtocolGuid
,
1211 (VOID
**)&mSmmMemoryAttribute
1213 if (!EFI_ERROR(Status
)) {
1214 SetAllGuardPages ();
1220 Helper function to convert a UINT64 value in binary to a string.
1222 @param[in] Value Value of a UINT64 integer.
1223 @param[out] BinString String buffer to contain the conversion result.
1230 OUT CHAR8
*BinString
1235 if (BinString
== NULL
) {
1239 for (Index
= 64; Index
> 0; --Index
) {
1240 BinString
[Index
- 1] = '0' + (Value
& 1);
1241 Value
= RShiftU64 (Value
, 1);
1243 BinString
[64] = '\0';
1247 Dump the guarded memory bit map.
1251 DumpGuardedMemoryBitmap (
1255 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1256 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1257 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1258 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1259 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1264 CHAR8 String
[GUARDED_HEAP_MAP_ENTRY_BITS
+ 1];
1268 if (mGuardedMemoryMap
== 0 ||
1270 mMapLevel
> GUARDED_HEAP_MAP_TABLE_DEPTH
) {
1274 Ruler1
= " 3 2 1 0";
1275 Ruler2
= "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1277 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "============================="
1278 " Guarded Memory Bitmap "
1279 "==============================\r\n"));
1280 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler1
));
1281 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler2
));
1283 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1284 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1286 SetMem (Indices
, sizeof(Indices
), 0);
1287 SetMem (Tables
, sizeof(Tables
), 0);
1288 SetMem (Addresses
, sizeof(Addresses
), 0);
1290 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1291 Tables
[Level
] = mGuardedMemoryMap
;
1296 if (Indices
[Level
] > Entries
[Level
]) {
1303 HEAP_GUARD_DEBUG_LEVEL
,
1304 "========================================="
1305 "=========================================\r\n"
1310 TableEntry
= ((UINT64
*)(UINTN
)Tables
[Level
])[Indices
[Level
]];
1311 Address
= Addresses
[Level
];
1313 if (TableEntry
== 0) {
1315 if (Level
== GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1316 if (RepeatZero
== 0) {
1317 Uint64ToBinString(TableEntry
, String
);
1318 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1319 } else if (RepeatZero
== 1) {
1320 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "... : ...\r\n"));
1325 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1328 Tables
[Level
] = TableEntry
;
1329 Addresses
[Level
] = Address
;
1338 Uint64ToBinString(TableEntry
, String
);
1339 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
]);
1356 Debug function used to verify if the Guard page is well set or not.
1358 @param[in] BaseAddress Address of memory to check.
1359 @param[in] NumberOfPages Size of memory in pages.
1361 @return TRUE The head Guard and tail Guard are both well set.
1362 @return FALSE The head Guard and/or tail Guard are not well set.
1366 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1367 IN UINTN NumberOfPages
1372 EFI_PHYSICAL_ADDRESS Address
;
1374 if (mSmmMemoryAttribute
== NULL
) {
1379 Address
= BaseAddress
- EFI_PAGE_SIZE
;
1380 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1381 mSmmMemoryAttribute
,
1386 if (EFI_ERROR (Status
) || (Attribute
& EFI_MEMORY_RP
) == 0) {
1387 DEBUG ((DEBUG_ERROR
, "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
1388 Address
, Attribute
));
1389 DumpGuardedMemoryBitmap ();
1394 Address
= BaseAddress
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
1395 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1396 mSmmMemoryAttribute
,
1401 if (EFI_ERROR (Status
) || (Attribute
& EFI_MEMORY_RP
) == 0) {
1402 DEBUG ((DEBUG_ERROR
, "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
1403 Address
, Attribute
));
1404 DumpGuardedMemoryBitmap ();