]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/HeapGuard.c
MdeModulePkg/PiSmmCore: fix #PF caused by freeing read-only memory
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / HeapGuard.c
1 /** @file
2 UEFI Heap Guard functions.
3
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
9
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.
12
13 **/
14
15 #include "HeapGuard.h"
16
17 //
18 // Global to avoid infinite reentrance of memory allocation when updating
19 // page table attributes, which may need allocating pages for new PDE/PTE.
20 //
21 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
22
23 //
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.
27 //
28 GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
29
30 //
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.
34 //
35 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
36
37 //
38 // Shift and mask for each level of map table
39 //
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;
44
45 //
46 // SMM memory attribute protocol
47 //
48 EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *mSmmMemoryAttribute = NULL;
49
50 /**
51 Set corresponding bits in bitmap table to 1 according to the address.
52
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.
56
57 @return VOID
58 **/
59 STATIC
60 VOID
61 SetBits (
62 IN EFI_PHYSICAL_ADDRESS Address,
63 IN UINTN BitNumber,
64 IN UINT64 *BitMap
65 )
66 {
67 UINTN Lsbs;
68 UINTN Qwords;
69 UINTN Msbs;
70 UINTN StartBit;
71 UINTN EndBit;
72
73 StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
74 EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
75
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;
81 } else {
82 Msbs = BitNumber;
83 Lsbs = 0;
84 Qwords = 0;
85 }
86
87 if (Msbs > 0) {
88 *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
89 BitMap += 1;
90 }
91
92 if (Qwords > 0) {
93 SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
94 (UINT64)-1);
95 BitMap += Qwords;
96 }
97
98 if (Lsbs > 0) {
99 *BitMap |= (LShiftU64 (1, Lsbs) - 1);
100 }
101 }
102
103 /**
104 Set corresponding bits in bitmap table to 0 according to the address.
105
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.
109
110 @return VOID.
111 **/
112 STATIC
113 VOID
114 ClearBits (
115 IN EFI_PHYSICAL_ADDRESS Address,
116 IN UINTN BitNumber,
117 IN UINT64 *BitMap
118 )
119 {
120 UINTN Lsbs;
121 UINTN Qwords;
122 UINTN Msbs;
123 UINTN StartBit;
124 UINTN EndBit;
125
126 StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
127 EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
128
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;
134 } else {
135 Msbs = BitNumber;
136 Lsbs = 0;
137 Qwords = 0;
138 }
139
140 if (Msbs > 0) {
141 *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
142 BitMap += 1;
143 }
144
145 if (Qwords > 0) {
146 SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
147 BitMap += Qwords;
148 }
149
150 if (Lsbs > 0) {
151 *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
152 }
153 }
154
155 /**
156 Get corresponding bits in bitmap table according to the address.
157
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.
160
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.
164
165 @return An integer containing the bits information.
166 **/
167 STATIC
168 UINT64
169 GetBits (
170 IN EFI_PHYSICAL_ADDRESS Address,
171 IN UINTN BitNumber,
172 IN UINT64 *BitMap
173 )
174 {
175 UINTN StartBit;
176 UINTN EndBit;
177 UINTN Lsbs;
178 UINTN Msbs;
179 UINT64 Result;
180
181 ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
182
183 StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
184 EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
185
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;
189 } else {
190 Msbs = BitNumber;
191 Lsbs = 0;
192 }
193
194 if (StartBit == 0 && BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS) {
195 Result = *BitMap;
196 } else {
197 Result = RShiftU64((*BitMap), StartBit) & (LShiftU64(1, Msbs) - 1);
198 if (Lsbs > 0) {
199 BitMap += 1;
200 Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
201 }
202 }
203
204 return Result;
205 }
206
207 /**
208 Helper function to allocate pages without Guard for internal uses.
209
210 @param[in] Pages Page number.
211
212 @return Address of memory allocated.
213 **/
214 VOID *
215 PageAlloc (
216 IN UINTN Pages
217 )
218 {
219 EFI_STATUS Status;
220 EFI_PHYSICAL_ADDRESS Memory;
221
222 Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData,
223 Pages, &Memory, FALSE);
224 if (EFI_ERROR (Status)) {
225 Memory = 0;
226 }
227
228 return (VOID *)(UINTN)Memory;
229 }
230
231 /**
232 Locate the pointer of bitmap from the guarded memory bitmap tables, which
233 covers the given Address.
234
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.
238
239 @return The bit number from given Address to the end of current map table.
240 **/
241 UINTN
242 FindGuardedMemoryMap (
243 IN EFI_PHYSICAL_ADDRESS Address,
244 IN BOOLEAN AllocMapUnit,
245 OUT UINT64 **BitMap
246 )
247 {
248 UINTN Level;
249 UINT64 *GuardMap;
250 UINT64 MapMemory;
251 UINTN Index;
252 UINTN Size;
253 UINTN BitsToUnitEnd;
254
255 //
256 // Adjust current map table depth according to the address to access
257 //
258 while (AllocMapUnit &&
259 mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
260 RShiftU64 (
261 Address,
262 mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
263 ) != 0) {
264
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);
270
271 SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
272
273 *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
274 mGuardedMemoryMap = MapMemory;
275 }
276
277 mMapLevel++;
278
279 }
280
281 GuardMap = &mGuardedMemoryMap;
282 for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
283 Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
284 ++Level) {
285
286 if (*GuardMap == 0) {
287 if (!AllocMapUnit) {
288 GuardMap = NULL;
289 break;
290 }
291
292 Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
293 MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size));
294 ASSERT (MapMemory != 0);
295
296 SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
297 *GuardMap = MapMemory;
298 }
299
300 Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
301 Index &= mLevelMask[Level];
302 GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
303
304 }
305
306 BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
307 *BitMap = GuardMap;
308
309 return BitsToUnitEnd;
310 }
311
312 /**
313 Set corresponding bits in bitmap table to 1 according to given memory range.
314
315 @param[in] Address Memory address to guard from.
316 @param[in] NumberOfPages Number of pages to guard.
317
318 @return VOID
319 **/
320 VOID
321 EFIAPI
322 SetGuardedMemoryBits (
323 IN EFI_PHYSICAL_ADDRESS Address,
324 IN UINTN NumberOfPages
325 )
326 {
327 UINT64 *BitMap;
328 UINTN Bits;
329 UINTN BitsToUnitEnd;
330
331 while (NumberOfPages > 0) {
332 BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
333 ASSERT (BitMap != NULL);
334
335 if (NumberOfPages > BitsToUnitEnd) {
336 // Cross map unit
337 Bits = BitsToUnitEnd;
338 } else {
339 Bits = NumberOfPages;
340 }
341
342 SetBits (Address, Bits, BitMap);
343
344 NumberOfPages -= Bits;
345 Address += EFI_PAGES_TO_SIZE (Bits);
346 }
347 }
348
349 /**
350 Clear corresponding bits in bitmap table according to given memory range.
351
352 @param[in] Address Memory address to unset from.
353 @param[in] NumberOfPages Number of pages to unset guard.
354
355 @return VOID
356 **/
357 VOID
358 EFIAPI
359 ClearGuardedMemoryBits (
360 IN EFI_PHYSICAL_ADDRESS Address,
361 IN UINTN NumberOfPages
362 )
363 {
364 UINT64 *BitMap;
365 UINTN Bits;
366 UINTN BitsToUnitEnd;
367
368 while (NumberOfPages > 0) {
369 BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
370 ASSERT (BitMap != NULL);
371
372 if (NumberOfPages > BitsToUnitEnd) {
373 // Cross map unit
374 Bits = BitsToUnitEnd;
375 } else {
376 Bits = NumberOfPages;
377 }
378
379 ClearBits (Address, Bits, BitMap);
380
381 NumberOfPages -= Bits;
382 Address += EFI_PAGES_TO_SIZE (Bits);
383 }
384 }
385
386 /**
387 Retrieve corresponding bits in bitmap table according to given memory range.
388
389 @param[in] Address Memory address to retrieve from.
390 @param[in] NumberOfPages Number of pages to retrieve.
391
392 @return An integer containing the guarded memory bitmap.
393 **/
394 UINTN
395 GetGuardedMemoryBits (
396 IN EFI_PHYSICAL_ADDRESS Address,
397 IN UINTN NumberOfPages
398 )
399 {
400 UINT64 *BitMap;
401 UINTN Bits;
402 UINTN Result;
403 UINTN Shift;
404 UINTN BitsToUnitEnd;
405
406 ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
407
408 Result = 0;
409 Shift = 0;
410 while (NumberOfPages > 0) {
411 BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
412
413 if (NumberOfPages > BitsToUnitEnd) {
414 // Cross map unit
415 Bits = BitsToUnitEnd;
416 } else {
417 Bits = NumberOfPages;
418 }
419
420 if (BitMap != NULL) {
421 Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
422 }
423
424 Shift += Bits;
425 NumberOfPages -= Bits;
426 Address += EFI_PAGES_TO_SIZE (Bits);
427 }
428
429 return Result;
430 }
431
432 /**
433 Get bit value in bitmap table for the given address.
434
435 @param[in] Address The address to retrieve for.
436
437 @return 1 or 0.
438 **/
439 UINTN
440 EFIAPI
441 GetGuardMapBit (
442 IN EFI_PHYSICAL_ADDRESS Address
443 )
444 {
445 UINT64 *GuardMap;
446
447 FindGuardedMemoryMap (Address, FALSE, &GuardMap);
448 if (GuardMap != NULL) {
449 if (RShiftU64 (*GuardMap,
450 GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)) & 1) {
451 return 1;
452 }
453 }
454
455 return 0;
456 }
457
458 /**
459 Set the bit in bitmap table for the given address.
460
461 @param[in] Address The address to set for.
462
463 @return VOID.
464 **/
465 VOID
466 EFIAPI
467 SetGuardMapBit (
468 IN EFI_PHYSICAL_ADDRESS Address
469 )
470 {
471 UINT64 *GuardMap;
472 UINT64 BitMask;
473
474 FindGuardedMemoryMap (Address, TRUE, &GuardMap);
475 if (GuardMap != NULL) {
476 BitMask = LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address));
477 *GuardMap |= BitMask;
478 }
479 }
480
481 /**
482 Clear the bit in bitmap table for the given address.
483
484 @param[in] Address The address to clear for.
485
486 @return VOID.
487 **/
488 VOID
489 EFIAPI
490 ClearGuardMapBit (
491 IN EFI_PHYSICAL_ADDRESS Address
492 )
493 {
494 UINT64 *GuardMap;
495 UINT64 BitMask;
496
497 FindGuardedMemoryMap (Address, TRUE, &GuardMap);
498 if (GuardMap != NULL) {
499 BitMask = LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address));
500 *GuardMap &= ~BitMask;
501 }
502 }
503
504 /**
505 Check to see if the page at the given address is a Guard page or not.
506
507 @param[in] Address The address to check for.
508
509 @return TRUE The page at Address is a Guard page.
510 @return FALSE The page at Address is not a Guard page.
511 **/
512 BOOLEAN
513 EFIAPI
514 IsGuardPage (
515 IN EFI_PHYSICAL_ADDRESS Address
516 )
517 {
518 UINTN BitMap;
519
520 //
521 // There must be at least one guarded page before and/or after given
522 // address if it's a Guard page. The bitmap pattern should be one of
523 // 001, 100 and 101
524 //
525 BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
526 return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
527 }
528
529 /**
530 Check to see if the page at the given address is a head Guard page or not.
531
532 @param[in] Address The address to check for.
533
534 @return TRUE The page at Address is a head Guard page.
535 @return FALSE The page at Address is not a head Guard page.
536 **/
537 BOOLEAN
538 EFIAPI
539 IsHeadGuard (
540 IN EFI_PHYSICAL_ADDRESS Address
541 )
542 {
543 return (GetGuardedMemoryBits (Address, 2) == BIT1);
544 }
545
546 /**
547 Check to see if the page at the given address is a tail Guard page or not.
548
549 @param[in] Address The address to check for.
550
551 @return TRUE The page at Address is a tail Guard page.
552 @return FALSE The page at Address is not a tail Guard page.
553 **/
554 BOOLEAN
555 EFIAPI
556 IsTailGuard (
557 IN EFI_PHYSICAL_ADDRESS Address
558 )
559 {
560 return (GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 2) == BIT0);
561 }
562
563 /**
564 Check to see if the page at the given address is guarded or not.
565
566 @param[in] Address The address to check for.
567
568 @return TRUE The page at Address is guarded.
569 @return FALSE The page at Address is not guarded.
570 **/
571 BOOLEAN
572 EFIAPI
573 IsMemoryGuarded (
574 IN EFI_PHYSICAL_ADDRESS Address
575 )
576 {
577 return (GetGuardMapBit (Address) == 1);
578 }
579
580 /**
581 Set the page at the given address to be a Guard page.
582
583 This is done by changing the page table attribute to be NOT PRSENT.
584
585 @param[in] BaseAddress Page address to Guard at.
586
587 @return VOID.
588 **/
589 VOID
590 EFIAPI
591 SetGuardPage (
592 IN EFI_PHYSICAL_ADDRESS BaseAddress
593 )
594 {
595 if (mSmmMemoryAttribute != NULL) {
596 mOnGuarding = TRUE;
597 mSmmMemoryAttribute->SetMemoryAttributes (
598 mSmmMemoryAttribute,
599 BaseAddress,
600 EFI_PAGE_SIZE,
601 EFI_MEMORY_RP
602 );
603 mOnGuarding = FALSE;
604 }
605 }
606
607 /**
608 Unset the Guard page at the given address to the normal memory.
609
610 This is done by changing the page table attribute to be PRSENT.
611
612 @param[in] BaseAddress Page address to Guard at.
613
614 @return VOID.
615 **/
616 VOID
617 EFIAPI
618 UnsetGuardPage (
619 IN EFI_PHYSICAL_ADDRESS BaseAddress
620 )
621 {
622 if (mSmmMemoryAttribute != NULL) {
623 mOnGuarding = TRUE;
624 mSmmMemoryAttribute->ClearMemoryAttributes (
625 mSmmMemoryAttribute,
626 BaseAddress,
627 EFI_PAGE_SIZE,
628 EFI_MEMORY_RP
629 );
630 mOnGuarding = FALSE;
631 }
632 }
633
634 /**
635 Check to see if the memory at the given address should be guarded or not.
636
637 @param[in] MemoryType Memory type to check.
638 @param[in] AllocateType Allocation type to check.
639 @param[in] PageOrPool Indicate a page allocation or pool allocation.
640
641
642 @return TRUE The given type of memory should be guarded.
643 @return FALSE The given type of memory should not be guarded.
644 **/
645 BOOLEAN
646 IsMemoryTypeToGuard (
647 IN EFI_MEMORY_TYPE MemoryType,
648 IN EFI_ALLOCATE_TYPE AllocateType,
649 IN UINT8 PageOrPool
650 )
651 {
652 UINT64 TestBit;
653 UINT64 ConfigBit;
654
655 if ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0
656 || mOnGuarding
657 || AllocateType == AllocateAddress) {
658 return FALSE;
659 }
660
661 ConfigBit = 0;
662 if ((PageOrPool & GUARD_HEAP_TYPE_POOL) != 0) {
663 ConfigBit |= PcdGet64 (PcdHeapGuardPoolType);
664 }
665
666 if ((PageOrPool & GUARD_HEAP_TYPE_PAGE) != 0) {
667 ConfigBit |= PcdGet64 (PcdHeapGuardPageType);
668 }
669
670 if (MemoryType == EfiRuntimeServicesData ||
671 MemoryType == EfiRuntimeServicesCode) {
672 TestBit = LShiftU64 (1, MemoryType);
673 } else if (MemoryType == EfiMaxMemoryType) {
674 TestBit = (UINT64)-1;
675 } else {
676 TestBit = 0;
677 }
678
679 return ((ConfigBit & TestBit) != 0);
680 }
681
682 /**
683 Check to see if the pool at the given address should be guarded or not.
684
685 @param[in] MemoryType Pool type to check.
686
687
688 @return TRUE The given type of pool should be guarded.
689 @return FALSE The given type of pool should not be guarded.
690 **/
691 BOOLEAN
692 IsPoolTypeToGuard (
693 IN EFI_MEMORY_TYPE MemoryType
694 )
695 {
696 return IsMemoryTypeToGuard (MemoryType, AllocateAnyPages,
697 GUARD_HEAP_TYPE_POOL);
698 }
699
700 /**
701 Check to see if the page at the given address should be guarded or not.
702
703 @param[in] MemoryType Page type to check.
704 @param[in] AllocateType Allocation type to check.
705
706 @return TRUE The given type of page should be guarded.
707 @return FALSE The given type of page should not be guarded.
708 **/
709 BOOLEAN
710 IsPageTypeToGuard (
711 IN EFI_MEMORY_TYPE MemoryType,
712 IN EFI_ALLOCATE_TYPE AllocateType
713 )
714 {
715 return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
716 }
717
718 /**
719 Check to see if the heap guard is enabled for page and/or pool allocation.
720
721 @return TRUE/FALSE.
722 **/
723 BOOLEAN
724 IsHeapGuardEnabled (
725 VOID
726 )
727 {
728 return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages,
729 GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_PAGE);
730 }
731
732 /**
733 Set head Guard and tail Guard for the given memory range.
734
735 @param[in] Memory Base address of memory to set guard for.
736 @param[in] NumberOfPages Memory size in pages.
737
738 @return VOID.
739 **/
740 VOID
741 SetGuardForMemory (
742 IN EFI_PHYSICAL_ADDRESS Memory,
743 IN UINTN NumberOfPages
744 )
745 {
746 EFI_PHYSICAL_ADDRESS GuardPage;
747
748 //
749 // Set tail Guard
750 //
751 GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
752 if (!IsGuardPage (GuardPage)) {
753 SetGuardPage (GuardPage);
754 }
755
756 // Set head Guard
757 GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
758 if (!IsGuardPage (GuardPage)) {
759 SetGuardPage (GuardPage);
760 }
761
762 //
763 // Mark the memory range as Guarded
764 //
765 SetGuardedMemoryBits (Memory, NumberOfPages);
766 }
767
768 /**
769 Unset head Guard and tail Guard for the given memory range.
770
771 @param[in] Memory Base address of memory to unset guard for.
772 @param[in] NumberOfPages Memory size in pages.
773
774 @return VOID.
775 **/
776 VOID
777 UnsetGuardForMemory (
778 IN EFI_PHYSICAL_ADDRESS Memory,
779 IN UINTN NumberOfPages
780 )
781 {
782 EFI_PHYSICAL_ADDRESS GuardPage;
783 UINT64 GuardBitmap;
784
785 if (NumberOfPages == 0) {
786 return;
787 }
788
789 //
790 // Head Guard must be one page before, if any.
791 //
792 // MSB-> 1 0 <-LSB
793 // -------------------
794 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
795 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
796 // 1 X -> Don't free first page (need a new Guard)
797 // (it'll be turned into a Guard page later)
798 // -------------------
799 // Start -> -1 -2
800 //
801 GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
802 GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
803 if ((GuardBitmap & BIT1) == 0) {
804 //
805 // Head Guard exists.
806 //
807 if ((GuardBitmap & BIT0) == 0) {
808 //
809 // If the head Guard is not a tail Guard of adjacent memory block,
810 // unset it.
811 //
812 UnsetGuardPage (GuardPage);
813 }
814 } else {
815 //
816 // Pages before memory to free are still in Guard. It's a partial free
817 // case. Turn first page of memory block to free into a new Guard.
818 //
819 SetGuardPage (Memory);
820 }
821
822 //
823 // Tail Guard must be the page after this memory block to free, if any.
824 //
825 // MSB-> 1 0 <-LSB
826 // --------------------
827 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
828 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
829 // X 1 -> Don't free last page (need a new Guard)
830 // (it'll be turned into a Guard page later)
831 // --------------------
832 // +1 +0 <- End
833 //
834 GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
835 GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
836 if ((GuardBitmap & BIT0) == 0) {
837 //
838 // Tail Guard exists.
839 //
840 if ((GuardBitmap & BIT1) == 0) {
841 //
842 // If the tail Guard is not a head Guard of adjacent memory block,
843 // free it; otherwise, keep it.
844 //
845 UnsetGuardPage (GuardPage);
846 }
847 } else {
848 //
849 // Pages after memory to free are still in Guard. It's a partial free
850 // case. We need to keep one page to be a head Guard.
851 //
852 SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
853 }
854
855 //
856 // No matter what, we just clear the mark of the Guarded memory.
857 //
858 ClearGuardedMemoryBits(Memory, NumberOfPages);
859 }
860
861 /**
862 Adjust address of free memory according to existing and/or required Guard.
863
864 This function will check if there're existing Guard pages of adjacent
865 memory blocks, and try to use it as the Guard page of the memory to be
866 allocated.
867
868 @param[in] Start Start address of free memory block.
869 @param[in] Size Size of free memory block.
870 @param[in] SizeRequested Size of memory to allocate.
871
872 @return The end address of memory block found.
873 @return 0 if no enough space for the required size of memory and its Guard.
874 **/
875 UINT64
876 AdjustMemoryS (
877 IN UINT64 Start,
878 IN UINT64 Size,
879 IN UINT64 SizeRequested
880 )
881 {
882 UINT64 Target;
883
884 //
885 // UEFI spec requires that allocated pool must be 8-byte aligned. If it's
886 // indicated to put the pool near the Tail Guard, we need extra bytes to
887 // make sure alignment of the returned pool address.
888 //
889 if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0) {
890 SizeRequested = ALIGN_VALUE(SizeRequested, 8);
891 }
892
893 Target = Start + Size - SizeRequested;
894 ASSERT (Target >= Start);
895 if (Target == 0) {
896 return 0;
897 }
898
899 if (!IsGuardPage (Start + Size)) {
900 // No Guard at tail to share. One more page is needed.
901 Target -= EFI_PAGES_TO_SIZE (1);
902 }
903
904 // Out of range?
905 if (Target < Start) {
906 return 0;
907 }
908
909 // At the edge?
910 if (Target == Start) {
911 if (!IsGuardPage (Target - EFI_PAGES_TO_SIZE (1))) {
912 // No enough space for a new head Guard if no Guard at head to share.
913 return 0;
914 }
915 }
916
917 // OK, we have enough pages for memory and its Guards. Return the End of the
918 // free space.
919 return Target + SizeRequested - 1;
920 }
921
922 /**
923 Adjust the start address and number of pages to free according to Guard.
924
925 The purpose of this function is to keep the shared Guard page with adjacent
926 memory block if it's still in guard, or free it if no more sharing. Another
927 is to reserve pages as Guard pages in partial page free situation.
928
929 @param[in,out] Memory Base address of memory to free.
930 @param[in,out] NumberOfPages Size of memory to free.
931
932 @return VOID.
933 **/
934 VOID
935 AdjustMemoryF (
936 IN OUT EFI_PHYSICAL_ADDRESS *Memory,
937 IN OUT UINTN *NumberOfPages
938 )
939 {
940 EFI_PHYSICAL_ADDRESS Start;
941 EFI_PHYSICAL_ADDRESS MemoryToTest;
942 UINTN PagesToFree;
943 UINT64 GuardBitmap;
944 UINT64 Attributes;
945
946 if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages == 0) {
947 return;
948 }
949
950 Start = *Memory;
951 PagesToFree = *NumberOfPages;
952
953 //
954 // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).
955 //
956 if (mSmmMemoryAttribute != NULL) {
957 Attributes = 0;
958 mSmmMemoryAttribute->GetMemoryAttributes (
959 mSmmMemoryAttribute,
960 Start,
961 EFI_PAGES_TO_SIZE (PagesToFree),
962 &Attributes
963 );
964 if ((Attributes & EFI_MEMORY_RO) != 0) {
965 mSmmMemoryAttribute->ClearMemoryAttributes (
966 mSmmMemoryAttribute,
967 Start,
968 EFI_PAGES_TO_SIZE (PagesToFree),
969 EFI_MEMORY_RO
970 );
971 }
972 }
973
974 //
975 // Head Guard must be one page before, if any.
976 //
977 // MSB-> 1 0 <-LSB
978 // -------------------
979 // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
980 // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
981 // 1 X -> Don't free first page (need a new Guard)
982 // (it'll be turned into a Guard page later)
983 // -------------------
984 // Start -> -1 -2
985 //
986 MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
987 GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
988 if ((GuardBitmap & BIT1) == 0) {
989 //
990 // Head Guard exists.
991 //
992 if ((GuardBitmap & BIT0) == 0) {
993 //
994 // If the head Guard is not a tail Guard of adjacent memory block,
995 // free it; otherwise, keep it.
996 //
997 Start -= EFI_PAGES_TO_SIZE (1);
998 PagesToFree += 1;
999 }
1000 } else {
1001 //
1002 // No Head Guard, and pages before memory to free are still in Guard. It's a
1003 // partial free case. We need to keep one page to be a tail Guard.
1004 //
1005 Start += EFI_PAGES_TO_SIZE (1);
1006 PagesToFree -= 1;
1007 }
1008
1009 //
1010 // Tail Guard must be the page after this memory block to free, if any.
1011 //
1012 // MSB-> 1 0 <-LSB
1013 // --------------------
1014 // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
1015 // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
1016 // X 1 -> Don't free last page (need a new Guard)
1017 // (it'll be turned into a Guard page later)
1018 // --------------------
1019 // +1 +0 <- End
1020 //
1021 MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
1022 GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
1023 if ((GuardBitmap & BIT0) == 0) {
1024 //
1025 // Tail Guard exists.
1026 //
1027 if ((GuardBitmap & BIT1) == 0) {
1028 //
1029 // If the tail Guard is not a head Guard of adjacent memory block,
1030 // free it; otherwise, keep it.
1031 //
1032 PagesToFree += 1;
1033 }
1034 } else if (PagesToFree > 0) {
1035 //
1036 // No Tail Guard, and pages after memory to free are still in Guard. It's a
1037 // partial free case. We need to keep one page to be a head Guard.
1038 //
1039 PagesToFree -= 1;
1040 }
1041
1042 *Memory = Start;
1043 *NumberOfPages = PagesToFree;
1044 }
1045
1046 /**
1047 Adjust the base and number of pages to really allocate according to Guard.
1048
1049 @param[in,out] Memory Base address of free memory.
1050 @param[in,out] NumberOfPages Size of memory to allocate.
1051
1052 @return VOID.
1053 **/
1054 VOID
1055 AdjustMemoryA (
1056 IN OUT EFI_PHYSICAL_ADDRESS *Memory,
1057 IN OUT UINTN *NumberOfPages
1058 )
1059 {
1060 //
1061 // FindFreePages() has already taken the Guard into account. It's safe to
1062 // adjust the start address and/or number of pages here, to make sure that
1063 // the Guards are also "allocated".
1064 //
1065 if (!IsGuardPage (*Memory + EFI_PAGES_TO_SIZE (*NumberOfPages))) {
1066 // No tail Guard, add one.
1067 *NumberOfPages += 1;
1068 }
1069
1070 if (!IsGuardPage (*Memory - EFI_PAGE_SIZE)) {
1071 // No head Guard, add one.
1072 *Memory -= EFI_PAGE_SIZE;
1073 *NumberOfPages += 1;
1074 }
1075 }
1076
1077 /**
1078 Adjust the pool head position to make sure the Guard page is adjavent to
1079 pool tail or pool head.
1080
1081 @param[in] Memory Base address of memory allocated.
1082 @param[in] NoPages Number of pages actually allocated.
1083 @param[in] Size Size of memory requested.
1084 (plus pool head/tail overhead)
1085
1086 @return Address of pool head
1087 **/
1088 VOID *
1089 AdjustPoolHeadA (
1090 IN EFI_PHYSICAL_ADDRESS Memory,
1091 IN UINTN NoPages,
1092 IN UINTN Size
1093 )
1094 {
1095 if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
1096 //
1097 // Pool head is put near the head Guard
1098 //
1099 return (VOID *)(UINTN)Memory;
1100 }
1101
1102 //
1103 // Pool head is put near the tail Guard
1104 //
1105 Size = ALIGN_VALUE (Size, 8);
1106 return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
1107 }
1108
1109 /**
1110 Get the page base address according to pool head address.
1111
1112 @param[in] Memory Head address of pool to free.
1113
1114 @return Address of pool head.
1115 **/
1116 VOID *
1117 AdjustPoolHeadF (
1118 IN EFI_PHYSICAL_ADDRESS Memory
1119 )
1120 {
1121 if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
1122 //
1123 // Pool head is put near the head Guard
1124 //
1125 return (VOID *)(UINTN)Memory;
1126 }
1127
1128 //
1129 // Pool head is put near the tail Guard
1130 //
1131 return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK);
1132 }
1133
1134 /**
1135 Helper function of memory allocation with Guard pages.
1136
1137 @param FreePageList The free page node.
1138 @param NumberOfPages Number of pages to be allocated.
1139 @param MaxAddress Request to allocate memory below this address.
1140 @param MemoryType Type of memory requested.
1141
1142 @return Memory address of allocated pages.
1143 **/
1144 UINTN
1145 InternalAllocMaxAddressWithGuard (
1146 IN OUT LIST_ENTRY *FreePageList,
1147 IN UINTN NumberOfPages,
1148 IN UINTN MaxAddress,
1149 IN EFI_MEMORY_TYPE MemoryType
1150
1151 )
1152 {
1153 LIST_ENTRY *Node;
1154 FREE_PAGE_LIST *Pages;
1155 UINTN PagesToAlloc;
1156 UINTN HeadGuard;
1157 UINTN TailGuard;
1158 UINTN Address;
1159
1160 for (Node = FreePageList->BackLink; Node != FreePageList;
1161 Node = Node->BackLink) {
1162 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
1163 if (Pages->NumberOfPages >= NumberOfPages &&
1164 (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {
1165
1166 //
1167 // We may need 1 or 2 more pages for Guard. Check it out.
1168 //
1169 PagesToAlloc = NumberOfPages;
1170 TailGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
1171 if (!IsGuardPage (TailGuard)) {
1172 //
1173 // Add one if no Guard at the end of current free memory block.
1174 //
1175 PagesToAlloc += 1;
1176 TailGuard = 0;
1177 }
1178
1179 HeadGuard = (UINTN)Pages +
1180 EFI_PAGES_TO_SIZE (Pages->NumberOfPages - PagesToAlloc) -
1181 EFI_PAGE_SIZE;
1182 if (!IsGuardPage (HeadGuard)) {
1183 //
1184 // Add one if no Guard at the page before the address to allocate
1185 //
1186 PagesToAlloc += 1;
1187 HeadGuard = 0;
1188 }
1189
1190 if (Pages->NumberOfPages < PagesToAlloc) {
1191 // Not enough space to allocate memory with Guards? Try next block.
1192 continue;
1193 }
1194
1195 Address = InternalAllocPagesOnOneNode (Pages, PagesToAlloc, MaxAddress);
1196 ConvertSmmMemoryMapEntry(MemoryType, Address, PagesToAlloc, FALSE);
1197 CoreFreeMemoryMapStack();
1198 if (HeadGuard == 0) {
1199 // Don't pass the Guard page to user.
1200 Address += EFI_PAGE_SIZE;
1201 }
1202 SetGuardForMemory (Address, NumberOfPages);
1203 return Address;
1204 }
1205 }
1206
1207 return (UINTN)(-1);
1208 }
1209
1210 /**
1211 Helper function of memory free with Guard pages.
1212
1213 @param[in] Memory Base address of memory being freed.
1214 @param[in] NumberOfPages The number of pages to free.
1215 @param[in] AddRegion If this memory is new added region.
1216
1217 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
1218 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
1219 @return EFI_SUCCESS Pages successfully freed.
1220 **/
1221 EFI_STATUS
1222 SmmInternalFreePagesExWithGuard (
1223 IN EFI_PHYSICAL_ADDRESS Memory,
1224 IN UINTN NumberOfPages,
1225 IN BOOLEAN AddRegion
1226 )
1227 {
1228 EFI_PHYSICAL_ADDRESS MemoryToFree;
1229 UINTN PagesToFree;
1230
1231 if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
1232 return EFI_INVALID_PARAMETER;
1233 }
1234
1235 MemoryToFree = Memory;
1236 PagesToFree = NumberOfPages;
1237
1238 AdjustMemoryF (&MemoryToFree, &PagesToFree);
1239 UnsetGuardForMemory (Memory, NumberOfPages);
1240 if (PagesToFree == 0) {
1241 return EFI_SUCCESS;
1242 }
1243
1244 return SmmInternalFreePagesEx (MemoryToFree, PagesToFree, AddRegion);
1245 }
1246
1247 /**
1248 Set all Guard pages which cannot be set during the non-SMM mode time.
1249 **/
1250 VOID
1251 SetAllGuardPages (
1252 VOID
1253 )
1254 {
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];
1260 UINT64 TableEntry;
1261 UINT64 Address;
1262 UINT64 GuardPage;
1263 INTN Level;
1264 UINTN Index;
1265 BOOLEAN OnGuarding;
1266
1267 if (mGuardedMemoryMap == 0 ||
1268 mMapLevel == 0 ||
1269 mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
1270 return;
1271 }
1272
1273 CopyMem (Entries, mLevelMask, sizeof (Entries));
1274 CopyMem (Shifts, mLevelShift, sizeof (Shifts));
1275
1276 SetMem (Tables, sizeof(Tables), 0);
1277 SetMem (Addresses, sizeof(Addresses), 0);
1278 SetMem (Indices, sizeof(Indices), 0);
1279
1280 Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
1281 Tables[Level] = mGuardedMemoryMap;
1282 Address = 0;
1283 OnGuarding = FALSE;
1284
1285 DEBUG_CODE (
1286 DumpGuardedMemoryBitmap ();
1287 );
1288
1289 while (TRUE) {
1290 if (Indices[Level] > Entries[Level]) {
1291 Tables[Level] = 0;
1292 Level -= 1;
1293 } else {
1294
1295 TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
1296 Address = Addresses[Level];
1297
1298 if (TableEntry == 0) {
1299
1300 OnGuarding = FALSE;
1301
1302 } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
1303
1304 Level += 1;
1305 Tables[Level] = TableEntry;
1306 Addresses[Level] = Address;
1307 Indices[Level] = 0;
1308
1309 continue;
1310
1311 } else {
1312
1313 Index = 0;
1314 while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
1315 if ((TableEntry & 1) == 1) {
1316 if (OnGuarding) {
1317 GuardPage = 0;
1318 } else {
1319 GuardPage = Address - EFI_PAGE_SIZE;
1320 }
1321 OnGuarding = TRUE;
1322 } else {
1323 if (OnGuarding) {
1324 GuardPage = Address;
1325 } else {
1326 GuardPage = 0;
1327 }
1328 OnGuarding = FALSE;
1329 }
1330
1331 if (GuardPage != 0) {
1332 SetGuardPage (GuardPage);
1333 }
1334
1335 if (TableEntry == 0) {
1336 break;
1337 }
1338
1339 TableEntry = RShiftU64 (TableEntry, 1);
1340 Address += EFI_PAGE_SIZE;
1341 Index += 1;
1342 }
1343 }
1344 }
1345
1346 if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
1347 break;
1348 }
1349
1350 Indices[Level] += 1;
1351 Address = (Level == 0) ? 0 : Addresses[Level - 1];
1352 Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
1353
1354 }
1355 }
1356
1357 /**
1358 Hook function used to set all Guard pages after entering SMM mode.
1359 **/
1360 VOID
1361 SmmEntryPointMemoryManagementHook (
1362 VOID
1363 )
1364 {
1365 EFI_STATUS Status;
1366
1367 if (mSmmMemoryAttribute == NULL) {
1368 Status = SmmLocateProtocol (
1369 &gEdkiiSmmMemoryAttributeProtocolGuid,
1370 NULL,
1371 (VOID **)&mSmmMemoryAttribute
1372 );
1373 if (!EFI_ERROR(Status)) {
1374 SetAllGuardPages ();
1375 }
1376 }
1377 }
1378
1379 /**
1380 Helper function to convert a UINT64 value in binary to a string.
1381
1382 @param[in] Value Value of a UINT64 integer.
1383 @param[out] BinString String buffer to contain the conversion result.
1384
1385 @return VOID.
1386 **/
1387 VOID
1388 Uint64ToBinString (
1389 IN UINT64 Value,
1390 OUT CHAR8 *BinString
1391 )
1392 {
1393 UINTN Index;
1394
1395 if (BinString == NULL) {
1396 return;
1397 }
1398
1399 for (Index = 64; Index > 0; --Index) {
1400 BinString[Index - 1] = '0' + (Value & 1);
1401 Value = RShiftU64 (Value, 1);
1402 }
1403 BinString[64] = '\0';
1404 }
1405
1406 /**
1407 Dump the guarded memory bit map.
1408 **/
1409 VOID
1410 EFIAPI
1411 DumpGuardedMemoryBitmap (
1412 VOID
1413 )
1414 {
1415 UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
1416 UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
1417 UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
1418 UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
1419 UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
1420 UINT64 TableEntry;
1421 UINT64 Address;
1422 INTN Level;
1423 UINTN RepeatZero;
1424 CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
1425 CHAR8 *Ruler1;
1426 CHAR8 *Ruler2;
1427
1428 if (mGuardedMemoryMap == 0 ||
1429 mMapLevel == 0 ||
1430 mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
1431 return;
1432 }
1433
1434 Ruler1 = " 3 2 1 0";
1435 Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1436
1437 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "============================="
1438 " Guarded Memory Bitmap "
1439 "==============================\r\n"));
1440 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
1441 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
1442
1443 CopyMem (Entries, mLevelMask, sizeof (Entries));
1444 CopyMem (Shifts, mLevelShift, sizeof (Shifts));
1445
1446 SetMem (Indices, sizeof(Indices), 0);
1447 SetMem (Tables, sizeof(Tables), 0);
1448 SetMem (Addresses, sizeof(Addresses), 0);
1449
1450 Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
1451 Tables[Level] = mGuardedMemoryMap;
1452 Address = 0;
1453 RepeatZero = 0;
1454
1455 while (TRUE) {
1456 if (Indices[Level] > Entries[Level]) {
1457
1458 Tables[Level] = 0;
1459 Level -= 1;
1460 RepeatZero = 0;
1461
1462 DEBUG ((
1463 HEAP_GUARD_DEBUG_LEVEL,
1464 "========================================="
1465 "=========================================\r\n"
1466 ));
1467
1468 } else {
1469
1470 TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
1471 Address = Addresses[Level];
1472
1473 if (TableEntry == 0) {
1474
1475 if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
1476 if (RepeatZero == 0) {
1477 Uint64ToBinString(TableEntry, String);
1478 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
1479 } else if (RepeatZero == 1) {
1480 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
1481 }
1482 RepeatZero += 1;
1483 }
1484
1485 } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
1486
1487 Level += 1;
1488 Tables[Level] = TableEntry;
1489 Addresses[Level] = Address;
1490 Indices[Level] = 0;
1491 RepeatZero = 0;
1492
1493 continue;
1494
1495 } else {
1496
1497 RepeatZero = 0;
1498 Uint64ToBinString(TableEntry, String);
1499 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
1500
1501 }
1502 }
1503
1504 if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
1505 break;
1506 }
1507
1508 Indices[Level] += 1;
1509 Address = (Level == 0) ? 0 : Addresses[Level - 1];
1510 Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
1511
1512 }
1513 }
1514
1515 /**
1516 Debug function used to verify if the Guard page is well set or not.
1517
1518 @param[in] BaseAddress Address of memory to check.
1519 @param[in] NumberOfPages Size of memory in pages.
1520
1521 @return TRUE The head Guard and tail Guard are both well set.
1522 @return FALSE The head Guard and/or tail Guard are not well set.
1523 **/
1524 BOOLEAN
1525 VerifyMemoryGuard (
1526 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1527 IN UINTN NumberOfPages
1528 )
1529 {
1530 EFI_STATUS Status;
1531 UINT64 Attribute;
1532 EFI_PHYSICAL_ADDRESS Address;
1533
1534 if (mSmmMemoryAttribute == NULL) {
1535 return TRUE;
1536 }
1537
1538 Attribute = 0;
1539 Address = BaseAddress - EFI_PAGE_SIZE;
1540 Status = mSmmMemoryAttribute->GetMemoryAttributes (
1541 mSmmMemoryAttribute,
1542 Address,
1543 EFI_PAGE_SIZE,
1544 &Attribute
1545 );
1546 if (EFI_ERROR (Status) || (Attribute & EFI_MEMORY_RP) == 0) {
1547 DEBUG ((DEBUG_ERROR, "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
1548 Address, Attribute));
1549 DumpGuardedMemoryBitmap ();
1550 return FALSE;
1551 }
1552
1553 Attribute = 0;
1554 Address = BaseAddress + EFI_PAGES_TO_SIZE (NumberOfPages);
1555 Status = mSmmMemoryAttribute->GetMemoryAttributes (
1556 mSmmMemoryAttribute,
1557 Address,
1558 EFI_PAGE_SIZE,
1559 &Attribute
1560 );
1561 if (EFI_ERROR (Status) || (Attribute & EFI_MEMORY_RP) == 0) {
1562 DEBUG ((DEBUG_ERROR, "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
1563 Address, Attribute));
1564 DumpGuardedMemoryBitmap ();
1565 return FALSE;
1566 }
1567
1568 return TRUE;
1569 }
1570