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