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