MdeModulePkg/DxeCore: Implement heap guard feature for UEFI
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / HeapGuard.c
CommitLineData
235a4490
JW
1/** @file
2 UEFI Heap Guard functions.
3
4Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "DxeMain.h"
16#include "Imem.h"
17#include "HeapGuard.h"
18
19//
20// Global to avoid infinite reentrance of memory allocation when updating
21// page table attributes, which may need allocate pages for new PDE/PTE.
22//
23GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
24
25//
26// Pointer to table tracking the Guarded memory with bitmap, in which '1'
27// is used to indicate memory guarded. '0' might be free memory or Guard
28// page itself, depending on status of memory adjacent to it.
29//
30GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
31
32//
33// Current depth level of map table pointed by mGuardedMemoryMap.
34// mMapLevel must be initialized at least by 1. It will be automatically
35// updated according to the address of memory just tracked.
36//
37GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
38
39//
40// Shift and mask for each level of map table
41//
42GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
43 = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
44GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
45 = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
46
47/**
48 Set corresponding bits in bitmap table to 1 according to the address.
49
50 @param[in] Address Start address to set for.
51 @param[in] BitNumber Number of bits to set.
52 @param[in] BitMap Pointer to bitmap which covers the Address.
53
54 @return VOID.
55**/
56STATIC
57VOID
58SetBits (
59 IN EFI_PHYSICAL_ADDRESS Address,
60 IN UINTN BitNumber,
61 IN UINT64 *BitMap
62 )
63{
64 UINTN Lsbs;
65 UINTN Qwords;
66 UINTN Msbs;
67 UINTN StartBit;
68 UINTN EndBit;
69
70 StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
71 EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
72
73 if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
74 Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
75 GUARDED_HEAP_MAP_ENTRY_BITS;
76 Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
77 Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
78 } else {
79 Msbs = BitNumber;
80 Lsbs = 0;
81 Qwords = 0;
82 }
83
84 if (Msbs > 0) {
85 *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
86 BitMap += 1;
87 }
88
89 if (Qwords > 0) {
90 SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
91 (UINT64)-1);
92 BitMap += Qwords;
93 }
94
95 if (Lsbs > 0) {
96 *BitMap |= (LShiftU64 (1, Lsbs) - 1);
97 }
98}
99
100/**
101 Set corresponding bits in bitmap table to 0 according to the address.
102
103 @param[in] Address Start address to set for.
104 @param[in] BitNumber Number of bits to set.
105 @param[in] BitMap Pointer to bitmap which covers the Address.
106
107 @return VOID.
108**/
109STATIC
110VOID
111ClearBits (
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
152/**
153 Get corresponding bits in bitmap table according to the address.
154
155 The value of bit 0 corresponds to the status of memory at given Address.
156 No more than 64 bits can be retrieved in one call.
157
158 @param[in] Address Start address to retrieve bits for.
159 @param[in] BitNumber Number of bits to get.
160 @param[in] BitMap Pointer to bitmap which covers the Address.
161
162 @return An integer containing the bits information.
163**/
164STATIC
165UINT64
166GetBits (
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 Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);
192 if (Lsbs > 0) {
193 BitMap += 1;
194 Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
195 }
196
197 return Result;
198}
199
200/**
201 Locate the pointer of bitmap from the guarded memory bitmap tables, which
202 covers the given Address.
203
204 @param[in] Address Start address to search the bitmap for.
205 @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
206 @param[out] BitMap Pointer to bitmap which covers the Address.
207
208 @return The bit number from given Address to the end of current map table.
209**/
210UINTN
211FindGuardedMemoryMap (
212 IN EFI_PHYSICAL_ADDRESS Address,
213 IN BOOLEAN AllocMapUnit,
214 OUT UINT64 **BitMap
215 )
216{
217 UINTN Level;
218 UINT64 *GuardMap;
219 UINT64 MapMemory;
220 UINTN Index;
221 UINTN Size;
222 UINTN BitsToUnitEnd;
223 EFI_STATUS Status;
224
225 //
226 // Adjust current map table depth according to the address to access
227 //
228 while (mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH
229 &&
230 RShiftU64 (
231 Address,
232 mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
233 ) != 0) {
234
235 if (mGuardedMemoryMap != 0) {
236 Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
237 * GUARDED_HEAP_MAP_ENTRY_BYTES;
238 Status = CoreInternalAllocatePages (
239 AllocateAnyPages,
240 EfiBootServicesData,
241 EFI_SIZE_TO_PAGES (Size),
242 &MapMemory,
243 FALSE
244 );
245 ASSERT_EFI_ERROR (Status);
246 ASSERT (MapMemory != 0);
247
248 SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
249
250 *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
251 mGuardedMemoryMap = MapMemory;
252 }
253
254 mMapLevel++;
255
256 }
257
258 GuardMap = &mGuardedMemoryMap;
259 for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
260 Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
261 ++Level) {
262
263 if (*GuardMap == 0) {
264 if (!AllocMapUnit) {
265 GuardMap = NULL;
266 break;
267 }
268
269 Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
270 Status = CoreInternalAllocatePages (
271 AllocateAnyPages,
272 EfiBootServicesData,
273 EFI_SIZE_TO_PAGES (Size),
274 &MapMemory,
275 FALSE
276 );
277 ASSERT_EFI_ERROR (Status);
278 ASSERT (MapMemory != 0);
279
280 SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
281 *GuardMap = MapMemory;
282 }
283
284 Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
285 Index &= mLevelMask[Level];
286 GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
287
288 }
289
290 BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
291 *BitMap = GuardMap;
292
293 return BitsToUnitEnd;
294}
295
296/**
297 Set corresponding bits in bitmap table to 1 according to given memory range.
298
299 @param[in] Address Memory address to guard from.
300 @param[in] NumberOfPages Number of pages to guard.
301
302 @return VOID.
303**/
304VOID
305EFIAPI
306SetGuardedMemoryBits (
307 IN EFI_PHYSICAL_ADDRESS Address,
308 IN UINTN NumberOfPages
309 )
310{
311 UINT64 *BitMap;
312 UINTN Bits;
313 UINTN BitsToUnitEnd;
314
315 while (NumberOfPages > 0) {
316 BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
317 ASSERT (BitMap != NULL);
318
319 if (NumberOfPages > BitsToUnitEnd) {
320 // Cross map unit
321 Bits = BitsToUnitEnd;
322 } else {
323 Bits = NumberOfPages;
324 }
325
326 SetBits (Address, Bits, BitMap);
327
328 NumberOfPages -= Bits;
329 Address += EFI_PAGES_TO_SIZE (Bits);
330 }
331}
332
333/**
334 Clear corresponding bits in bitmap table according to given memory range.
335
336 @param[in] Address Memory address to unset from.
337 @param[in] NumberOfPages Number of pages to unset guard.
338
339 @return VOID.
340**/
341VOID
342EFIAPI
343ClearGuardedMemoryBits (
344 IN EFI_PHYSICAL_ADDRESS Address,
345 IN UINTN NumberOfPages
346 )
347{
348 UINT64 *BitMap;
349 UINTN Bits;
350 UINTN BitsToUnitEnd;
351
352 while (NumberOfPages > 0) {
353 BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
354 ASSERT (BitMap != NULL);
355
356 if (NumberOfPages > BitsToUnitEnd) {
357 // Cross map unit
358 Bits = BitsToUnitEnd;
359 } else {
360 Bits = NumberOfPages;
361 }
362
363 ClearBits (Address, Bits, BitMap);
364
365 NumberOfPages -= Bits;
366 Address += EFI_PAGES_TO_SIZE (Bits);
367 }
368}
369
370/**
371 Retrieve corresponding bits in bitmap table according to given memory range.
372
373 @param[in] Address Memory address to retrieve from.
374 @param[in] NumberOfPages Number of pages to retrieve.
375
376 @return VOID.
377**/
378UINTN
379GetGuardedMemoryBits (
380 IN EFI_PHYSICAL_ADDRESS Address,
381 IN UINTN NumberOfPages
382 )
383{
384 UINT64 *BitMap;
385 UINTN Bits;
386 UINTN Result;
387 UINTN Shift;
388 UINTN BitsToUnitEnd;
389
390 ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
391
392 Result = 0;
393 Shift = 0;
394 while (NumberOfPages > 0) {
395 BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
396
397 if (NumberOfPages > BitsToUnitEnd) {
398 // Cross map unit
399 Bits = BitsToUnitEnd;
400 } else {
401 Bits = NumberOfPages;
402 }
403
404 if (BitMap != NULL) {
405 Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
406 }
407
408 Shift += Bits;
409 NumberOfPages -= Bits;
410 Address += EFI_PAGES_TO_SIZE (Bits);
411 }
412
413 return Result;
414}
415
416/**
417 Get bit value in bitmap table for the given address.
418
419 @param[in] Address The address to retrieve for.
420
421 @return 1 or 0.
422**/
423UINTN
424EFIAPI
425GetGuardMapBit (
426 IN EFI_PHYSICAL_ADDRESS Address
427 )
428{
429 UINT64 *GuardMap;
430
431 FindGuardedMemoryMap (Address, FALSE, &GuardMap);
432 if (GuardMap != NULL) {
433 if (RShiftU64 (*GuardMap,
434 GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)) & 1) {
435 return 1;
436 }
437 }
438
439 return 0;
440}
441
442/**
443 Set the bit in bitmap table for the given address.
444
445 @param[in] Address The address to set for.
446
447 @return VOID.
448**/
449VOID
450EFIAPI
451SetGuardMapBit (
452 IN EFI_PHYSICAL_ADDRESS Address
453 )
454{
455 UINT64 *GuardMap;
456 UINT64 BitMask;
457
458 FindGuardedMemoryMap (Address, TRUE, &GuardMap);
459 if (GuardMap != NULL) {
460 BitMask = LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address));
461 *GuardMap |= BitMask;
462 }
463}
464
465/**
466 Clear the bit in bitmap table for the given address.
467
468 @param[in] Address The address to clear for.
469
470 @return VOID.
471**/
472VOID
473EFIAPI
474ClearGuardMapBit (
475 IN EFI_PHYSICAL_ADDRESS Address
476 )
477{
478 UINT64 *GuardMap;
479 UINT64 BitMask;
480
481 FindGuardedMemoryMap (Address, TRUE, &GuardMap);
482 if (GuardMap != NULL) {
483 BitMask = LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address));
484 *GuardMap &= ~BitMask;
485 }
486}
487
488/**
489 Check to see if the page at the given address is a Guard page or not.
490
491 @param[in] Address The address to check for.
492
493 @return TRUE The page at Address is a Guard page.
494 @return FALSE The page at Address is not a Guard page.
495**/
496BOOLEAN
497EFIAPI
498IsGuardPage (
499 IN EFI_PHYSICAL_ADDRESS Address
500 )
501{
502 UINTN BitMap;
503
504 BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
505 return ((BitMap == 0b001) || (BitMap == 0b100) || (BitMap == 0b101));
506}
507
508/**
509 Check to see if the page at the given address is a head Guard page or not.
510
511 @param[in] Address The address to check for
512
513 @return TRUE The page at Address is a head Guard page
514 @return FALSE The page at Address is not a head Guard page
515**/
516BOOLEAN
517EFIAPI
518IsHeadGuard (
519 IN EFI_PHYSICAL_ADDRESS Address
520 )
521{
522 return (GetGuardedMemoryBits (Address, 2) == 0b10);
523}
524
525/**
526 Check to see if the page at the given address is a tail Guard page or not.
527
528 @param[in] Address The address to check for.
529
530 @return TRUE The page at Address is a tail Guard page.
531 @return FALSE The page at Address is not a tail Guard page.
532**/
533BOOLEAN
534EFIAPI
535IsTailGuard (
536 IN EFI_PHYSICAL_ADDRESS Address
537 )
538{
539 return (GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 2) == 0b01);
540}
541
542/**
543 Check to see if the page at the given address is guarded or not.
544
545 @param[in] Address The address to check for.
546
547 @return TRUE The page at Address is guarded.
548 @return FALSE The page at Address is not guarded.
549**/
550BOOLEAN
551EFIAPI
552IsMemoryGuarded (
553 IN EFI_PHYSICAL_ADDRESS Address
554 )
555{
556 return (GetGuardMapBit (Address) == 1);
557}
558
559/**
560 Set the page at the given address to be a Guard page.
561
562 This is done by changing the page table attribute to be NOT PRSENT.
563
564 @param[in] BaseAddress Page address to Guard at
565
566 @return VOID
567**/
568VOID
569EFIAPI
570SetGuardPage (
571 IN EFI_PHYSICAL_ADDRESS BaseAddress
572 )
573{
574 //
575 // Set flag to make sure allocating memory without GUARD for page table
576 // operation; otherwise infinite loops could be caused.
577 //
578 mOnGuarding = TRUE;
579 //
580 // Note: This might overwrite other attributes needed by other features,
581 // such as memory protection (NX). Please make sure they are not enabled
582 // at the same time.
583 //
584 gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, EFI_MEMORY_RP);
585 mOnGuarding = FALSE;
586}
587
588/**
589 Unset the Guard page at the given address to the normal memory.
590
591 This is done by changing the page table attribute to be PRSENT.
592
593 @param[in] BaseAddress Page address to Guard at.
594
595 @return VOID.
596**/
597VOID
598EFIAPI
599UnsetGuardPage (
600 IN EFI_PHYSICAL_ADDRESS BaseAddress
601 )
602{
603 //
604 // Set flag to make sure allocating memory without GUARD for page table
605 // operation; otherwise infinite loops could be caused.
606 //
607 mOnGuarding = TRUE;
608 //
609 // Note: This might overwrite other attributes needed by other features,
610 // such as memory protection (NX). Please make sure they are not enabled
611 // at the same time.
612 //
613 gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, 0);
614 mOnGuarding = FALSE;
615}
616
617/**
618 Check to see if the memory at the given address should be guarded or not.
619
620 @param[in] MemoryType Memory type to check.
621 @param[in] AllocateType Allocation type to check.
622 @param[in] PageOrPool Indicate a page allocation or pool allocation.
623
624
625 @return TRUE The given type of memory should be guarded.
626 @return FALSE The given type of memory should not be guarded.
627**/
628BOOLEAN
629IsMemoryTypeToGuard (
630 IN EFI_MEMORY_TYPE MemoryType,
631 IN EFI_ALLOCATE_TYPE AllocateType,
632 IN UINT8 PageOrPool
633 )
634{
635 UINT64 TestBit;
636 UINT64 ConfigBit;
637 BOOLEAN InSmm;
638
639 if (gCpu == NULL || AllocateType == AllocateAddress) {
640 return FALSE;
641 }
642
643 InSmm = FALSE;
644 if (gSmmBase2 != NULL) {
645 gSmmBase2->InSmm (gSmmBase2, &InSmm);
646 }
647
648 if (InSmm) {
649 return FALSE;
650 }
651
652 if ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0) {
653 return FALSE;
654 }
655
656 if (PageOrPool == GUARD_HEAP_TYPE_POOL) {
657 ConfigBit = PcdGet64 (PcdHeapGuardPoolType);
658 } else if (PageOrPool == GUARD_HEAP_TYPE_PAGE) {
659 ConfigBit = PcdGet64 (PcdHeapGuardPageType);
660 } else {
661 ConfigBit = (UINT64)-1;
662 }
663
664 if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
665 TestBit = BIT63;
666 } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
667 TestBit = BIT62;
668 } else if (MemoryType < EfiMaxMemoryType) {
669 TestBit = LShiftU64 (1, MemoryType);
670 } else if (MemoryType == EfiMaxMemoryType) {
671 TestBit = (UINT64)-1;
672 } else {
673 TestBit = 0;
674 }
675
676 return ((ConfigBit & TestBit) != 0);
677}
678
679/**
680 Check to see if the pool at the given address should be guarded or not.
681
682 @param[in] MemoryType Pool type to check.
683
684
685 @return TRUE The given type of pool should be guarded.
686 @return FALSE The given type of pool should not be guarded.
687**/
688BOOLEAN
689IsPoolTypeToGuard (
690 IN EFI_MEMORY_TYPE MemoryType
691 )
692{
693 return IsMemoryTypeToGuard (MemoryType, AllocateAnyPages,
694 GUARD_HEAP_TYPE_POOL);
695}
696
697/**
698 Check to see if the page at the given address should be guarded or not.
699
700 @param[in] MemoryType Page type to check.
701 @param[in] AllocateType Allocation type to check.
702
703 @return TRUE The given type of page should be guarded.
704 @return FALSE The given type of page should not be guarded.
705**/
706BOOLEAN
707IsPageTypeToGuard (
708 IN EFI_MEMORY_TYPE MemoryType,
709 IN EFI_ALLOCATE_TYPE AllocateType
710 )
711{
712 return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
713}
714
715/**
716 Set head Guard and tail Guard for the given memory range.
717
718 @param[in] Memory Base address of memory to set guard for.
719 @param[in] NumberOfPages Memory size in pages.
720
721 @return VOID
722**/
723VOID
724SetGuardForMemory (
725 IN EFI_PHYSICAL_ADDRESS Memory,
726 IN UINTN NumberOfPages
727 )
728{
729 EFI_PHYSICAL_ADDRESS GuardPage;
730
731 //
732 // Set tail Guard
733 //
734 GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
735 if (!IsGuardPage (GuardPage)) {
736 SetGuardPage (GuardPage);
737 }
738
739 // Set head Guard
740 GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
741 if (!IsGuardPage (GuardPage)) {
742 SetGuardPage (GuardPage);
743 }
744
745 //
746 // Mark the memory range as Guarded
747 //
748 SetGuardedMemoryBits (Memory, NumberOfPages);
749}
750
751/**
752 Unset head Guard and tail Guard for the given memory range.
753
754 @param[in] Memory Base address of memory to unset guard for.
755 @param[in] NumberOfPages Memory size in pages.
756
757 @return VOID
758**/
759VOID
760UnsetGuardForMemory (
761 IN EFI_PHYSICAL_ADDRESS Memory,
762 IN UINTN NumberOfPages
763 )
764{
765 EFI_PHYSICAL_ADDRESS GuardPage;
766
767 if (NumberOfPages == 0) {
768 return;
769 }
770
771 //
772 // Head Guard must be one page before, if any.
773 //
774 GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
775 if (IsHeadGuard (GuardPage)) {
776 if (!IsMemoryGuarded (GuardPage - EFI_PAGES_TO_SIZE (1))) {
777 //
778 // If the head Guard is not a tail Guard of adjacent memory block,
779 // unset it.
780 //
781 UnsetGuardPage (GuardPage);
782 }
783 } else if (IsMemoryGuarded (GuardPage)) {
784 //
785 // Pages before memory to free are still in Guard. It's a partial free
786 // case. Turn first page of memory block to free into a new Guard.
787 //
788 SetGuardPage (Memory);
789 }
790
791 //
792 // Tail Guard must be the page after this memory block to free, if any.
793 //
794 GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
795 if (IsTailGuard (GuardPage)) {
796 if (!IsMemoryGuarded (GuardPage + EFI_PAGES_TO_SIZE (1))) {
797 //
798 // If the tail Guard is not a head Guard of adjacent memory block,
799 // free it; otherwise, keep it.
800 //
801 UnsetGuardPage (GuardPage);
802 }
803 } else if (IsMemoryGuarded (GuardPage)) {
804 //
805 // Pages after memory to free are still in Guard. It's a partial free
806 // case. We need to keep one page to be a head Guard.
807 //
808 SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
809 }
810
811 //
812 // No matter what, we just clear the mark of the Guarded memory.
813 //
814 ClearGuardedMemoryBits(Memory, NumberOfPages);
815}
816
817/**
818 Adjust address of free memory according to existing and/or required Guard.
819
820 This function will check if there're existing Guard pages of adjacent
821 memory blocks, and try to use it as the Guard page of the memory to be
822 allocated.
823
824 @param[in] Start Start address of free memory block.
825 @param[in] Size Size of free memory block.
826 @param[in] SizeRequested Size of memory to allocate.
827
828 @return The end address of memory block found.
829 @return 0 if no enough space for the required size of memory and its Guard.
830**/
831UINT64
832AdjustMemoryS (
833 IN UINT64 Start,
834 IN UINT64 Size,
835 IN UINT64 SizeRequested
836 )
837{
838 UINT64 Target;
839
840 Target = Start + Size - SizeRequested;
841
842 //
843 // At least one more page needed for Guard page.
844 //
845 if (Size < (SizeRequested + EFI_PAGES_TO_SIZE (1))) {
846 return 0;
847 }
848
849 if (!IsGuardPage (Start + Size)) {
850 // No Guard at tail to share. One more page is needed.
851 Target -= EFI_PAGES_TO_SIZE (1);
852 }
853
854 // Out of range?
855 if (Target < Start) {
856 return 0;
857 }
858
859 // At the edge?
860 if (Target == Start) {
861 if (!IsGuardPage (Target - EFI_PAGES_TO_SIZE (1))) {
862 // No enough space for a new head Guard if no Guard at head to share.
863 return 0;
864 }
865 }
866
867 // OK, we have enough pages for memory and its Guards. Return the End of the
868 // free space.
869 return Target + SizeRequested - 1;
870}
871
872/**
873 Adjust the start address and number of pages to free according to Guard.
874
875 The purpose of this function is to keep the shared Guard page with adjacent
876 memory block if it's still in guard, or free it if no more sharing. Another
877 is to reserve pages as Guard pages in partial page free situation.
878
879 @param[in,out] Memory Base address of memory to free.
880 @param[in,out] NumberOfPages Size of memory to free.
881
882 @return VOID.
883**/
884VOID
885AdjustMemoryF (
886 IN OUT EFI_PHYSICAL_ADDRESS *Memory,
887 IN OUT UINTN *NumberOfPages
888 )
889{
890 EFI_PHYSICAL_ADDRESS Start;
891 EFI_PHYSICAL_ADDRESS MemoryToTest;
892 UINTN PagesToFree;
893
894 if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages == 0) {
895 return;
896 }
897
898 Start = *Memory;
899 PagesToFree = *NumberOfPages;
900
901 //
902 // Head Guard must be one page before, if any.
903 //
904 MemoryToTest = Start - EFI_PAGES_TO_SIZE (1);
905 if (IsHeadGuard (MemoryToTest)) {
906 if (!IsMemoryGuarded (MemoryToTest - EFI_PAGES_TO_SIZE (1))) {
907 //
908 // If the head Guard is not a tail Guard of adjacent memory block,
909 // free it; otherwise, keep it.
910 //
911 Start -= EFI_PAGES_TO_SIZE (1);
912 PagesToFree += 1;
913 }
914 } else if (IsMemoryGuarded (MemoryToTest)) {
915 //
916 // Pages before memory to free are still in Guard. It's a partial free
917 // case. We need to keep one page to be a tail Guard.
918 //
919 Start += EFI_PAGES_TO_SIZE (1);
920 PagesToFree -= 1;
921 }
922
923 //
924 // Tail Guard must be the page after this memory block to free, if any.
925 //
926 MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
927 if (IsTailGuard (MemoryToTest)) {
928 if (!IsMemoryGuarded (MemoryToTest + EFI_PAGES_TO_SIZE (1))) {
929 //
930 // If the tail Guard is not a head Guard of adjacent memory block,
931 // free it; otherwise, keep it.
932 //
933 PagesToFree += 1;
934 }
935 } else if (IsMemoryGuarded (MemoryToTest)) {
936 //
937 // Pages after memory to free are still in Guard. It's a partial free
938 // case. We need to keep one page to be a head Guard.
939 //
940 PagesToFree -= 1;
941 }
942
943 *Memory = Start;
944 *NumberOfPages = PagesToFree;
945}
946
947/**
948 Adjust the base and number of pages to really allocate according to Guard.
949
950 @param[in,out] Memory Base address of free memory.
951 @param[in,out] NumberOfPages Size of memory to allocate.
952
953 @return VOID.
954**/
955VOID
956AdjustMemoryA (
957 IN OUT EFI_PHYSICAL_ADDRESS *Memory,
958 IN OUT UINTN *NumberOfPages
959 )
960{
961 //
962 // FindFreePages() has already taken the Guard into account. It's safe to
963 // adjust the start address and/or number of pages here, to make sure that
964 // the Guards are also "allocated".
965 //
966 if (!IsGuardPage (*Memory + EFI_PAGES_TO_SIZE (*NumberOfPages))) {
967 // No tail Guard, add one.
968 *NumberOfPages += 1;
969 }
970
971 if (!IsGuardPage (*Memory - EFI_PAGE_SIZE)) {
972 // No head Guard, add one.
973 *Memory -= EFI_PAGE_SIZE;
974 *NumberOfPages += 1;
975 }
976}
977
978/**
979 Adjust the pool head position to make sure the Guard page is adjavent to
980 pool tail or pool head.
981
982 @param[in] Memory Base address of memory allocated.
983 @param[in] NoPages Number of pages actually allocated.
984 @param[in] Size Size of memory requested.
985 (plus pool head/tail overhead)
986
987 @return Address of pool head.
988**/
989VOID *
990AdjustPoolHeadA (
991 IN EFI_PHYSICAL_ADDRESS Memory,
992 IN UINTN NoPages,
993 IN UINTN Size
994 )
995{
996 if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
997 //
998 // Pool head is put near the head Guard
999 //
1000 return (VOID *)(UINTN)Memory;
1001 }
1002
1003 //
1004 // Pool head is put near the tail Guard
1005 //
1006 return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
1007}
1008
1009/**
1010 Get the page base address according to pool head address.
1011
1012 @param[in] Memory Head address of pool to free.
1013
1014 @return Address of pool head.
1015**/
1016VOID *
1017AdjustPoolHeadF (
1018 IN EFI_PHYSICAL_ADDRESS Memory
1019 )
1020{
1021 if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
1022 //
1023 // Pool head is put near the head Guard
1024 //
1025 return (VOID *)(UINTN)Memory;
1026 }
1027
1028 //
1029 // Pool head is put near the tail Guard
1030 //
1031 return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK);
1032}
1033
1034/**
1035 Allocate or free guarded memory.
1036
1037 @param[in] Start Start address of memory to allocate or free.
1038 @param[in] NumberOfPages Memory size in pages.
1039 @param[in] NewType Memory type to convert to.
1040
1041 @return VOID.
1042**/
1043EFI_STATUS
1044CoreConvertPagesWithGuard (
1045 IN UINT64 Start,
1046 IN UINTN NumberOfPages,
1047 IN EFI_MEMORY_TYPE NewType
1048 )
1049{
1050 if (NewType == EfiConventionalMemory) {
1051 AdjustMemoryF (&Start, &NumberOfPages);
1052 } else {
1053 AdjustMemoryA (&Start, &NumberOfPages);
1054 }
1055
1056 return CoreConvertPages(Start, NumberOfPages, NewType);
1057}
1058
1059/**
1060 Helper function to convert a UINT64 value in binary to a string.
1061
1062 @param[in] Value Value of a UINT64 integer.
1063 @param[out] BinString String buffer to contain the conversion result.
1064
1065 @return VOID.
1066**/
1067VOID
1068Uint64ToBinString (
1069 IN UINT64 Value,
1070 OUT CHAR8 *BinString
1071 )
1072{
1073 UINTN Index;
1074
1075 if (BinString == NULL) {
1076 return;
1077 }
1078
1079 for (Index = 64; Index > 0; --Index) {
1080 BinString[Index - 1] = '0' + (Value & 1);
1081 Value = RShiftU64 (Value, 1);
1082 }
1083 BinString[64] = '\0';
1084}
1085
1086/**
1087 Dump the guarded memory bit map.
1088**/
1089VOID
1090EFIAPI
1091DumpGuardedMemoryBitmap (
1092 VOID
1093 )
1094{
1095 UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
1096 UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
1097 UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
1098 UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
1099 UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
1100 UINT64 TableEntry;
1101 UINT64 Address;
1102 INTN Level;
1103 UINTN RepeatZero;
1104 CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
1105 CHAR8 *Ruler1;
1106 CHAR8 *Ruler2;
1107
1108 if (mGuardedMemoryMap == 0) {
1109 return;
1110 }
1111
1112 Ruler1 = " 3 2 1 0";
1113 Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
1114
1115 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "============================="
1116 " Guarded Memory Bitmap "
1117 "==============================\r\n"));
1118 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
1119 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
1120
1121 CopyMem (Entries, mLevelMask, sizeof (Entries));
1122 CopyMem (Shifts, mLevelShift, sizeof (Shifts));
1123
1124 SetMem (Indices, sizeof(Indices), 0);
1125 SetMem (Tables, sizeof(Tables), 0);
1126 SetMem (Addresses, sizeof(Addresses), 0);
1127
1128 Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
1129 Tables[Level] = mGuardedMemoryMap;
1130 Address = 0;
1131 RepeatZero = 0;
1132
1133 while (TRUE) {
1134 if (Indices[Level] > Entries[Level]) {
1135
1136 Tables[Level] = 0;
1137 Level -= 1;
1138 RepeatZero = 0;
1139
1140 DEBUG ((
1141 HEAP_GUARD_DEBUG_LEVEL,
1142 "========================================="
1143 "=========================================\r\n"
1144 ));
1145
1146 } else {
1147
1148 TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
1149 Address = Addresses[Level];
1150
1151 if (TableEntry == 0) {
1152
1153 if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
1154 if (RepeatZero == 0) {
1155 Uint64ToBinString(TableEntry, String);
1156 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
1157 } else if (RepeatZero == 1) {
1158 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
1159 }
1160 RepeatZero += 1;
1161 }
1162
1163 } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
1164
1165 Level += 1;
1166 Tables[Level] = TableEntry;
1167 Addresses[Level] = Address;
1168 Indices[Level] = 0;
1169 RepeatZero = 0;
1170
1171 continue;
1172
1173 } else {
1174
1175 RepeatZero = 0;
1176 Uint64ToBinString(TableEntry, String);
1177 DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
1178
1179 }
1180 }
1181
1182 if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
1183 break;
1184 }
1185
1186 Indices[Level] += 1;
1187 Address = (Level == 0) ? 0 : Addresses[Level - 1];
1188 Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
1189
1190 }
1191}
1192