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