TianoCore EDK2 master
Loading...
Searching...
No Matches
HeapGuard.c
Go to the documentation of this file.
1
9#include "HeapGuard.h"
10
11//
12// Global to avoid infinite reentrance of memory allocation when updating
13// page table attributes, which may need allocating pages for new PDE/PTE.
14//
15GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
16
17//
18// Pointer to table tracking the Guarded memory with bitmap, in which '1'
19// is used to indicate memory guarded. '0' might be free memory or Guard
20// page itself, depending on status of memory adjacent to it.
21//
22GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
23
24//
25// Current depth level of map table pointed by mGuardedMemoryMap.
26// mMapLevel must be initialized at least by 1. It will be automatically
27// updated according to the address of memory just tracked.
28//
30
31//
32// Shift and mask for each level of map table
33//
34GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
35 = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
36GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
37 = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
38
39//
40// SMM memory attribute protocol
41//
42EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *mSmmMemoryAttribute = NULL;
43
54VOID
57 IN UINTN BitNumber,
58 IN UINT64 *BitMap
59 )
60{
61 UINTN Lsbs;
62 UINTN Qwords;
63 UINTN Msbs;
64 UINTN StartBit;
65 UINTN EndBit;
66
67 StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
68 EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
69
70 if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
71 Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
72 GUARDED_HEAP_MAP_ENTRY_BITS;
73 Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
74 Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
75 } else {
76 Msbs = BitNumber;
77 Lsbs = 0;
78 Qwords = 0;
79 }
80
81 if (Msbs > 0) {
82 *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
83 BitMap += 1;
84 }
85
86 if (Qwords > 0) {
87 SetMem64 (
88 (VOID *)BitMap,
89 Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
90 (UINT64)-1
91 );
92 BitMap += Qwords;
93 }
94
95 if (Lsbs > 0) {
96 *BitMap |= (LShiftU64 (1, Lsbs) - 1);
97 }
98}
99
109STATIC
110VOID
112 IN EFI_PHYSICAL_ADDRESS Address,
113 IN UINTN BitNumber,
114 IN UINT64 *BitMap
115 )
116{
117 UINTN Lsbs;
118 UINTN Qwords;
119 UINTN Msbs;
120 UINTN StartBit;
121 UINTN EndBit;
122
123 StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
124 EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
125
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;
131 } else {
132 Msbs = BitNumber;
133 Lsbs = 0;
134 Qwords = 0;
135 }
136
137 if (Msbs > 0) {
138 *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
139 BitMap += 1;
140 }
141
142 if (Qwords > 0) {
143 SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
144 BitMap += Qwords;
145 }
146
147 if (Lsbs > 0) {
148 *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
149 }
150}
151
164STATIC
165UINT64
167 IN EFI_PHYSICAL_ADDRESS Address,
168 IN UINTN BitNumber,
169 IN UINT64 *BitMap
170 )
171{
172 UINTN StartBit;
173 UINTN EndBit;
174 UINTN Lsbs;
175 UINTN Msbs;
176 UINT64 Result;
177
178 ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
179
180 StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
181 EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
182
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;
186 } else {
187 Msbs = BitNumber;
188 Lsbs = 0;
189 }
190
191 if ((StartBit == 0) && (BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS)) {
192 Result = *BitMap;
193 } else {
194 Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);
195 if (Lsbs > 0) {
196 BitMap += 1;
197 Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
198 }
199 }
200
201 return Result;
202}
203
211VOID *
213 IN UINTN Pages
214 )
215{
216 EFI_STATUS Status;
218
219 Status = SmmInternalAllocatePages (
222 Pages,
223 &Memory,
224 FALSE
225 );
226 if (EFI_ERROR (Status)) {
227 Memory = 0;
228 }
229
230 return (VOID *)(UINTN)Memory;
231}
232
243UINTN
245 IN EFI_PHYSICAL_ADDRESS Address,
246 IN BOOLEAN AllocMapUnit,
247 OUT UINT64 **BitMap
248 )
249{
250 UINTN Level;
251 UINT64 *GuardMap;
252 UINT64 MapMemory;
253 UINTN Index;
254 UINTN Size;
255 UINTN BitsToUnitEnd;
256
257 //
258 // Adjust current map table depth according to the address to access
259 //
260 while (AllocMapUnit &&
261 mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
262 RShiftU64 (
263 Address,
264 mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
265 ) != 0)
266 {
267 if (mGuardedMemoryMap != 0) {
268 Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
269 * GUARDED_HEAP_MAP_ENTRY_BYTES;
270 MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size));
271 if (MapMemory == 0) {
272 ASSERT (MapMemory != 0);
273 return 0;
274 }
275
276 SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
277
278 *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
279 mGuardedMemoryMap = MapMemory;
280 }
281
282 mMapLevel++;
283 }
284
285 GuardMap = &mGuardedMemoryMap;
286 for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
287 Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
288 ++Level)
289 {
290 if (*GuardMap == 0) {
291 if (!AllocMapUnit) {
292 GuardMap = NULL;
293 break;
294 }
295
296 Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
297 MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size));
298 ASSERT (MapMemory != 0);
299
300 SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
301 *GuardMap = MapMemory;
302 }
303
304 Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
305 Index &= mLevelMask[Level];
306 GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
307 }
308
309 BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
310 *BitMap = GuardMap;
311
312 return BitsToUnitEnd;
313}
314
323VOID
324EFIAPI
326 IN EFI_PHYSICAL_ADDRESS Address,
327 IN UINTN NumberOfPages
328 )
329{
330 UINT64 *BitMap;
331 UINTN Bits;
332 UINTN BitsToUnitEnd;
333
334 while (NumberOfPages > 0) {
335 BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
336 ASSERT (BitMap != NULL);
337
338 if (NumberOfPages > BitsToUnitEnd) {
339 // Cross map unit
340 Bits = BitsToUnitEnd;
341 } else {
342 Bits = NumberOfPages;
343 }
344
345 SetBits (Address, Bits, BitMap);
346
347 NumberOfPages -= Bits;
348 Address += EFI_PAGES_TO_SIZE (Bits);
349 }
350}
351
360VOID
361EFIAPI
363 IN EFI_PHYSICAL_ADDRESS Address,
364 IN UINTN NumberOfPages
365 )
366{
367 UINT64 *BitMap;
368 UINTN Bits;
369 UINTN BitsToUnitEnd;
370
371 while (NumberOfPages > 0) {
372 BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
373 ASSERT (BitMap != NULL);
374
375 if (NumberOfPages > BitsToUnitEnd) {
376 // Cross map unit
377 Bits = BitsToUnitEnd;
378 } else {
379 Bits = NumberOfPages;
380 }
381
382 ClearBits (Address, Bits, BitMap);
383
384 NumberOfPages -= Bits;
385 Address += EFI_PAGES_TO_SIZE (Bits);
386 }
387}
388
397UINTN
399 IN EFI_PHYSICAL_ADDRESS Address,
400 IN UINTN NumberOfPages
401 )
402{
403 UINT64 *BitMap;
404 UINTN Bits;
405 UINTN Result;
406 UINTN Shift;
407 UINTN BitsToUnitEnd;
408
409 ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
410
411 Result = 0;
412 Shift = 0;
413 while (NumberOfPages > 0) {
414 BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
415
416 if (NumberOfPages > BitsToUnitEnd) {
417 // Cross map unit
418 Bits = BitsToUnitEnd;
419 } else {
420 Bits = NumberOfPages;
421 }
422
423 if (BitMap != NULL) {
424 Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
425 }
426
427 Shift += Bits;
428 NumberOfPages -= Bits;
429 Address += EFI_PAGES_TO_SIZE (Bits);
430 }
431
432 return Result;
433}
434
442UINTN
443EFIAPI
446 )
447{
448 UINT64 *GuardMap;
449
450 FindGuardedMemoryMap (Address, FALSE, &GuardMap);
451 if (GuardMap != NULL) {
452 if (RShiftU64 (
453 *GuardMap,
454 GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)
455 ) & 1)
456 {
457 return 1;
458 }
459 }
460
461 return 0;
462}
463
472BOOLEAN
473EFIAPI
476 )
477{
478 UINTN BitMap;
479
480 //
481 // There must be at least one guarded page before and/or after given
482 // address if it's a Guard page. The bitmap pattern should be one of
483 // 001, 100 and 101
484 //
485 BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
486 return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
487}
488
497BOOLEAN
498EFIAPI
501 )
502{
503 return (GetGuardMapBit (Address) == 1);
504}
505
515VOID
516EFIAPI
518 IN EFI_PHYSICAL_ADDRESS BaseAddress
519 )
520{
521 EFI_STATUS Status;
522
523 if (mSmmMemoryAttribute != NULL) {
524 mOnGuarding = TRUE;
525 Status = mSmmMemoryAttribute->SetMemoryAttributes (
526 mSmmMemoryAttribute,
527 BaseAddress,
528 EFI_PAGE_SIZE,
529 EFI_MEMORY_RP
530 );
531 ASSERT_EFI_ERROR (Status);
532 mOnGuarding = FALSE;
533 }
534}
535
545VOID
546EFIAPI
548 IN EFI_PHYSICAL_ADDRESS BaseAddress
549 )
550{
551 EFI_STATUS Status;
552
553 if (mSmmMemoryAttribute != NULL) {
554 mOnGuarding = TRUE;
555 Status = mSmmMemoryAttribute->ClearMemoryAttributes (
556 mSmmMemoryAttribute,
557 BaseAddress,
558 EFI_PAGE_SIZE,
559 EFI_MEMORY_RP|EFI_MEMORY_RO|EFI_MEMORY_XP
560 );
561 ASSERT_EFI_ERROR (Status);
562
563 if (gST == NULL) {
564 //
565 // Make sure EfiConventionalMemory is NX after SmmReadyToLock
566 //
567 Status = mSmmMemoryAttribute->SetMemoryAttributes (
568 mSmmMemoryAttribute,
569 BaseAddress,
570 EFI_PAGE_SIZE,
571 EFI_MEMORY_XP
572 );
573 ASSERT_EFI_ERROR (Status);
574 }
575
576 mOnGuarding = FALSE;
577 }
578}
579
591BOOLEAN
593 IN EFI_MEMORY_TYPE MemoryType,
594 IN EFI_ALLOCATE_TYPE AllocateType,
595 IN UINT8 PageOrPool
596 )
597{
598 UINT64 TestBit;
599 UINT64 ConfigBit;
600
601 if ( ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0)
602 || mOnGuarding
603 || (AllocateType == AllocateAddress))
604 {
605 return FALSE;
606 }
607
608 ConfigBit = 0;
609 if ((PageOrPool & GUARD_HEAP_TYPE_POOL) != 0) {
610 ConfigBit |= PcdGet64 (PcdHeapGuardPoolType);
611 }
612
613 if ((PageOrPool & GUARD_HEAP_TYPE_PAGE) != 0) {
614 ConfigBit |= PcdGet64 (PcdHeapGuardPageType);
615 }
616
617 if ((MemoryType == EfiRuntimeServicesData) ||
618 (MemoryType == EfiRuntimeServicesCode))
619 {
620 TestBit = LShiftU64 (1, MemoryType);
621 } else if (MemoryType == EfiMaxMemoryType) {
622 TestBit = (UINT64)-1;
623 } else {
624 TestBit = 0;
625 }
626
627 return ((ConfigBit & TestBit) != 0);
628}
629
639BOOLEAN
641 IN EFI_MEMORY_TYPE MemoryType
642 )
643{
644 return IsMemoryTypeToGuard (
645 MemoryType,
647 GUARD_HEAP_TYPE_POOL
648 );
649}
650
660BOOLEAN
662 IN EFI_MEMORY_TYPE MemoryType,
663 IN EFI_ALLOCATE_TYPE AllocateType
664 )
665{
666 return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
667}
668
674BOOLEAN
676 VOID
677 )
678{
679 return IsMemoryTypeToGuard (
680 EfiMaxMemoryType,
682 GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_PAGE
683 );
684}
685
694VOID
697 IN UINTN NumberOfPages
698 )
699{
700 EFI_PHYSICAL_ADDRESS GuardPage;
701
702 //
703 // Set tail Guard
704 //
705 GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
706 if (!IsGuardPage (GuardPage)) {
707 SetGuardPage (GuardPage);
708 }
709
710 // Set head Guard
711 GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
712 if (!IsGuardPage (GuardPage)) {
713 SetGuardPage (GuardPage);
714 }
715
716 //
717 // Mark the memory range as Guarded
718 //
719 SetGuardedMemoryBits (Memory, NumberOfPages);
720}
721
730VOID
733 IN UINTN NumberOfPages
734 )
735{
736 EFI_PHYSICAL_ADDRESS GuardPage;
737 UINT64 GuardBitmap;
738
739 if (NumberOfPages == 0) {
740 return;
741 }
742
743 //
744 // Head Guard must be one page before, if any.
745 //
746 // MSB-> 1 0 <-LSB
747 // -------------------
748 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
749 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
750 // 1 X -> Don't free first page (need a new Guard)
751 // (it'll be turned into a Guard page later)
752 // -------------------
753 // Start -> -1 -2
754 //
755 GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
756 GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
757 if ((GuardBitmap & BIT1) == 0) {
758 //
759 // Head Guard exists.
760 //
761 if ((GuardBitmap & BIT0) == 0) {
762 //
763 // If the head Guard is not a tail Guard of adjacent memory block,
764 // unset it.
765 //
766 UnsetGuardPage (GuardPage);
767 }
768 } else {
769 //
770 // Pages before memory to free are still in Guard. It's a partial free
771 // case. Turn first page of memory block to free into a new Guard.
772 //
773 SetGuardPage (Memory);
774 }
775
776 //
777 // Tail Guard must be the page after this memory block to free, if any.
778 //
779 // MSB-> 1 0 <-LSB
780 // --------------------
781 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
782 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
783 // X 1 -> Don't free last page (need a new Guard)
784 // (it'll be turned into a Guard page later)
785 // --------------------
786 // +1 +0 <- End
787 //
788 GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
789 GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
790 if ((GuardBitmap & BIT0) == 0) {
791 //
792 // Tail Guard exists.
793 //
794 if ((GuardBitmap & BIT1) == 0) {
795 //
796 // If the tail Guard is not a head Guard of adjacent memory block,
797 // free it; otherwise, keep it.
798 //
799 UnsetGuardPage (GuardPage);
800 }
801 } else {
802 //
803 // Pages after memory to free are still in Guard. It's a partial free
804 // case. We need to keep one page to be a head Guard.
805 //
806 SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
807 }
808
809 //
810 // No matter what, we just clear the mark of the Guarded memory.
811 //
812 ClearGuardedMemoryBits (Memory, NumberOfPages);
813}
814
827VOID
830 IN OUT UINTN *NumberOfPages
831 )
832{
834 EFI_PHYSICAL_ADDRESS MemoryToTest;
835 UINTN PagesToFree;
836 UINT64 GuardBitmap;
837 UINT64 Attributes;
838
839 if ((Memory == NULL) || (NumberOfPages == NULL) || (*NumberOfPages == 0)) {
840 return;
841 }
842
843 Start = *Memory;
844 PagesToFree = *NumberOfPages;
845
846 //
847 // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).
848 //
849 if (mSmmMemoryAttribute != NULL) {
850 Attributes = 0;
851 mSmmMemoryAttribute->GetMemoryAttributes (
852 mSmmMemoryAttribute,
853 Start,
854 EFI_PAGES_TO_SIZE (PagesToFree),
855 &Attributes
856 );
857 if ((Attributes & EFI_MEMORY_RO) != 0) {
858 mSmmMemoryAttribute->ClearMemoryAttributes (
859 mSmmMemoryAttribute,
860 Start,
861 EFI_PAGES_TO_SIZE (PagesToFree),
862 EFI_MEMORY_RO
863 );
864 }
865 }
866
867 //
868 // Head Guard must be one page before, if any.
869 //
870 // MSB-> 1 0 <-LSB
871 // -------------------
872 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
873 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
874 // 1 X -> Don't free first page (need a new Guard)
875 // (it'll be turned into a Guard page later)
876 // -------------------
877 // Start -> -1 -2
878 //
879 MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
880 GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
881 if ((GuardBitmap & BIT1) == 0) {
882 //
883 // Head Guard exists.
884 //
885 if ((GuardBitmap & BIT0) == 0) {
886 //
887 // If the head Guard is not a tail Guard of adjacent memory block,
888 // free it; otherwise, keep it.
889 //
890 Start -= EFI_PAGES_TO_SIZE (1);
891 PagesToFree += 1;
892 }
893 } else {
894 //
895 // No Head Guard, and pages before memory to free are still in Guard. It's a
896 // partial free case. We need to keep one page to be a tail Guard.
897 //
898 Start += EFI_PAGES_TO_SIZE (1);
899 PagesToFree -= 1;
900 }
901
902 //
903 // Tail Guard must be the page after this memory block to free, if any.
904 //
905 // MSB-> 1 0 <-LSB
906 // --------------------
907 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
908 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
909 // X 1 -> Don't free last page (need a new Guard)
910 // (it'll be turned into a Guard page later)
911 // --------------------
912 // +1 +0 <- End
913 //
914 MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
915 GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
916 if ((GuardBitmap & BIT0) == 0) {
917 //
918 // Tail Guard exists.
919 //
920 if ((GuardBitmap & BIT1) == 0) {
921 //
922 // If the tail Guard is not a head Guard of adjacent memory block,
923 // free it; otherwise, keep it.
924 //
925 PagesToFree += 1;
926 }
927 } else if (PagesToFree > 0) {
928 //
929 // No Tail Guard, and pages after memory to free are still in Guard. It's a
930 // partial free case. We need to keep one page to be a head Guard.
931 //
932 PagesToFree -= 1;
933 }
934
935 *Memory = Start;
936 *NumberOfPages = PagesToFree;
937}
938
950VOID *
953 IN UINTN NoPages,
954 IN UINTN Size
955 )
956{
957 if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) {
958 //
959 // Pool head is put near the head Guard
960 //
961 return (VOID *)(UINTN)Memory;
962 }
963
964 //
965 // Pool head is put near the tail Guard
966 //
967 Size = ALIGN_VALUE (Size, 8);
968 return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
969}
970
978VOID *
981 )
982{
983 if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) {
984 //
985 // Pool head is put near the head Guard
986 //
987 return (VOID *)(UINTN)Memory;
988 }
989
990 //
991 // Pool head is put near the tail Guard
992 //
993 return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK);
994}
995
1006UINTN
1008 IN OUT LIST_ENTRY *FreePageList,
1009 IN UINTN NumberOfPages,
1010 IN UINTN MaxAddress,
1011 IN EFI_MEMORY_TYPE MemoryType
1012
1013 )
1014{
1015 LIST_ENTRY *Node;
1016 FREE_PAGE_LIST *Pages;
1017 UINTN PagesToAlloc;
1018 UINTN HeadGuard;
1019 UINTN TailGuard;
1020 UINTN Address;
1021
1022 for (Node = FreePageList->BackLink; Node != FreePageList;
1023 Node = Node->BackLink)
1024 {
1025 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
1026 if ((Pages->NumberOfPages >= NumberOfPages) &&
1027 ((UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress))
1028 {
1029 //
1030 // We may need 1 or 2 more pages for Guard. Check it out.
1031 //
1032 PagesToAlloc = NumberOfPages;
1033 TailGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
1034 if (!IsGuardPage (TailGuard)) {
1035 //
1036 // Add one if no Guard at the end of current free memory block.
1037 //
1038 PagesToAlloc += 1;
1039 TailGuard = 0;
1040 }
1041
1042 HeadGuard = (UINTN)Pages +
1043 EFI_PAGES_TO_SIZE (Pages->NumberOfPages - PagesToAlloc) -
1044 EFI_PAGE_SIZE;
1045 if (!IsGuardPage (HeadGuard)) {
1046 //
1047 // Add one if no Guard at the page before the address to allocate
1048 //
1049 PagesToAlloc += 1;
1050 HeadGuard = 0;
1051 }
1052
1053 if (Pages->NumberOfPages < PagesToAlloc) {
1054 // Not enough space to allocate memory with Guards? Try next block.
1055 continue;
1056 }
1057
1058 Address = InternalAllocPagesOnOneNode (Pages, PagesToAlloc, MaxAddress);
1059 ConvertSmmMemoryMapEntry (MemoryType, Address, PagesToAlloc, FALSE);
1061 if (HeadGuard == 0) {
1062 // Don't pass the Guard page to user.
1063 Address += EFI_PAGE_SIZE;
1064 }
1065
1066 SetGuardForMemory (Address, NumberOfPages);
1067 return Address;
1068 }
1069 }
1070
1071 return (UINTN)(-1);
1072}
1073
1087 IN EFI_PHYSICAL_ADDRESS Memory,
1088 IN UINTN NumberOfPages,
1089 IN BOOLEAN AddRegion
1090 )
1091{
1092 EFI_PHYSICAL_ADDRESS MemoryToFree;
1093 UINTN PagesToFree;
1094
1095 if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
1096 return EFI_INVALID_PARAMETER;
1097 }
1098
1099 MemoryToFree = Memory;
1100 PagesToFree = NumberOfPages;
1101
1102 AdjustMemoryF (&MemoryToFree, &PagesToFree);
1103 UnsetGuardForMemory (Memory, NumberOfPages);
1104 if (PagesToFree == 0) {
1105 return EFI_SUCCESS;
1106 }
1107
1108 return SmmInternalFreePagesEx (MemoryToFree, PagesToFree, AddRegion);
1109}
1110
1114VOID
1116 VOID
1117 )
1118{
1119 UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
1120 UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
1121 UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
1122 UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
1123 UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
1124 UINT64 TableEntry;
1125 UINT64 Address;
1126 UINT64 GuardPage;
1127 INTN Level;
1128 UINTN Index;
1129 BOOLEAN OnGuarding;
1130
1131 if ((mGuardedMemoryMap == 0) ||
1132 (mMapLevel == 0) ||
1133 (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
1134 {
1135 return;
1136 }
1137
1138 CopyMem (Entries, mLevelMask, sizeof (Entries));
1139 CopyMem (Shifts, mLevelShift, sizeof (Shifts));
1140
1141 SetMem (Tables, sizeof (Tables), 0);
1142 SetMem (Addresses, sizeof (Addresses), 0);
1143 SetMem (Indices, sizeof (Indices), 0);
1144
1145 Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
1146 Tables[Level] = mGuardedMemoryMap;
1147 Address = 0;
1148 OnGuarding = FALSE;
1149
1150 DEBUG_CODE (
1152 );
1153
1154 while (TRUE) {
1155 if (Indices[Level] > Entries[Level]) {
1156 Tables[Level] = 0;
1157 Level -= 1;
1158 } else {
1159 TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
1160 Address = Addresses[Level];
1161
1162 if (TableEntry == 0) {
1163 OnGuarding = FALSE;
1164 } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
1165 Level += 1;
1166 Tables[Level] = TableEntry;
1167 Addresses[Level] = Address;
1168 Indices[Level] = 0;
1169
1170 continue;
1171 } else {
1172 Index = 0;
1173 while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
1174 if ((TableEntry & 1) == 1) {
1175 if (OnGuarding) {
1176 GuardPage = 0;
1177 } else {
1178 GuardPage = Address - EFI_PAGE_SIZE;
1179 }
1180
1181 OnGuarding = TRUE;
1182 } else {
1183 if (OnGuarding) {
1184 GuardPage = Address;
1185 } else {
1186 GuardPage = 0;
1187 }
1188
1189 OnGuarding = FALSE;
1190 }
1191
1192 if (GuardPage != 0) {
1193 SetGuardPage (GuardPage);
1194 }
1195
1196 if (TableEntry == 0) {
1197 break;
1198 }
1199
1200 TableEntry = RShiftU64 (TableEntry, 1);
1201 Address += EFI_PAGE_SIZE;
1202 Index += 1;
1203 }
1204 }
1205 }
1206
1207 if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
1208 break;
1209 }
1210
1211 Indices[Level] += 1;
1212 Address = (Level == 0) ? 0 : Addresses[Level - 1];
1213 Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
1214 }
1215}
1216
1220VOID
1222 VOID
1223 )
1224{
1225 EFI_STATUS Status;
1226
1227 if (mSmmMemoryAttribute == NULL) {
1228 Status = SmmLocateProtocol (
1229 &gEdkiiSmmMemoryAttributeProtocolGuid,
1230 NULL,
1231 (VOID **)&mSmmMemoryAttribute
1232 );
1233 if (!EFI_ERROR (Status)) {
1235 }
1236 }
1237}
1238
1247VOID
1249 IN UINT64 Value,
1250 OUT CHAR8 *BinString
1251 )
1252{
1253 UINTN Index;
1254
1255 if (BinString == NULL) {
1256 return;
1257 }
1258
1259 for (Index = 64; Index > 0; --Index) {
1260 BinString[Index - 1] = '0' + (Value & 1);
1261 Value = RShiftU64 (Value, 1);
1262 }
1263
1264 BinString[64] = '\0';
1265}
1266
1270VOID
1271EFIAPI
1273 VOID
1274 )
1275{
1276 UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
1277 UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
1278 UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
1279 UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
1280 UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
1281 UINT64 TableEntry;
1282 UINT64 Address;
1283 INTN Level;
1284 UINTN RepeatZero;
1285 CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
1286 CHAR8 *Ruler1;
1287 CHAR8 *Ruler2;
1288
1289 if ((mGuardedMemoryMap == 0) ||
1290 (mMapLevel == 0) ||
1291 (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
1292 {
1293 return;
1294 }
1295
1296 Ruler1 = " 3 2 1 0";
1297 Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1298
1299 DEBUG ((
1300 HEAP_GUARD_DEBUG_LEVEL,
1301 "============================="
1302 " Guarded Memory Bitmap "
1303 "==============================\r\n"
1304 ));
1305 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
1306 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
1307
1308 CopyMem (Entries, mLevelMask, sizeof (Entries));
1309 CopyMem (Shifts, mLevelShift, sizeof (Shifts));
1310
1311 SetMem (Indices, sizeof (Indices), 0);
1312 SetMem (Tables, sizeof (Tables), 0);
1313 SetMem (Addresses, sizeof (Addresses), 0);
1314
1315 Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
1316 Tables[Level] = mGuardedMemoryMap;
1317 Address = 0;
1318 RepeatZero = 0;
1319
1320 while (TRUE) {
1321 if (Indices[Level] > Entries[Level]) {
1322 Tables[Level] = 0;
1323 Level -= 1;
1324 RepeatZero = 0;
1325
1326 DEBUG ((
1327 HEAP_GUARD_DEBUG_LEVEL,
1328 "========================================="
1329 "=========================================\r\n"
1330 ));
1331 } else {
1332 TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
1333 Address = Addresses[Level];
1334
1335 if (TableEntry == 0) {
1336 if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
1337 if (RepeatZero == 0) {
1338 Uint64ToBinString (TableEntry, String);
1339 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
1340 } else if (RepeatZero == 1) {
1341 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
1342 }
1343
1344 RepeatZero += 1;
1345 }
1346 } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
1347 Level += 1;
1348 Tables[Level] = TableEntry;
1349 Addresses[Level] = Address;
1350 Indices[Level] = 0;
1351 RepeatZero = 0;
1352
1353 continue;
1354 } else {
1355 RepeatZero = 0;
1356 Uint64ToBinString (TableEntry, String);
1357 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
1358 }
1359 }
1360
1361 if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
1362 break;
1363 }
1364
1365 Indices[Level] += 1;
1366 Address = (Level == 0) ? 0 : Addresses[Level - 1];
1367 Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
1368 }
1369}
1370
1380BOOLEAN
1382 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1383 IN UINTN NumberOfPages
1384 )
1385{
1386 EFI_STATUS Status;
1387 UINT64 Attribute;
1388 EFI_PHYSICAL_ADDRESS Address;
1389
1390 if (mSmmMemoryAttribute == NULL) {
1391 return TRUE;
1392 }
1393
1394 Attribute = 0;
1395 Address = BaseAddress - EFI_PAGE_SIZE;
1396 Status = mSmmMemoryAttribute->GetMemoryAttributes (
1397 mSmmMemoryAttribute,
1398 Address,
1399 EFI_PAGE_SIZE,
1400 &Attribute
1401 );
1402 if (EFI_ERROR (Status) || ((Attribute & EFI_MEMORY_RP) == 0)) {
1403 DEBUG ((
1404 DEBUG_ERROR,
1405 "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
1406 Address,
1407 Attribute
1408 ));
1410 return FALSE;
1411 }
1412
1413 Attribute = 0;
1414 Address = BaseAddress + EFI_PAGES_TO_SIZE (NumberOfPages);
1415 Status = mSmmMemoryAttribute->GetMemoryAttributes (
1416 mSmmMemoryAttribute,
1417 Address,
1418 EFI_PAGE_SIZE,
1419 &Attribute
1420 );
1421 if (EFI_ERROR (Status) || ((Attribute & EFI_MEMORY_RP) == 0)) {
1422 DEBUG ((
1423 DEBUG_ERROR,
1424 "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
1425 Address,
1426 Attribute
1427 ));
1429 return FALSE;
1430 }
1431
1432 return TRUE;
1433}
UINT64 UINTN
INT64 INTN
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID *EFIAPI SetMem64(OUT VOID *Buffer, IN UINTN Length, IN UINT64 Value)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
VOID SetGuardForMemory(IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages)
Definition: HeapGuard.c:690
UINTN EFIAPI GetGuardMapBit(IN EFI_PHYSICAL_ADDRESS Address)
Definition: HeapGuard.c:431
VOID AdjustMemoryF(IN OUT EFI_PHYSICAL_ADDRESS *Memory, IN OUT UINTN *NumberOfPages)
Definition: HeapGuard.c:884
VOID * AdjustPoolHeadF(IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NoPages, IN UINTN Size)
Definition: HeapGuard.c:1047
VOID SetAllGuardPages(VOID)
Definition: HeapGuard.c:1115
VOID EFIAPI DumpGuardedMemoryBitmap(VOID)
Definition: HeapGuard.c:1659
STATIC UINT64 GetBits(IN EFI_PHYSICAL_ADDRESS Address, IN UINTN BitNumber, IN UINT64 *BitMap)
Definition: HeapGuard.c:168
BOOLEAN EFIAPI IsGuardPage(IN EFI_PHYSICAL_ADDRESS Address)
Definition: HeapGuard.c:461
STATIC VOID ClearBits(IN EFI_PHYSICAL_ADDRESS Address, IN UINTN BitNumber, IN UINT64 *BitMap)
Definition: HeapGuard.c:113
VOID EFIAPI SetGuardPage(IN EFI_PHYSICAL_ADDRESS BaseAddress)
Definition: HeapGuard.c:504
VOID EFIAPI UnsetGuardPage(IN EFI_PHYSICAL_ADDRESS BaseAddress)
Definition: HeapGuard.c:539
VOID Uint64ToBinString(IN UINT64 Value, OUT CHAR8 *BinString)
Definition: HeapGuard.c:1635
UINT64 GetGuardedMemoryBits(IN EFI_PHYSICAL_ADDRESS Address, IN UINTN NumberOfPages)
Definition: HeapGuard.c:385
BOOLEAN IsHeapGuardEnabled(UINT8 GuardType)
Definition: HeapGuard.c:674
VOID UnsetGuardForMemory(IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages)
Definition: HeapGuard.c:726
STATIC VOID SetBits(IN EFI_PHYSICAL_ADDRESS Address, IN UINTN BitNumber, IN UINT64 *BitMap)
Definition: HeapGuard.c:57
BOOLEAN IsPoolTypeToGuard(IN EFI_MEMORY_TYPE MemoryType)
Definition: HeapGuard.c:637
VOID EFIAPI ClearGuardedMemoryBits(IN EFI_PHYSICAL_ADDRESS Address, IN UINTN NumberOfPages)
Definition: HeapGuard.c:349
BOOLEAN EFIAPI IsMemoryGuarded(IN EFI_PHYSICAL_ADDRESS Address)
Definition: HeapGuard.c:486
VOID EFIAPI SetGuardedMemoryBits(IN EFI_PHYSICAL_ADDRESS Address, IN UINTN NumberOfPages)
Definition: HeapGuard.c:312
BOOLEAN IsPageTypeToGuard(IN EFI_MEMORY_TYPE MemoryType, IN EFI_ALLOCATE_TYPE AllocateType)
Definition: HeapGuard.c:658
UINTN FindGuardedMemoryMap(IN EFI_PHYSICAL_ADDRESS Address, IN BOOLEAN AllocMapUnit, OUT UINT64 **BitMap)
Definition: HeapGuard.c:217
VOID * AdjustPoolHeadA(IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NoPages, IN UINTN Size)
Definition: HeapGuard.c:1016
BOOLEAN IsMemoryTypeToGuard(IN EFI_MEMORY_TYPE MemoryType, IN EFI_ALLOCATE_TYPE AllocateType, IN UINT8 PageOrPool)
Definition: HeapGuard.c:587
VOID CoreFreeMemoryMapStack(VOID)
Definition: Page.c:314
EFI_STATUS EFIAPI SmmLocateProtocol(IN EFI_GUID *Protocol, IN VOID *Registration OPTIONAL, OUT VOID **Interface)
Definition: Locate.c:194
UINTN InternalAllocPagesOnOneNode(IN OUT FREE_PAGE_LIST *Pages, IN UINTN NumberOfPages, IN UINTN MaxAddress)
Definition: Page.c:467
EFI_STATUS SmmInternalFreePagesEx(IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages, IN BOOLEAN AddRegion)
Definition: Page.c:801
VOID ConvertSmmMemoryMapEntry(IN EFI_MEMORY_TYPE Type, IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages, IN BOOLEAN AddRegion)
Definition: Page.c:260
EFI_STATUS EFIAPI SmmInternalAllocatePages(IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NumberOfPages, OUT EFI_PHYSICAL_ADDRESS *Memory, IN BOOLEAN NeedGuard)
Definition: Page.c:691
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define VOID
Definition: Base.h:269
#define ALIGN_VALUE(Value, Alignment)
Definition: Base.h:948
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define GLOBAL_REMOVE_IF_UNREFERENCED
Definition: Base.h:48
#define BASE_CR(Record, TYPE, Field)
Definition: Base.h:891
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:463
#define DEBUG(Expression)
Definition: DebugLib.h:435
#define DEBUG_CODE(Expression)
Definition: DebugLib.h:591
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
#define PcdGet8(TokenName)
Definition: PcdLib.h:336
VOID * PageAlloc(IN UINTN Pages)
Definition: HeapGuard.c:212
BOOLEAN VerifyMemoryGuard(IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINTN NumberOfPages)
Definition: HeapGuard.c:1381
UINTN InternalAllocMaxAddressWithGuard(IN OUT LIST_ENTRY *FreePageList, IN UINTN NumberOfPages, IN UINTN MaxAddress, IN EFI_MEMORY_TYPE MemoryType)
Definition: HeapGuard.c:1007
EFI_STATUS SmmInternalFreePagesExWithGuard(IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages, IN BOOLEAN AddRegion)
Definition: HeapGuard.c:1086
VOID SmmEntryPointMemoryManagementHook(VOID)
Definition: HeapGuard.c:1221
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_SYSTEM_TABLE * gST
EFI_MEMORY_TYPE
@ EfiRuntimeServicesCode
@ EfiRuntimeServicesData
EFI_ALLOCATE_TYPE
Definition: UefiSpec.h:29
@ AllocateAddress
Definition: UefiSpec.h:42
@ AllocateAnyPages
Definition: UefiSpec.h:33