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