2 UEFI Heap Guard functions.
4 Copyright (c) 2017, 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 Result
= RShiftU64 ((*BitMap
), StartBit
) & (LShiftU64 (1, Msbs
) - 1);
197 Result
|= LShiftU64 ((*BitMap
) & (LShiftU64 (1, Lsbs
) - 1), Msbs
);
204 Helper function to allocate pages without Guard for internal uses.
206 @param[in] Pages Page number.
208 @return Address of memory allocated.
216 EFI_PHYSICAL_ADDRESS Memory
;
218 Status
= SmmInternalAllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
,
219 Pages
, &Memory
, FALSE
);
220 if (EFI_ERROR (Status
)) {
224 return (VOID
*)(UINTN
)Memory
;
228 Locate the pointer of bitmap from the guarded memory bitmap tables, which
229 covers the given Address.
231 @param[in] Address Start address to search the bitmap for.
232 @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
233 @param[out] BitMap Pointer to bitmap which covers the Address.
235 @return The bit number from given Address to the end of current map table.
238 FindGuardedMemoryMap (
239 IN EFI_PHYSICAL_ADDRESS Address
,
240 IN BOOLEAN AllocMapUnit
,
252 // Adjust current map table depth according to the address to access
254 while (mMapLevel
< GUARDED_HEAP_MAP_TABLE_DEPTH
258 mLevelShift
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1]
261 if (mGuardedMemoryMap
!= 0) {
262 Size
= (mLevelMask
[GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
- 1] + 1)
263 * GUARDED_HEAP_MAP_ENTRY_BYTES
;
264 MapMemory
= (UINT64
)(UINTN
)PageAlloc (EFI_SIZE_TO_PAGES (Size
));
265 ASSERT (MapMemory
!= 0);
267 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
269 *(UINT64
*)(UINTN
)MapMemory
= mGuardedMemoryMap
;
270 mGuardedMemoryMap
= MapMemory
;
277 GuardMap
= &mGuardedMemoryMap
;
278 for (Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
279 Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
;
282 if (*GuardMap
== 0) {
288 Size
= (mLevelMask
[Level
] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES
;
289 MapMemory
= (UINT64
)(UINTN
)PageAlloc (EFI_SIZE_TO_PAGES (Size
));
290 ASSERT (MapMemory
!= 0);
292 SetMem ((VOID
*)(UINTN
)MapMemory
, Size
, 0);
293 *GuardMap
= MapMemory
;
296 Index
= (UINTN
)RShiftU64 (Address
, mLevelShift
[Level
]);
297 Index
&= mLevelMask
[Level
];
298 GuardMap
= (UINT64
*)(UINTN
)((*GuardMap
) + Index
* sizeof (UINT64
));
302 BitsToUnitEnd
= GUARDED_HEAP_MAP_BITS
- GUARDED_HEAP_MAP_BIT_INDEX (Address
);
305 return BitsToUnitEnd
;
309 Set corresponding bits in bitmap table to 1 according to given memory range.
311 @param[in] Address Memory address to guard from.
312 @param[in] NumberOfPages Number of pages to guard.
318 SetGuardedMemoryBits (
319 IN EFI_PHYSICAL_ADDRESS Address
,
320 IN UINTN NumberOfPages
327 while (NumberOfPages
> 0) {
328 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, TRUE
, &BitMap
);
329 ASSERT (BitMap
!= NULL
);
331 if (NumberOfPages
> BitsToUnitEnd
) {
333 Bits
= BitsToUnitEnd
;
335 Bits
= NumberOfPages
;
338 SetBits (Address
, Bits
, BitMap
);
340 NumberOfPages
-= Bits
;
341 Address
+= EFI_PAGES_TO_SIZE (Bits
);
346 Clear corresponding bits in bitmap table according to given memory range.
348 @param[in] Address Memory address to unset from.
349 @param[in] NumberOfPages Number of pages to unset guard.
355 ClearGuardedMemoryBits (
356 IN EFI_PHYSICAL_ADDRESS Address
,
357 IN UINTN NumberOfPages
364 while (NumberOfPages
> 0) {
365 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, TRUE
, &BitMap
);
366 ASSERT (BitMap
!= NULL
);
368 if (NumberOfPages
> BitsToUnitEnd
) {
370 Bits
= BitsToUnitEnd
;
372 Bits
= NumberOfPages
;
375 ClearBits (Address
, Bits
, BitMap
);
377 NumberOfPages
-= Bits
;
378 Address
+= EFI_PAGES_TO_SIZE (Bits
);
383 Retrieve corresponding bits in bitmap table according to given memory range.
385 @param[in] Address Memory address to retrieve from.
386 @param[in] NumberOfPages Number of pages to retrieve.
391 GetGuardedMemoryBits (
392 IN EFI_PHYSICAL_ADDRESS Address
,
393 IN UINTN NumberOfPages
402 ASSERT (NumberOfPages
<= GUARDED_HEAP_MAP_ENTRY_BITS
);
406 while (NumberOfPages
> 0) {
407 BitsToUnitEnd
= FindGuardedMemoryMap (Address
, FALSE
, &BitMap
);
409 if (NumberOfPages
> BitsToUnitEnd
) {
411 Bits
= BitsToUnitEnd
;
413 Bits
= NumberOfPages
;
416 if (BitMap
!= NULL
) {
417 Result
|= LShiftU64 (GetBits (Address
, Bits
, BitMap
), Shift
);
421 NumberOfPages
-= Bits
;
422 Address
+= EFI_PAGES_TO_SIZE (Bits
);
429 Get bit value in bitmap table for the given address.
431 @param[in] Address The address to retrieve for.
438 IN EFI_PHYSICAL_ADDRESS Address
443 FindGuardedMemoryMap (Address
, FALSE
, &GuardMap
);
444 if (GuardMap
!= NULL
) {
445 if (RShiftU64 (*GuardMap
,
446 GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
)) & 1) {
455 Set the bit in bitmap table for the given address.
457 @param[in] Address The address to set for.
464 IN EFI_PHYSICAL_ADDRESS Address
470 FindGuardedMemoryMap (Address
, TRUE
, &GuardMap
);
471 if (GuardMap
!= NULL
) {
472 BitMask
= LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
));
473 *GuardMap
|= BitMask
;
478 Clear the bit in bitmap table for the given address.
480 @param[in] Address The address to clear for.
487 IN EFI_PHYSICAL_ADDRESS Address
493 FindGuardedMemoryMap (Address
, TRUE
, &GuardMap
);
494 if (GuardMap
!= NULL
) {
495 BitMask
= LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address
));
496 *GuardMap
&= ~BitMask
;
501 Check to see if the page at the given address is a Guard page or not.
503 @param[in] Address The address to check for.
505 @return TRUE The page at Address is a Guard page.
506 @return FALSE The page at Address is not a Guard page.
511 IN EFI_PHYSICAL_ADDRESS Address
516 BitMap
= GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 3);
517 return ((BitMap
== 0b001) || (BitMap
== 0b100) || (BitMap
== 0b101));
521 Check to see if the page at the given address is a head Guard page or not.
523 @param[in] Address The address to check for.
525 @return TRUE The page at Address is a head Guard page.
526 @return FALSE The page at Address is not a head Guard page.
531 IN EFI_PHYSICAL_ADDRESS Address
534 return (GetGuardedMemoryBits (Address
, 2) == 0b10);
538 Check to see if the page at the given address is a tail Guard page or not.
540 @param[in] Address The address to check for.
542 @return TRUE The page at Address is a tail Guard page.
543 @return FALSE The page at Address is not a tail Guard page.
548 IN EFI_PHYSICAL_ADDRESS Address
551 return (GetGuardedMemoryBits (Address
- EFI_PAGE_SIZE
, 2) == 0b01);
555 Check to see if the page at the given address is guarded or not.
557 @param[in] Address The address to check for.
559 @return TRUE The page at Address is guarded.
560 @return FALSE The page at Address is not guarded.
565 IN EFI_PHYSICAL_ADDRESS Address
568 return (GetGuardMapBit (Address
) == 1);
572 Set the page at the given address to be a Guard page.
574 This is done by changing the page table attribute to be NOT PRSENT.
576 @param[in] BaseAddress Page address to Guard at.
583 IN EFI_PHYSICAL_ADDRESS BaseAddress
586 if (mSmmMemoryAttribute
!= NULL
) {
588 mSmmMemoryAttribute
->SetMemoryAttributes (
599 Unset the Guard page at the given address to the normal memory.
601 This is done by changing the page table attribute to be PRSENT.
603 @param[in] BaseAddress Page address to Guard at.
610 IN EFI_PHYSICAL_ADDRESS BaseAddress
613 if (mSmmMemoryAttribute
!= NULL
) {
615 mSmmMemoryAttribute
->ClearMemoryAttributes (
626 Check to see if the memory at the given address should be guarded or not.
628 @param[in] MemoryType Memory type to check.
629 @param[in] AllocateType Allocation type to check.
630 @param[in] PageOrPool Indicate a page allocation or pool allocation.
633 @return TRUE The given type of memory should be guarded.
634 @return FALSE The given type of memory should not be guarded.
637 IsMemoryTypeToGuard (
638 IN EFI_MEMORY_TYPE MemoryType
,
639 IN EFI_ALLOCATE_TYPE AllocateType
,
646 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & PageOrPool
) == 0
648 || AllocateType
== AllocateAddress
) {
653 if ((PageOrPool
& GUARD_HEAP_TYPE_POOL
) != 0) {
654 ConfigBit
|= PcdGet64 (PcdHeapGuardPoolType
);
657 if ((PageOrPool
& GUARD_HEAP_TYPE_PAGE
) != 0) {
658 ConfigBit
|= PcdGet64 (PcdHeapGuardPageType
);
661 if (MemoryType
== EfiRuntimeServicesData
||
662 MemoryType
== EfiRuntimeServicesCode
) {
663 TestBit
= LShiftU64 (1, MemoryType
);
664 } else if (MemoryType
== EfiMaxMemoryType
) {
665 TestBit
= (UINT64
)-1;
670 return ((ConfigBit
& TestBit
) != 0);
674 Check to see if the pool at the given address should be guarded or not.
676 @param[in] MemoryType Pool type to check.
679 @return TRUE The given type of pool should be guarded.
680 @return FALSE The given type of pool should not be guarded.
684 IN EFI_MEMORY_TYPE MemoryType
687 return IsMemoryTypeToGuard (MemoryType
, AllocateAnyPages
,
688 GUARD_HEAP_TYPE_POOL
);
692 Check to see if the page at the given address should be guarded or not.
694 @param[in] MemoryType Page type to check.
695 @param[in] AllocateType Allocation type to check.
697 @return TRUE The given type of page should be guarded.
698 @return FALSE The given type of page should not be guarded.
702 IN EFI_MEMORY_TYPE MemoryType
,
703 IN EFI_ALLOCATE_TYPE AllocateType
706 return IsMemoryTypeToGuard (MemoryType
, AllocateType
, GUARD_HEAP_TYPE_PAGE
);
710 Check to see if the heap guard is enabled for page and/or pool allocation.
719 return IsMemoryTypeToGuard (EfiMaxMemoryType
, AllocateAnyPages
,
720 GUARD_HEAP_TYPE_POOL
|GUARD_HEAP_TYPE_PAGE
);
724 Set head Guard and tail Guard for the given memory range.
726 @param[in] Memory Base address of memory to set guard for.
727 @param[in] NumberOfPages Memory size in pages.
733 IN EFI_PHYSICAL_ADDRESS Memory
,
734 IN UINTN NumberOfPages
737 EFI_PHYSICAL_ADDRESS GuardPage
;
742 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
743 if (!IsGuardPage (GuardPage
)) {
744 SetGuardPage (GuardPage
);
748 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
749 if (!IsGuardPage (GuardPage
)) {
750 SetGuardPage (GuardPage
);
754 // Mark the memory range as Guarded
756 SetGuardedMemoryBits (Memory
, NumberOfPages
);
760 Unset head Guard and tail Guard for the given memory range.
762 @param[in] Memory Base address of memory to unset guard for.
763 @param[in] NumberOfPages Memory size in pages.
768 UnsetGuardForMemory (
769 IN EFI_PHYSICAL_ADDRESS Memory
,
770 IN UINTN NumberOfPages
773 EFI_PHYSICAL_ADDRESS GuardPage
;
775 if (NumberOfPages
== 0) {
780 // Head Guard must be one page before, if any.
782 GuardPage
= Memory
- EFI_PAGES_TO_SIZE (1);
783 if (IsHeadGuard (GuardPage
)) {
784 if (!IsMemoryGuarded (GuardPage
- EFI_PAGES_TO_SIZE (1))) {
786 // If the head Guard is not a tail Guard of adjacent memory block,
789 UnsetGuardPage (GuardPage
);
791 } else if (IsMemoryGuarded (GuardPage
)) {
793 // Pages before memory to free are still in Guard. It's a partial free
794 // case. Turn first page of memory block to free into a new Guard.
796 SetGuardPage (Memory
);
800 // Tail Guard must be the page after this memory block to free, if any.
802 GuardPage
= Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
803 if (IsTailGuard (GuardPage
)) {
804 if (!IsMemoryGuarded (GuardPage
+ EFI_PAGES_TO_SIZE (1))) {
806 // If the tail Guard is not a head Guard of adjacent memory block,
807 // free it; otherwise, keep it.
809 UnsetGuardPage (GuardPage
);
811 } else if (IsMemoryGuarded (GuardPage
)) {
813 // Pages after memory to free are still in Guard. It's a partial free
814 // case. We need to keep one page to be a head Guard.
816 SetGuardPage (GuardPage
- EFI_PAGES_TO_SIZE (1));
820 // No matter what, we just clear the mark of the Guarded memory.
822 ClearGuardedMemoryBits(Memory
, NumberOfPages
);
826 Adjust address of free memory according to existing and/or required Guard.
828 This function will check if there're existing Guard pages of adjacent
829 memory blocks, and try to use it as the Guard page of the memory to be
832 @param[in] Start Start address of free memory block.
833 @param[in] Size Size of free memory block.
834 @param[in] SizeRequested Size of memory to allocate.
836 @return The end address of memory block found.
837 @return 0 if no enough space for the required size of memory and its Guard.
843 IN UINT64 SizeRequested
848 Target
= Start
+ Size
- SizeRequested
;
851 // At least one more page needed for Guard page.
853 if (Size
< (SizeRequested
+ EFI_PAGES_TO_SIZE (1))) {
857 if (!IsGuardPage (Start
+ Size
)) {
858 // No Guard at tail to share. One more page is needed.
859 Target
-= EFI_PAGES_TO_SIZE (1);
863 if (Target
< Start
) {
868 if (Target
== Start
) {
869 if (!IsGuardPage (Target
- EFI_PAGES_TO_SIZE (1))) {
870 // No enough space for a new head Guard if no Guard at head to share.
875 // OK, we have enough pages for memory and its Guards. Return the End of the
877 return Target
+ SizeRequested
- 1;
881 Adjust the start address and number of pages to free according to Guard.
883 The purpose of this function is to keep the shared Guard page with adjacent
884 memory block if it's still in guard, or free it if no more sharing. Another
885 is to reserve pages as Guard pages in partial page free situation.
887 @param[in,out] Memory Base address of memory to free.
888 @param[in,out] NumberOfPages Size of memory to free.
894 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
895 IN OUT UINTN
*NumberOfPages
898 EFI_PHYSICAL_ADDRESS Start
;
899 EFI_PHYSICAL_ADDRESS MemoryToTest
;
902 if (Memory
== NULL
|| NumberOfPages
== NULL
|| *NumberOfPages
== 0) {
907 PagesToFree
= *NumberOfPages
;
910 // Head Guard must be one page before, if any.
912 MemoryToTest
= Start
- EFI_PAGES_TO_SIZE (1);
913 if (IsHeadGuard (MemoryToTest
)) {
914 if (!IsMemoryGuarded (MemoryToTest
- EFI_PAGES_TO_SIZE (1))) {
916 // If the head Guard is not a tail Guard of adjacent memory block,
917 // free it; otherwise, keep it.
919 Start
-= EFI_PAGES_TO_SIZE (1);
922 } else if (IsMemoryGuarded (MemoryToTest
)) {
924 // Pages before memory to free are still in Guard. It's a partial free
925 // case. We need to keep one page to be a tail Guard.
927 Start
+= EFI_PAGES_TO_SIZE (1);
932 // Tail Guard must be the page after this memory block to free, if any.
934 MemoryToTest
= Start
+ EFI_PAGES_TO_SIZE (PagesToFree
);
935 if (IsTailGuard (MemoryToTest
)) {
936 if (!IsMemoryGuarded (MemoryToTest
+ EFI_PAGES_TO_SIZE (1))) {
938 // If the tail Guard is not a head Guard of adjacent memory block,
939 // free it; otherwise, keep it.
943 } else if (IsMemoryGuarded (MemoryToTest
)) {
945 // Pages after memory to free are still in Guard. It's a partial free
946 // case. We need to keep one page to be a head Guard.
952 *NumberOfPages
= PagesToFree
;
956 Adjust the base and number of pages to really allocate according to Guard.
958 @param[in,out] Memory Base address of free memory.
959 @param[in,out] NumberOfPages Size of memory to allocate.
965 IN OUT EFI_PHYSICAL_ADDRESS
*Memory
,
966 IN OUT UINTN
*NumberOfPages
970 // FindFreePages() has already taken the Guard into account. It's safe to
971 // adjust the start address and/or number of pages here, to make sure that
972 // the Guards are also "allocated".
974 if (!IsGuardPage (*Memory
+ EFI_PAGES_TO_SIZE (*NumberOfPages
))) {
975 // No tail Guard, add one.
979 if (!IsGuardPage (*Memory
- EFI_PAGE_SIZE
)) {
980 // No head Guard, add one.
981 *Memory
-= EFI_PAGE_SIZE
;
987 Adjust the pool head position to make sure the Guard page is adjavent to
988 pool tail or pool head.
990 @param[in] Memory Base address of memory allocated.
991 @param[in] NoPages Number of pages actually allocated.
992 @param[in] Size Size of memory requested.
993 (plus pool head/tail overhead)
995 @return Address of pool head
999 IN EFI_PHYSICAL_ADDRESS Memory
,
1004 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
1006 // Pool head is put near the head Guard
1008 return (VOID
*)(UINTN
)Memory
;
1012 // Pool head is put near the tail Guard
1014 return (VOID
*)(UINTN
)(Memory
+ EFI_PAGES_TO_SIZE (NoPages
) - Size
);
1018 Get the page base address according to pool head address.
1020 @param[in] Memory Head address of pool to free.
1022 @return Address of pool head.
1026 IN EFI_PHYSICAL_ADDRESS Memory
1029 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) != 0) {
1031 // Pool head is put near the head Guard
1033 return (VOID
*)(UINTN
)Memory
;
1037 // Pool head is put near the tail Guard
1039 return (VOID
*)(UINTN
)(Memory
& ~EFI_PAGE_MASK
);
1043 Helper function of memory allocation with Guard pages.
1045 @param FreePageList The free page node.
1046 @param NumberOfPages Number of pages to be allocated.
1047 @param MaxAddress Request to allocate memory below this address.
1048 @param MemoryType Type of memory requested.
1050 @return Memory address of allocated pages.
1053 InternalAllocMaxAddressWithGuard (
1054 IN OUT LIST_ENTRY
*FreePageList
,
1055 IN UINTN NumberOfPages
,
1056 IN UINTN MaxAddress
,
1057 IN EFI_MEMORY_TYPE MemoryType
1062 FREE_PAGE_LIST
*Pages
;
1068 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
;
1069 Node
= Node
->BackLink
) {
1070 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
1071 if (Pages
->NumberOfPages
>= NumberOfPages
&&
1072 (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
) {
1075 // We may need 1 or 2 more pages for Guard. Check it out.
1077 PagesToAlloc
= NumberOfPages
;
1078 TailGuard
= (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
);
1079 if (!IsGuardPage (TailGuard
)) {
1081 // Add one if no Guard at the end of current free memory block.
1087 HeadGuard
= (UINTN
)Pages
+
1088 EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
- PagesToAlloc
) -
1090 if (!IsGuardPage (HeadGuard
)) {
1092 // Add one if no Guard at the page before the address to allocate
1098 if (Pages
->NumberOfPages
< PagesToAlloc
) {
1099 // Not enough space to allocate memory with Guards? Try next block.
1103 Address
= InternalAllocPagesOnOneNode (Pages
, PagesToAlloc
, MaxAddress
);
1104 ConvertSmmMemoryMapEntry(MemoryType
, Address
, PagesToAlloc
, FALSE
);
1105 CoreFreeMemoryMapStack();
1106 if (HeadGuard
== 0) {
1107 // Don't pass the Guard page to user.
1108 Address
+= EFI_PAGE_SIZE
;
1110 SetGuardForMemory (Address
, NumberOfPages
);
1119 Helper function of memory free with Guard pages.
1121 @param[in] Memory Base address of memory being freed.
1122 @param[in] NumberOfPages The number of pages to free.
1123 @param[in] AddRegion If this memory is new added region.
1125 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
1126 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
1127 @return EFI_SUCCESS Pages successfully freed.
1130 SmmInternalFreePagesExWithGuard (
1131 IN EFI_PHYSICAL_ADDRESS Memory
,
1132 IN UINTN NumberOfPages
,
1133 IN BOOLEAN AddRegion
1136 EFI_PHYSICAL_ADDRESS MemoryToFree
;
1139 MemoryToFree
= Memory
;
1140 PagesToFree
= NumberOfPages
;
1142 AdjustMemoryF (&MemoryToFree
, &PagesToFree
);
1143 UnsetGuardForMemory (Memory
, NumberOfPages
);
1145 return SmmInternalFreePagesEx (MemoryToFree
, PagesToFree
, AddRegion
);
1149 Set all Guard pages which cannot be set during the non-SMM mode time.
1156 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1157 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1158 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1159 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1160 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1168 if (mGuardedMemoryMap
== 0) {
1172 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1173 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1175 SetMem (Tables
, sizeof(Tables
), 0);
1176 SetMem (Addresses
, sizeof(Addresses
), 0);
1177 SetMem (Indices
, sizeof(Indices
), 0);
1179 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1180 Tables
[Level
] = mGuardedMemoryMap
;
1185 DumpGuardedMemoryBitmap ();
1189 if (Indices
[Level
] > Entries
[Level
]) {
1194 TableEntry
= ((UINT64
*)(UINTN
)(Tables
[Level
]))[Indices
[Level
]];
1195 Address
= Addresses
[Level
];
1197 if (TableEntry
== 0) {
1201 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1204 Tables
[Level
] = TableEntry
;
1205 Addresses
[Level
] = Address
;
1213 while (Index
< GUARDED_HEAP_MAP_ENTRY_BITS
) {
1214 if ((TableEntry
& 1) == 1) {
1218 GuardPage
= Address
- EFI_PAGE_SIZE
;
1223 GuardPage
= Address
;
1230 if (GuardPage
!= 0) {
1231 SetGuardPage (GuardPage
);
1234 if (TableEntry
== 0) {
1238 TableEntry
= RShiftU64 (TableEntry
, 1);
1239 Address
+= EFI_PAGE_SIZE
;
1245 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1249 Indices
[Level
] += 1;
1250 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1251 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);
1257 Hook function used to set all Guard pages after entering SMM mode.
1260 SmmEntryPointMemoryManagementHook (
1266 if (mSmmMemoryAttribute
== NULL
) {
1267 Status
= SmmLocateProtocol (
1268 &gEdkiiSmmMemoryAttributeProtocolGuid
,
1270 (VOID
**)&mSmmMemoryAttribute
1272 if (!EFI_ERROR(Status
)) {
1273 SetAllGuardPages ();
1279 Helper function to convert a UINT64 value in binary to a string.
1281 @param[in] Value Value of a UINT64 integer.
1282 @param[out] BinString String buffer to contain the conversion result.
1289 OUT CHAR8
*BinString
1294 if (BinString
== NULL
) {
1298 for (Index
= 64; Index
> 0; --Index
) {
1299 BinString
[Index
- 1] = '0' + (Value
& 1);
1300 Value
= RShiftU64 (Value
, 1);
1302 BinString
[64] = '\0';
1306 Dump the guarded memory bit map.
1310 DumpGuardedMemoryBitmap (
1314 UINTN Entries
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1315 UINTN Shifts
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1316 UINTN Indices
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1317 UINT64 Tables
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1318 UINT64 Addresses
[GUARDED_HEAP_MAP_TABLE_DEPTH
];
1323 CHAR8 String
[GUARDED_HEAP_MAP_ENTRY_BITS
+ 1];
1327 if (mGuardedMemoryMap
== 0) {
1331 Ruler1
= " 3 2 1 0";
1332 Ruler2
= "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1334 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "============================="
1335 " Guarded Memory Bitmap "
1336 "==============================\r\n"));
1337 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler1
));
1338 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, " %a\r\n", Ruler2
));
1340 CopyMem (Entries
, mLevelMask
, sizeof (Entries
));
1341 CopyMem (Shifts
, mLevelShift
, sizeof (Shifts
));
1343 SetMem (Indices
, sizeof(Indices
), 0);
1344 SetMem (Tables
, sizeof(Tables
), 0);
1345 SetMem (Addresses
, sizeof(Addresses
), 0);
1347 Level
= GUARDED_HEAP_MAP_TABLE_DEPTH
- mMapLevel
;
1348 Tables
[Level
] = mGuardedMemoryMap
;
1353 if (Indices
[Level
] > Entries
[Level
]) {
1360 HEAP_GUARD_DEBUG_LEVEL
,
1361 "========================================="
1362 "=========================================\r\n"
1367 TableEntry
= ((UINT64
*)(UINTN
)Tables
[Level
])[Indices
[Level
]];
1368 Address
= Addresses
[Level
];
1370 if (TableEntry
== 0) {
1372 if (Level
== GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1373 if (RepeatZero
== 0) {
1374 Uint64ToBinString(TableEntry
, String
);
1375 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1376 } else if (RepeatZero
== 1) {
1377 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "... : ...\r\n"));
1382 } else if (Level
< GUARDED_HEAP_MAP_TABLE_DEPTH
- 1) {
1385 Tables
[Level
] = TableEntry
;
1386 Addresses
[Level
] = Address
;
1395 Uint64ToBinString(TableEntry
, String
);
1396 DEBUG ((HEAP_GUARD_DEBUG_LEVEL
, "%016lx: %a\r\n", Address
, String
));
1401 if (Level
< (GUARDED_HEAP_MAP_TABLE_DEPTH
- (INTN
)mMapLevel
)) {
1405 Indices
[Level
] += 1;
1406 Address
= (Level
== 0) ? 0 : Addresses
[Level
- 1];
1407 Addresses
[Level
] = Address
| LShiftU64(Indices
[Level
], Shifts
[Level
]);
1413 Debug function used to verify if the Guard page is well set or not.
1415 @param[in] BaseAddress Address of memory to check.
1416 @param[in] NumberOfPages Size of memory in pages.
1418 @return TRUE The head Guard and tail Guard are both well set.
1419 @return FALSE The head Guard and/or tail Guard are not well set.
1423 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1424 IN UINTN NumberOfPages
1429 EFI_PHYSICAL_ADDRESS Address
;
1431 if (mSmmMemoryAttribute
== NULL
) {
1436 Address
= BaseAddress
- EFI_PAGE_SIZE
;
1437 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1438 mSmmMemoryAttribute
,
1443 if (EFI_ERROR (Status
) || (Attribute
& EFI_MEMORY_RP
) == 0) {
1444 DEBUG ((DEBUG_ERROR
, "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
1445 Address
, Attribute
));
1446 DumpGuardedMemoryBitmap ();
1451 Address
= BaseAddress
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
1452 Status
= mSmmMemoryAttribute
->GetMemoryAttributes (
1453 mSmmMemoryAttribute
,
1458 if (EFI_ERROR (Status
) || (Attribute
& EFI_MEMORY_RP
) == 0) {
1459 DEBUG ((DEBUG_ERROR
, "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
1460 Address
, Attribute
));
1461 DumpGuardedMemoryBitmap ();