]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
UefiCpuPkg/PiSmmCpuDxeSmm: Make code consistent with comments
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / SmmCpuMemoryManagement.c
CommitLineData
717fb604
JY
1/** @file\r
2\r
3eb69b08 3Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
0acd8697 4SPDX-License-Identifier: BSD-2-Clause-Patent\r
717fb604
JY
5\r
6**/\r
7\r
8#include "PiSmmCpuDxeSmm.h"\r
9\r
ac6613db
JY
10//\r
11// attributes for reserved memory before it is promoted to system memory\r
12//\r
13#define EFI_MEMORY_PRESENT 0x0100000000000000ULL\r
14#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL\r
15#define EFI_MEMORY_TESTED 0x0400000000000000ULL\r
16\r
d2fc7711
JY
17#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
18 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))\r
19\r
20EFI_MEMORY_DESCRIPTOR *mUefiMemoryMap;\r
21UINTN mUefiMemoryMapSize;\r
22UINTN mUefiDescriptorSize;\r
23\r
ac6613db
JY
24EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mGcdMemSpace = NULL;\r
25UINTN mGcdMemNumberOfDesc = 0;\r
26\r
8a2e1a9d
JY
27EFI_MEMORY_ATTRIBUTES_TABLE *mUefiMemoryAttributesTable = NULL;\r
28\r
717fb604
JY
29PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {\r
30 {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},\r
31 {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},\r
32 {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},\r
33};\r
34\r
3eb69b08
JY
35UINTN mInternalGr3;\r
36\r
37/**\r
38 Set the internal page table base address.\r
39 If it is non zero, further MemoryAttribute modification will be on this page table.\r
40 If it is zero, further MemoryAttribute modification will be on real page table.\r
41\r
42 @param Cr3 page table base.\r
43**/\r
44VOID\r
45SetPageTableBase (\r
46 IN UINTN Cr3\r
47 )\r
48{\r
49 mInternalGr3 = Cr3;\r
50}\r
51\r
717fb604
JY
52/**\r
53 Return page table base.\r
54\r
55 @return page table base.\r
56**/\r
57UINTN\r
58GetPageTableBase (\r
59 VOID\r
60 )\r
61{\r
3eb69b08
JY
62 if (mInternalGr3 != 0) {\r
63 return mInternalGr3;\r
64 }\r
717fb604
JY
65 return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);\r
66}\r
67\r
68/**\r
69 Return length according to page attributes.\r
70\r
71 @param[in] PageAttributes The page attribute of the page entry.\r
72\r
73 @return The length of page entry.\r
74**/\r
75UINTN\r
76PageAttributeToLength (\r
77 IN PAGE_ATTRIBUTE PageAttribute\r
78 )\r
79{\r
80 UINTN Index;\r
81 for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {\r
82 if (PageAttribute == mPageAttributeTable[Index].Attribute) {\r
83 return (UINTN)mPageAttributeTable[Index].Length;\r
84 }\r
85 }\r
86 return 0;\r
87}\r
88\r
89/**\r
90 Return address mask according to page attributes.\r
91\r
92 @param[in] PageAttributes The page attribute of the page entry.\r
93\r
94 @return The address mask of page entry.\r
95**/\r
96UINTN\r
97PageAttributeToMask (\r
98 IN PAGE_ATTRIBUTE PageAttribute\r
99 )\r
100{\r
101 UINTN Index;\r
102 for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {\r
103 if (PageAttribute == mPageAttributeTable[Index].Attribute) {\r
104 return (UINTN)mPageAttributeTable[Index].AddressMask;\r
105 }\r
106 }\r
107 return 0;\r
108}\r
109\r
110/**\r
111 Return page table entry to match the address.\r
112\r
113 @param[in] Address The address to be checked.\r
114 @param[out] PageAttributes The page attribute of the page entry.\r
115\r
116 @return The page entry.\r
117**/\r
118VOID *\r
119GetPageTableEntry (\r
120 IN PHYSICAL_ADDRESS Address,\r
121 OUT PAGE_ATTRIBUTE *PageAttribute\r
122 )\r
123{\r
124 UINTN Index1;\r
125 UINTN Index2;\r
126 UINTN Index3;\r
127 UINTN Index4;\r
4eee0cc7 128 UINTN Index5;\r
717fb604
JY
129 UINT64 *L1PageTable;\r
130 UINT64 *L2PageTable;\r
131 UINT64 *L3PageTable;\r
132 UINT64 *L4PageTable;\r
4eee0cc7
RN
133 UINT64 *L5PageTable;\r
134 IA32_CR4 Cr4;\r
135 BOOLEAN Enable5LevelPaging;\r
717fb604 136\r
4eee0cc7 137 Index5 = ((UINTN)RShiftU64 (Address, 48)) & PAGING_PAE_INDEX_MASK;\r
717fb604
JY
138 Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;\r
139 Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;\r
140 Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;\r
141 Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;\r
142\r
4eee0cc7
RN
143 Cr4.UintN = AsmReadCr4 ();\r
144 Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);\r
145\r
717fb604 146 if (sizeof(UINTN) == sizeof(UINT64)) {\r
4eee0cc7
RN
147 if (Enable5LevelPaging) {\r
148 L5PageTable = (UINT64 *)GetPageTableBase ();\r
149 if (L5PageTable[Index5] == 0) {\r
150 *PageAttribute = PageNone;\r
151 return NULL;\r
152 }\r
153\r
154 L4PageTable = (UINT64 *)(UINTN)(L5PageTable[Index5] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
155 } else {\r
156 L4PageTable = (UINT64 *)GetPageTableBase ();\r
157 }\r
717fb604
JY
158 if (L4PageTable[Index4] == 0) {\r
159 *PageAttribute = PageNone;\r
160 return NULL;\r
161 }\r
162\r
241f9149 163 L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
164 } else {\r
165 L3PageTable = (UINT64 *)GetPageTableBase ();\r
166 }\r
167 if (L3PageTable[Index3] == 0) {\r
168 *PageAttribute = PageNone;\r
169 return NULL;\r
170 }\r
171 if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {\r
172 // 1G\r
173 *PageAttribute = Page1G;\r
174 return &L3PageTable[Index3];\r
175 }\r
176\r
241f9149 177 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
178 if (L2PageTable[Index2] == 0) {\r
179 *PageAttribute = PageNone;\r
180 return NULL;\r
181 }\r
182 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
183 // 2M\r
184 *PageAttribute = Page2M;\r
185 return &L2PageTable[Index2];\r
186 }\r
187\r
188 // 4k\r
241f9149 189 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
190 if ((L1PageTable[Index1] == 0) && (Address != 0)) {\r
191 *PageAttribute = PageNone;\r
192 return NULL;\r
193 }\r
194 *PageAttribute = Page4K;\r
195 return &L1PageTable[Index1];\r
196}\r
197\r
198/**\r
199 Return memory attributes of page entry.\r
200\r
201 @param[in] PageEntry The page entry.\r
202\r
203 @return Memory attributes of page entry.\r
204**/\r
205UINT64\r
206GetAttributesFromPageEntry (\r
207 IN UINT64 *PageEntry\r
208 )\r
209{\r
210 UINT64 Attributes;\r
211 Attributes = 0;\r
212 if ((*PageEntry & IA32_PG_P) == 0) {\r
213 Attributes |= EFI_MEMORY_RP;\r
214 }\r
215 if ((*PageEntry & IA32_PG_RW) == 0) {\r
216 Attributes |= EFI_MEMORY_RO;\r
217 }\r
218 if ((*PageEntry & IA32_PG_NX) != 0) {\r
219 Attributes |= EFI_MEMORY_XP;\r
220 }\r
221 return Attributes;\r
222}\r
223\r
224/**\r
225 Modify memory attributes of page entry.\r
226\r
227 @param[in] PageEntry The page entry.\r
228 @param[in] Attributes The bit mask of attributes to modify for the memory region.\r
229 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.\r
230 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.\r
231**/\r
232VOID\r
233ConvertPageEntryAttribute (\r
234 IN UINT64 *PageEntry,\r
235 IN UINT64 Attributes,\r
236 IN BOOLEAN IsSet,\r
237 OUT BOOLEAN *IsModified\r
238 )\r
239{\r
240 UINT64 CurrentPageEntry;\r
241 UINT64 NewPageEntry;\r
242\r
243 CurrentPageEntry = *PageEntry;\r
244 NewPageEntry = CurrentPageEntry;\r
245 if ((Attributes & EFI_MEMORY_RP) != 0) {\r
246 if (IsSet) {\r
247 NewPageEntry &= ~(UINT64)IA32_PG_P;\r
248 } else {\r
249 NewPageEntry |= IA32_PG_P;\r
250 }\r
251 }\r
252 if ((Attributes & EFI_MEMORY_RO) != 0) {\r
253 if (IsSet) {\r
254 NewPageEntry &= ~(UINT64)IA32_PG_RW;\r
3eb69b08
JY
255 if (mInternalGr3 != 0) {\r
256 // Environment setup\r
257 // ReadOnly page need set Dirty bit for shadow stack\r
258 NewPageEntry |= IA32_PG_D;\r
259 // Clear user bit for supervisor shadow stack\r
260 NewPageEntry &= ~(UINT64)IA32_PG_U;\r
261 } else {\r
262 // Runtime update\r
263 // Clear dirty bit for non shadow stack, to protect RO page.\r
264 NewPageEntry &= ~(UINT64)IA32_PG_D;\r
265 }\r
717fb604
JY
266 } else {\r
267 NewPageEntry |= IA32_PG_RW;\r
268 }\r
269 }\r
270 if ((Attributes & EFI_MEMORY_XP) != 0) {\r
750ec4ca
JY
271 if (mXdSupported) {\r
272 if (IsSet) {\r
273 NewPageEntry |= IA32_PG_NX;\r
274 } else {\r
275 NewPageEntry &= ~IA32_PG_NX;\r
276 }\r
717fb604
JY
277 }\r
278 }\r
279 *PageEntry = NewPageEntry;\r
280 if (CurrentPageEntry != NewPageEntry) {\r
281 *IsModified = TRUE;\r
282 DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));\r
283 DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));\r
284 } else {\r
285 *IsModified = FALSE;\r
286 }\r
287}\r
288\r
289/**\r
290 This function returns if there is need to split page entry.\r
291\r
292 @param[in] BaseAddress The base address to be checked.\r
293 @param[in] Length The length to be checked.\r
294 @param[in] PageEntry The page entry to be checked.\r
295 @param[in] PageAttribute The page attribute of the page entry.\r
296\r
297 @retval SplitAttributes on if there is need to split page entry.\r
298**/\r
299PAGE_ATTRIBUTE\r
300NeedSplitPage (\r
301 IN PHYSICAL_ADDRESS BaseAddress,\r
302 IN UINT64 Length,\r
303 IN UINT64 *PageEntry,\r
304 IN PAGE_ATTRIBUTE PageAttribute\r
305 )\r
306{\r
307 UINT64 PageEntryLength;\r
308\r
309 PageEntryLength = PageAttributeToLength (PageAttribute);\r
310\r
311 if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {\r
312 return PageNone;\r
313 }\r
314\r
315 if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {\r
316 return Page4K;\r
317 }\r
318\r
319 return Page2M;\r
320}\r
321\r
322/**\r
323 This function splits one page entry to small page entries.\r
324\r
325 @param[in] PageEntry The page entry to be splitted.\r
326 @param[in] PageAttribute The page attribute of the page entry.\r
327 @param[in] SplitAttribute How to split the page entry.\r
328\r
329 @retval RETURN_SUCCESS The page entry is splitted.\r
330 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.\r
331 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.\r
332**/\r
333RETURN_STATUS\r
334SplitPage (\r
335 IN UINT64 *PageEntry,\r
336 IN PAGE_ATTRIBUTE PageAttribute,\r
337 IN PAGE_ATTRIBUTE SplitAttribute\r
338 )\r
339{\r
340 UINT64 BaseAddress;\r
341 UINT64 *NewPageEntry;\r
342 UINTN Index;\r
343\r
344 ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);\r
345\r
346 if (PageAttribute == Page2M) {\r
347 //\r
348 // Split 2M to 4K\r
349 //\r
350 ASSERT (SplitAttribute == Page4K);\r
351 if (SplitAttribute == Page4K) {\r
352 NewPageEntry = AllocatePageTableMemory (1);\r
353 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
354 if (NewPageEntry == NULL) {\r
355 return RETURN_OUT_OF_RESOURCES;\r
356 }\r
357 BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;\r
358 for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
241f9149 359 NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | mAddressEncMask | ((*PageEntry) & PAGE_PROGATE_BITS);\r
717fb604 360 }\r
241f9149 361 (*PageEntry) = (UINT64)(UINTN)NewPageEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
717fb604
JY
362 return RETURN_SUCCESS;\r
363 } else {\r
364 return RETURN_UNSUPPORTED;\r
365 }\r
366 } else if (PageAttribute == Page1G) {\r
367 //\r
368 // Split 1G to 2M\r
369 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.\r
370 //\r
371 ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);\r
372 if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {\r
373 NewPageEntry = AllocatePageTableMemory (1);\r
374 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
375 if (NewPageEntry == NULL) {\r
376 return RETURN_OUT_OF_RESOURCES;\r
377 }\r
378 BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;\r
379 for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
241f9149 380 NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) | mAddressEncMask | IA32_PG_PS | ((*PageEntry) & PAGE_PROGATE_BITS);\r
717fb604 381 }\r
241f9149 382 (*PageEntry) = (UINT64)(UINTN)NewPageEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
717fb604
JY
383 return RETURN_SUCCESS;\r
384 } else {\r
385 return RETURN_UNSUPPORTED;\r
386 }\r
387 } else {\r
388 return RETURN_UNSUPPORTED;\r
389 }\r
390}\r
391\r
392/**\r
393 This function modifies the page attributes for the memory region specified by BaseAddress and\r
394 Length from their current attributes to the attributes specified by Attributes.\r
395\r
396 Caller should make sure BaseAddress and Length is at page boundary.\r
397\r
398 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
399 @param[in] Length The size in bytes of the memory region.\r
400 @param[in] Attributes The bit mask of attributes to modify for the memory region.\r
401 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.\r
402 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.\r
403 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.\r
404\r
405 @retval RETURN_SUCCESS The attributes were modified for the memory region.\r
406 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
407 BaseAddress and Length cannot be modified.\r
408 @retval RETURN_INVALID_PARAMETER Length is zero.\r
409 Attributes specified an illegal combination of attributes that\r
410 cannot be set together.\r
411 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
412 the memory resource range.\r
413 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory\r
414 resource range specified by BaseAddress and Length.\r
415 The bit mask of attributes is not support for the memory resource\r
416 range specified by BaseAddress and Length.\r
417**/\r
418RETURN_STATUS\r
419EFIAPI\r
420ConvertMemoryPageAttributes (\r
421 IN PHYSICAL_ADDRESS BaseAddress,\r
422 IN UINT64 Length,\r
423 IN UINT64 Attributes,\r
424 IN BOOLEAN IsSet,\r
425 OUT BOOLEAN *IsSplitted, OPTIONAL\r
426 OUT BOOLEAN *IsModified OPTIONAL\r
427 )\r
428{\r
429 UINT64 *PageEntry;\r
430 PAGE_ATTRIBUTE PageAttribute;\r
431 UINTN PageEntryLength;\r
432 PAGE_ATTRIBUTE SplitAttribute;\r
433 RETURN_STATUS Status;\r
434 BOOLEAN IsEntryModified;\r
714c2603 435 EFI_PHYSICAL_ADDRESS MaximumSupportMemAddress;\r
717fb604
JY
436\r
437 ASSERT (Attributes != 0);\r
438 ASSERT ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP)) == 0);\r
439\r
440 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);\r
441 ASSERT ((Length & (SIZE_4KB - 1)) == 0);\r
442\r
443 if (Length == 0) {\r
444 return RETURN_INVALID_PARAMETER;\r
445 }\r
446\r
714c2603
SZ
447 MaximumSupportMemAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, mPhysicalAddressBits) - 1);\r
448 if (BaseAddress > MaximumSupportMemAddress) {\r
449 return RETURN_UNSUPPORTED;\r
450 }\r
451 if (Length > MaximumSupportMemAddress) {\r
452 return RETURN_UNSUPPORTED;\r
453 }\r
454 if ((Length != 0) && (BaseAddress > MaximumSupportMemAddress - (Length - 1))) {\r
455 return RETURN_UNSUPPORTED;\r
456 }\r
457\r
717fb604
JY
458// DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));\r
459\r
460 if (IsSplitted != NULL) {\r
461 *IsSplitted = FALSE;\r
462 }\r
463 if (IsModified != NULL) {\r
464 *IsModified = FALSE;\r
465 }\r
466\r
467 //\r
468 // Below logic is to check 2M/4K page to make sure we donot waist memory.\r
469 //\r
470 while (Length != 0) {\r
471 PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);\r
472 if (PageEntry == NULL) {\r
473 return RETURN_UNSUPPORTED;\r
474 }\r
475 PageEntryLength = PageAttributeToLength (PageAttribute);\r
476 SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute);\r
477 if (SplitAttribute == PageNone) {\r
478 ConvertPageEntryAttribute (PageEntry, Attributes, IsSet, &IsEntryModified);\r
479 if (IsEntryModified) {\r
480 if (IsModified != NULL) {\r
481 *IsModified = TRUE;\r
482 }\r
483 }\r
484 //\r
485 // Convert success, move to next\r
486 //\r
487 BaseAddress += PageEntryLength;\r
488 Length -= PageEntryLength;\r
489 } else {\r
490 Status = SplitPage (PageEntry, PageAttribute, SplitAttribute);\r
491 if (RETURN_ERROR (Status)) {\r
492 return RETURN_UNSUPPORTED;\r
493 }\r
494 if (IsSplitted != NULL) {\r
495 *IsSplitted = TRUE;\r
496 }\r
497 if (IsModified != NULL) {\r
498 *IsModified = TRUE;\r
499 }\r
500 //\r
501 // Just split current page\r
502 // Convert success in next around\r
503 //\r
504 }\r
505 }\r
506\r
507 return RETURN_SUCCESS;\r
508}\r
509\r
510/**\r
511 FlushTlb on current processor.\r
512\r
513 @param[in,out] Buffer Pointer to private data buffer.\r
514**/\r
515VOID\r
516EFIAPI\r
517FlushTlbOnCurrentProcessor (\r
518 IN OUT VOID *Buffer\r
519 )\r
520{\r
521 CpuFlushTlb ();\r
522}\r
523\r
524/**\r
525 FlushTlb for all processors.\r
526**/\r
527VOID\r
528FlushTlbForAll (\r
529 VOID\r
530 )\r
531{\r
532 UINTN Index;\r
533\r
534 FlushTlbOnCurrentProcessor (NULL);\r
535\r
536 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {\r
537 if (Index != gSmst->CurrentlyExecutingCpu) {\r
538 // Force to start up AP in blocking mode,\r
539 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor, Index, NULL);\r
540 // Do not check return status, because AP might not be present in some corner cases.\r
541 }\r
542 }\r
543}\r
544\r
545/**\r
546 This function sets the attributes for the memory region specified by BaseAddress and\r
547 Length from their current attributes to the attributes specified by Attributes.\r
548\r
549 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
550 @param[in] Length The size in bytes of the memory region.\r
551 @param[in] Attributes The bit mask of attributes to set for the memory region.\r
552 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.\r
553\r
554 @retval EFI_SUCCESS The attributes were set for the memory region.\r
555 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
556 BaseAddress and Length cannot be modified.\r
557 @retval EFI_INVALID_PARAMETER Length is zero.\r
558 Attributes specified an illegal combination of attributes that\r
559 cannot be set together.\r
560 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
561 the memory resource range.\r
562 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
563 resource range specified by BaseAddress and Length.\r
564 The bit mask of attributes is not support for the memory resource\r
565 range specified by BaseAddress and Length.\r
566\r
567**/\r
568EFI_STATUS\r
569EFIAPI\r
570SmmSetMemoryAttributesEx (\r
571 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
572 IN UINT64 Length,\r
573 IN UINT64 Attributes,\r
574 OUT BOOLEAN *IsSplitted OPTIONAL\r
575 )\r
576{\r
577 EFI_STATUS Status;\r
578 BOOLEAN IsModified;\r
579\r
580 Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, TRUE, IsSplitted, &IsModified);\r
581 if (!EFI_ERROR(Status)) {\r
582 if (IsModified) {\r
583 //\r
584 // Flush TLB as last step\r
585 //\r
586 FlushTlbForAll();\r
587 }\r
588 }\r
589\r
590 return Status;\r
591}\r
592\r
593/**\r
594 This function clears the attributes for the memory region specified by BaseAddress and\r
595 Length from their current attributes to the attributes specified by Attributes.\r
596\r
597 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
598 @param[in] Length The size in bytes of the memory region.\r
599 @param[in] Attributes The bit mask of attributes to clear for the memory region.\r
600 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.\r
601\r
602 @retval EFI_SUCCESS The attributes were cleared for the memory region.\r
603 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
604 BaseAddress and Length cannot be modified.\r
605 @retval EFI_INVALID_PARAMETER Length is zero.\r
606 Attributes specified an illegal combination of attributes that\r
aae02dcc 607 cannot be cleared together.\r
717fb604
JY
608 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
609 the memory resource range.\r
610 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
611 resource range specified by BaseAddress and Length.\r
aae02dcc 612 The bit mask of attributes is not supported for the memory resource\r
717fb604
JY
613 range specified by BaseAddress and Length.\r
614\r
615**/\r
616EFI_STATUS\r
617EFIAPI\r
618SmmClearMemoryAttributesEx (\r
619 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
620 IN UINT64 Length,\r
621 IN UINT64 Attributes,\r
622 OUT BOOLEAN *IsSplitted OPTIONAL\r
623 )\r
624{\r
625 EFI_STATUS Status;\r
626 BOOLEAN IsModified;\r
627\r
628 Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, FALSE, IsSplitted, &IsModified);\r
629 if (!EFI_ERROR(Status)) {\r
630 if (IsModified) {\r
631 //\r
632 // Flush TLB as last step\r
633 //\r
634 FlushTlbForAll();\r
635 }\r
636 }\r
637\r
638 return Status;\r
639}\r
640\r
641/**\r
642 This function sets the attributes for the memory region specified by BaseAddress and\r
643 Length from their current attributes to the attributes specified by Attributes.\r
644\r
645 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
646 @param[in] Length The size in bytes of the memory region.\r
647 @param[in] Attributes The bit mask of attributes to set for the memory region.\r
648\r
649 @retval EFI_SUCCESS The attributes were set for the memory region.\r
650 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
651 BaseAddress and Length cannot be modified.\r
652 @retval EFI_INVALID_PARAMETER Length is zero.\r
653 Attributes specified an illegal combination of attributes that\r
654 cannot be set together.\r
655 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
656 the memory resource range.\r
657 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
658 resource range specified by BaseAddress and Length.\r
aae02dcc 659 The bit mask of attributes is not supported for the memory resource\r
717fb604
JY
660 range specified by BaseAddress and Length.\r
661\r
662**/\r
663EFI_STATUS\r
664EFIAPI\r
665SmmSetMemoryAttributes (\r
666 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
667 IN UINT64 Length,\r
668 IN UINT64 Attributes\r
669 )\r
670{\r
671 return SmmSetMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);\r
672}\r
673\r
674/**\r
675 This function clears the attributes for the memory region specified by BaseAddress and\r
676 Length from their current attributes to the attributes specified by Attributes.\r
677\r
678 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
679 @param[in] Length The size in bytes of the memory region.\r
680 @param[in] Attributes The bit mask of attributes to clear for the memory region.\r
681\r
682 @retval EFI_SUCCESS The attributes were cleared for the memory region.\r
683 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
684 BaseAddress and Length cannot be modified.\r
685 @retval EFI_INVALID_PARAMETER Length is zero.\r
686 Attributes specified an illegal combination of attributes that\r
aae02dcc 687 cannot be cleared together.\r
717fb604
JY
688 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
689 the memory resource range.\r
690 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
691 resource range specified by BaseAddress and Length.\r
aae02dcc 692 The bit mask of attributes is not supported for the memory resource\r
717fb604
JY
693 range specified by BaseAddress and Length.\r
694\r
695**/\r
696EFI_STATUS\r
697EFIAPI\r
698SmmClearMemoryAttributes (\r
699 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
700 IN UINT64 Length,\r
701 IN UINT64 Attributes\r
702 )\r
703{\r
704 return SmmClearMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);\r
705}\r
706\r
3eb69b08
JY
707/**\r
708 Set ShadowStack memory.\r
709\r
710 @param[in] Cr3 The page table base address.\r
711 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
712 @param[in] Length The size in bytes of the memory region.\r
713\r
714 @retval EFI_SUCCESS The shadow stack memory is set.\r
715**/\r
716EFI_STATUS\r
717SetShadowStack (\r
718 IN UINTN Cr3,\r
719 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
720 IN UINT64 Length\r
721 )\r
722{\r
723 EFI_STATUS Status;\r
724\r
725 SetPageTableBase (Cr3);\r
726\r
727 Status = SmmSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_RO);\r
728\r
729 SetPageTableBase (0);\r
730\r
731 return Status;\r
732}\r
733\r
734/**\r
735 Set not present memory.\r
736\r
737 @param[in] Cr3 The page table base address.\r
738 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
739 @param[in] Length The size in bytes of the memory region.\r
717fb604 740\r
3eb69b08
JY
741 @retval EFI_SUCCESS The not present memory is set.\r
742**/\r
743EFI_STATUS\r
744SetNotPresentPage (\r
745 IN UINTN Cr3,\r
746 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
747 IN UINT64 Length\r
748 )\r
749{\r
750 EFI_STATUS Status;\r
751\r
752 SetPageTableBase (Cr3);\r
753\r
754 Status = SmmSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_RP);\r
755\r
756 SetPageTableBase (0);\r
757\r
758 return Status;\r
759}\r
717fb604
JY
760\r
761/**\r
762 Retrieves a pointer to the system configuration table from the SMM System Table\r
763 based on a specified GUID.\r
764\r
765 @param[in] TableGuid The pointer to table's GUID type.\r
766 @param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.\r
767\r
768 @retval EFI_SUCCESS A configuration table matching TableGuid was found.\r
769 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.\r
770\r
771**/\r
772EFI_STATUS\r
773EFIAPI\r
774SmmGetSystemConfigurationTable (\r
775 IN EFI_GUID *TableGuid,\r
776 OUT VOID **Table\r
777 )\r
778{\r
779 UINTN Index;\r
780\r
781 ASSERT (TableGuid != NULL);\r
782 ASSERT (Table != NULL);\r
783\r
784 *Table = NULL;\r
785 for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {\r
786 if (CompareGuid (TableGuid, &(gSmst->SmmConfigurationTable[Index].VendorGuid))) {\r
787 *Table = gSmst->SmmConfigurationTable[Index].VendorTable;\r
788 return EFI_SUCCESS;\r
789 }\r
790 }\r
791\r
792 return EFI_NOT_FOUND;\r
793}\r
794\r
795/**\r
796 This function sets SMM save state buffer to be RW and XP.\r
797**/\r
798VOID\r
799PatchSmmSaveStateMap (\r
800 VOID\r
801 )\r
802{\r
803 UINTN Index;\r
804 UINTN TileCodeSize;\r
805 UINTN TileDataSize;\r
806 UINTN TileSize;\r
807\r
808 TileCodeSize = GetSmiHandlerSize ();\r
809 TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);\r
f12367a0 810 TileDataSize = (SMRAM_SAVE_STATE_MAP_OFFSET - SMM_PSD_OFFSET) + sizeof (SMRAM_SAVE_STATE_MAP);\r
717fb604
JY
811 TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);\r
812 TileSize = TileDataSize + TileCodeSize - 1;\r
813 TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);\r
814\r
815 DEBUG ((DEBUG_INFO, "PatchSmmSaveStateMap:\n"));\r
816 for (Index = 0; Index < mMaxNumberOfCpus - 1; Index++) {\r
817 //\r
818 // Code\r
819 //\r
820 SmmSetMemoryAttributes (\r
821 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,\r
822 TileCodeSize,\r
823 EFI_MEMORY_RO\r
824 );\r
825 SmmClearMemoryAttributes (\r
826 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,\r
827 TileCodeSize,\r
828 EFI_MEMORY_XP\r
829 );\r
830\r
831 //\r
832 // Data\r
833 //\r
834 SmmClearMemoryAttributes (\r
835 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,\r
836 TileSize - TileCodeSize,\r
837 EFI_MEMORY_RO\r
838 );\r
839 SmmSetMemoryAttributes (\r
840 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,\r
841 TileSize - TileCodeSize,\r
842 EFI_MEMORY_XP\r
843 );\r
844 }\r
845\r
846 //\r
847 // Code\r
848 //\r
849 SmmSetMemoryAttributes (\r
850 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,\r
851 TileCodeSize,\r
852 EFI_MEMORY_RO\r
853 );\r
854 SmmClearMemoryAttributes (\r
855 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,\r
856 TileCodeSize,\r
857 EFI_MEMORY_XP\r
858 );\r
859\r
860 //\r
861 // Data\r
862 //\r
863 SmmClearMemoryAttributes (\r
864 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,\r
865 SIZE_32KB - TileCodeSize,\r
866 EFI_MEMORY_RO\r
867 );\r
868 SmmSetMemoryAttributes (\r
869 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,\r
870 SIZE_32KB - TileCodeSize,\r
871 EFI_MEMORY_XP\r
872 );\r
873}\r
874\r
6e601a41
SZ
875/**\r
876 This function sets GDT/IDT buffer to be RO and XP.\r
877**/\r
878VOID\r
879PatchGdtIdtMap (\r
880 VOID\r
881 )\r
882{\r
883 EFI_PHYSICAL_ADDRESS BaseAddress;\r
884 UINTN Size;\r
885\r
886 //\r
887 // GDT\r
888 //\r
889 DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));\r
890\r
891 BaseAddress = mGdtBuffer;\r
892 Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);\r
893 //\r
894 // The range should have been set to RO\r
895 // if it is allocated with EfiRuntimeServicesCode.\r
896 //\r
897 SmmSetMemoryAttributes (\r
898 BaseAddress,\r
899 Size,\r
900 EFI_MEMORY_XP\r
901 );\r
902\r
903 //\r
904 // IDT\r
905 //\r
906 DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));\r
907\r
908 BaseAddress = gcSmiIdtr.Base;\r
909 Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);\r
fe90d0d2
SZ
910 //\r
911 // The range should have been set to RO\r
912 // if it is allocated with EfiRuntimeServicesCode.\r
913 //\r
6e601a41
SZ
914 SmmSetMemoryAttributes (\r
915 BaseAddress,\r
916 Size,\r
917 EFI_MEMORY_XP\r
918 );\r
919}\r
920\r
717fb604
JY
921/**\r
922 This function sets memory attribute according to MemoryAttributesTable.\r
923**/\r
924VOID\r
925SetMemMapAttributes (\r
926 VOID\r
927 )\r
928{\r
929 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
930 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;\r
931 UINTN MemoryMapEntryCount;\r
932 UINTN DescriptorSize;\r
933 UINTN Index;\r
934 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;\r
935\r
936 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);\r
937 if (MemoryAttributesTable == NULL) {\r
938 DEBUG ((DEBUG_INFO, "MemoryAttributesTable - NULL\n"));\r
939 return ;\r
940 }\r
941\r
942 DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n"));\r
943 DEBUG ((DEBUG_INFO, " Version - 0x%08x\n", MemoryAttributesTable->Version));\r
944 DEBUG ((DEBUG_INFO, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));\r
945 DEBUG ((DEBUG_INFO, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));\r
946\r
947 MemoryMapEntryCount = MemoryAttributesTable->NumberOfEntries;\r
948 DescriptorSize = MemoryAttributesTable->DescriptorSize;\r
949 MemoryMapStart = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);\r
950 MemoryMap = MemoryMapStart;\r
951 for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
952 DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryMap));\r
953 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", MemoryMap->Type));\r
954 DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", MemoryMap->PhysicalStart));\r
955 DEBUG ((DEBUG_INFO, " VirtualStart - 0x%016lx\n", MemoryMap->VirtualStart));\r
956 DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%016lx\n", MemoryMap->NumberOfPages));\r
957 DEBUG ((DEBUG_INFO, " Attribute - 0x%016lx\n", MemoryMap->Attribute));\r
958 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);\r
959 }\r
960\r
961 MemoryMap = MemoryMapStart;\r
962 for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
963 DEBUG ((DEBUG_VERBOSE, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap->PhysicalStart, MemoryMap->NumberOfPages));\r
964 switch (MemoryMap->Type) {\r
965 case EfiRuntimeServicesCode:\r
966 SmmSetMemoryAttributes (\r
967 MemoryMap->PhysicalStart,\r
968 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
969 EFI_MEMORY_RO\r
970 );\r
971 break;\r
972 case EfiRuntimeServicesData:\r
973 SmmSetMemoryAttributes (\r
974 MemoryMap->PhysicalStart,\r
975 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
976 EFI_MEMORY_XP\r
977 );\r
978 break;\r
979 default:\r
980 SmmSetMemoryAttributes (\r
981 MemoryMap->PhysicalStart,\r
982 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
983 EFI_MEMORY_XP\r
984 );\r
985 break;\r
986 }\r
987 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);\r
988 }\r
989\r
990 PatchSmmSaveStateMap ();\r
991 PatchGdtIdtMap ();\r
992\r
993 return ;\r
994}\r
d2fc7711
JY
995\r
996/**\r
997 Sort memory map entries based upon PhysicalStart, from low to high.\r
998\r
999 @param MemoryMap A pointer to the buffer in which firmware places\r
1000 the current memory map.\r
1001 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
1002 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
1003**/\r
1004STATIC\r
1005VOID\r
1006SortMemoryMap (\r
1007 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1008 IN UINTN MemoryMapSize,\r
1009 IN UINTN DescriptorSize\r
1010 )\r
1011{\r
1012 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
1013 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
1014 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
1015 EFI_MEMORY_DESCRIPTOR TempMemoryMap;\r
1016\r
1017 MemoryMapEntry = MemoryMap;\r
1018 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
1019 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
1020 while (MemoryMapEntry < MemoryMapEnd) {\r
1021 while (NextMemoryMapEntry < MemoryMapEnd) {\r
1022 if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
1023 CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
1024 CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
1025 CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
1026 }\r
1027\r
1028 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
1029 }\r
1030\r
1031 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
1032 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
1033 }\r
1034}\r
1035\r
1036/**\r
1037 Return if a UEFI memory page should be marked as not present in SMM page table.\r
1038 If the memory map entries type is\r
1039 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,\r
1040 EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.\r
1041 Or return FALSE.\r
1042\r
1043 @param[in] MemoryMap A pointer to the memory descriptor.\r
1044\r
1045 @return TRUE The memory described will be marked as not present in SMM page table.\r
1046 @return FALSE The memory described will not be marked as not present in SMM page table.\r
1047**/\r
1048BOOLEAN\r
1049IsUefiPageNotPresent (\r
1050 IN EFI_MEMORY_DESCRIPTOR *MemoryMap\r
1051 )\r
1052{\r
1053 switch (MemoryMap->Type) {\r
1054 case EfiLoaderCode:\r
1055 case EfiLoaderData:\r
1056 case EfiBootServicesCode:\r
1057 case EfiBootServicesData:\r
1058 case EfiConventionalMemory:\r
1059 case EfiUnusableMemory:\r
1060 case EfiACPIReclaimMemory:\r
1061 return TRUE;\r
1062 default:\r
1063 return FALSE;\r
1064 }\r
1065}\r
1066\r
1067/**\r
1068 Merge continous memory map entries whose type is\r
1069 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,\r
1070 EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by\r
1071 these entries will be set as NOT present in SMM page table.\r
1072\r
1073 @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
1074 the current memory map.\r
1075 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
1076 MemoryMap buffer. On input, this is the size of\r
1077 the current memory map. On output,\r
1078 it is the size of new memory map after merge.\r
1079 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
1080**/\r
1081STATIC\r
1082VOID\r
1083MergeMemoryMapForNotPresentEntry (\r
1084 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1085 IN OUT UINTN *MemoryMapSize,\r
1086 IN UINTN DescriptorSize\r
1087 )\r
1088{\r
1089 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
1090 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
1091 UINT64 MemoryBlockLength;\r
1092 EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;\r
1093 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
1094\r
1095 MemoryMapEntry = MemoryMap;\r
1096 NewMemoryMapEntry = MemoryMap;\r
1097 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
1098 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
1099 CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
1100 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
1101\r
1102 do {\r
1103 MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));\r
1104 if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
1105 IsUefiPageNotPresent(MemoryMapEntry) && IsUefiPageNotPresent(NextMemoryMapEntry) &&\r
1106 ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
1107 MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
1108 if (NewMemoryMapEntry != MemoryMapEntry) {\r
1109 NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
1110 }\r
1111\r
1112 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
1113 continue;\r
1114 } else {\r
1115 MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
1116 break;\r
1117 }\r
1118 } while (TRUE);\r
1119\r
1120 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
1121 NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
1122 }\r
1123\r
1124 *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
1125\r
1126 return ;\r
1127}\r
1128\r
ac6613db
JY
1129/**\r
1130 This function caches the GCD memory map information.\r
1131**/\r
1132VOID\r
1133GetGcdMemoryMap (\r
1134 VOID\r
1135 )\r
1136{\r
1137 UINTN NumberOfDescriptors;\r
1138 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemSpaceMap;\r
1139 EFI_STATUS Status;\r
1140 UINTN Index;\r
1141\r
1142 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);\r
1143 if (EFI_ERROR (Status)) {\r
1144 return ;\r
1145 }\r
1146\r
1147 mGcdMemNumberOfDesc = 0;\r
1148 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
1149 if (MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
1150 (MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
1151 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)\r
1152 ) {\r
1153 mGcdMemNumberOfDesc++;\r
1154 }\r
1155 }\r
1156\r
1157 mGcdMemSpace = AllocateZeroPool (mGcdMemNumberOfDesc * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
1158 ASSERT (mGcdMemSpace != NULL);\r
1159 if (mGcdMemSpace == NULL) {\r
1160 mGcdMemNumberOfDesc = 0;\r
1161 gBS->FreePool (MemSpaceMap);\r
1162 return ;\r
1163 }\r
1164\r
1165 mGcdMemNumberOfDesc = 0;\r
1166 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
1167 if (MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
1168 (MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
1169 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)\r
1170 ) {\r
1171 CopyMem (\r
1172 &mGcdMemSpace[mGcdMemNumberOfDesc],\r
1173 &MemSpaceMap[Index],\r
1174 sizeof(EFI_GCD_MEMORY_SPACE_DESCRIPTOR)\r
1175 );\r
1176 mGcdMemNumberOfDesc++;\r
1177 }\r
1178 }\r
1179\r
1180 gBS->FreePool (MemSpaceMap);\r
1181}\r
1182\r
8a2e1a9d
JY
1183/**\r
1184 Get UEFI MemoryAttributesTable.\r
1185**/\r
1186VOID\r
1187GetUefiMemoryAttributesTable (\r
1188 VOID\r
1189 )\r
1190{\r
1191 EFI_STATUS Status;\r
1192 EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;\r
1193 UINTN MemoryAttributesTableSize;\r
1194\r
1195 Status = EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);\r
6d9a0a94 1196 if (!EFI_ERROR (Status) && (MemoryAttributesTable != NULL)) {\r
8a2e1a9d
JY
1197 MemoryAttributesTableSize = sizeof(EFI_MEMORY_ATTRIBUTES_TABLE) + MemoryAttributesTable->DescriptorSize * MemoryAttributesTable->NumberOfEntries;\r
1198 mUefiMemoryAttributesTable = AllocateCopyPool (MemoryAttributesTableSize, MemoryAttributesTable);\r
1199 ASSERT (mUefiMemoryAttributesTable != NULL);\r
1200 }\r
1201}\r
1202\r
d2fc7711
JY
1203/**\r
1204 This function caches the UEFI memory map information.\r
1205**/\r
1206VOID\r
1207GetUefiMemoryMap (\r
1208 VOID\r
1209 )\r
1210{\r
1211 EFI_STATUS Status;\r
1212 UINTN MapKey;\r
1213 UINT32 DescriptorVersion;\r
1214 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
1215 UINTN UefiMemoryMapSize;\r
1216\r
1217 DEBUG ((DEBUG_INFO, "GetUefiMemoryMap\n"));\r
1218\r
1219 UefiMemoryMapSize = 0;\r
1220 MemoryMap = NULL;\r
1221 Status = gBS->GetMemoryMap (\r
1222 &UefiMemoryMapSize,\r
1223 MemoryMap,\r
1224 &MapKey,\r
1225 &mUefiDescriptorSize,\r
1226 &DescriptorVersion\r
1227 );\r
1228 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
1229\r
1230 do {\r
1231 Status = gBS->AllocatePool (EfiBootServicesData, UefiMemoryMapSize, (VOID **)&MemoryMap);\r
1232 ASSERT (MemoryMap != NULL);\r
1233 if (MemoryMap == NULL) {\r
1234 return ;\r
1235 }\r
1236\r
1237 Status = gBS->GetMemoryMap (\r
1238 &UefiMemoryMapSize,\r
1239 MemoryMap,\r
1240 &MapKey,\r
1241 &mUefiDescriptorSize,\r
1242 &DescriptorVersion\r
1243 );\r
1244 if (EFI_ERROR (Status)) {\r
1245 gBS->FreePool (MemoryMap);\r
1246 MemoryMap = NULL;\r
1247 }\r
1248 } while (Status == EFI_BUFFER_TOO_SMALL);\r
1249\r
403f5476
HW
1250 if (MemoryMap == NULL) {\r
1251 return ;\r
1252 }\r
1253\r
d2fc7711
JY
1254 SortMemoryMap (MemoryMap, UefiMemoryMapSize, mUefiDescriptorSize);\r
1255 MergeMemoryMapForNotPresentEntry (MemoryMap, &UefiMemoryMapSize, mUefiDescriptorSize);\r
1256\r
1257 mUefiMemoryMapSize = UefiMemoryMapSize;\r
1258 mUefiMemoryMap = AllocateCopyPool (UefiMemoryMapSize, MemoryMap);\r
1259 ASSERT (mUefiMemoryMap != NULL);\r
1260\r
1261 gBS->FreePool (MemoryMap);\r
ac6613db
JY
1262\r
1263 //\r
1264 // Get additional information from GCD memory map.\r
1265 //\r
1266 GetGcdMemoryMap ();\r
8a2e1a9d
JY
1267\r
1268 //\r
1269 // Get UEFI memory attributes table.\r
1270 //\r
1271 GetUefiMemoryAttributesTable ();\r
d2fc7711
JY
1272}\r
1273\r
1274/**\r
1275 This function sets UEFI memory attribute according to UEFI memory map.\r
1276\r
1277 The normal memory region is marked as not present, such as\r
1278 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,\r
1279 EfiUnusableMemory, EfiACPIReclaimMemory.\r
1280**/\r
1281VOID\r
1282SetUefiMemMapAttributes (\r
1283 VOID\r
1284 )\r
1285{\r
714c2603 1286 EFI_STATUS Status;\r
d2fc7711
JY
1287 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
1288 UINTN MemoryMapEntryCount;\r
1289 UINTN Index;\r
8a2e1a9d 1290 EFI_MEMORY_DESCRIPTOR *Entry;\r
d2fc7711
JY
1291\r
1292 DEBUG ((DEBUG_INFO, "SetUefiMemMapAttributes\n"));\r
1293\r
ac6613db
JY
1294 if (mUefiMemoryMap != NULL) {\r
1295 MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;\r
1296 MemoryMap = mUefiMemoryMap;\r
1297 for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
1298 if (IsUefiPageNotPresent(MemoryMap)) {\r
1299 Status = SmmSetMemoryAttributes (\r
1300 MemoryMap->PhysicalStart,\r
1301 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
1302 EFI_MEMORY_RP\r
1303 );\r
1304 DEBUG ((\r
1305 DEBUG_INFO,\r
1306 "UefiMemory protection: 0x%lx - 0x%lx %r\n",\r
1307 MemoryMap->PhysicalStart,\r
1308 MemoryMap->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),\r
1309 Status\r
1310 ));\r
1311 }\r
1312 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mUefiDescriptorSize);\r
1313 }\r
d2fc7711 1314 }\r
ac6613db
JY
1315 //\r
1316 // Do not free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().\r
1317 //\r
d2fc7711 1318\r
ac6613db
JY
1319 //\r
1320 // Set untested memory as not present.\r
1321 //\r
1322 if (mGcdMemSpace != NULL) {\r
1323 for (Index = 0; Index < mGcdMemNumberOfDesc; Index++) {\r
714c2603 1324 Status = SmmSetMemoryAttributes (\r
ac6613db
JY
1325 mGcdMemSpace[Index].BaseAddress,\r
1326 mGcdMemSpace[Index].Length,\r
714c2603
SZ
1327 EFI_MEMORY_RP\r
1328 );\r
1329 DEBUG ((\r
1330 DEBUG_INFO,\r
ac6613db
JY
1331 "GcdMemory protection: 0x%lx - 0x%lx %r\n",\r
1332 mGcdMemSpace[Index].BaseAddress,\r
1333 mGcdMemSpace[Index].BaseAddress + mGcdMemSpace[Index].Length,\r
714c2603
SZ
1334 Status\r
1335 ));\r
d2fc7711 1336 }\r
d2fc7711 1337 }\r
d2fc7711 1338 //\r
ac6613db 1339 // Do not free mGcdMemSpace, it will be checked in IsSmmCommBufferForbiddenAddress().\r
d2fc7711 1340 //\r
8a2e1a9d
JY
1341\r
1342 //\r
1343 // Set UEFI runtime memory with EFI_MEMORY_RO as not present.\r
1344 //\r
1345 if (mUefiMemoryAttributesTable != NULL) {\r
1346 Entry = (EFI_MEMORY_DESCRIPTOR *)(mUefiMemoryAttributesTable + 1);\r
1347 for (Index = 0; Index < mUefiMemoryAttributesTable->NumberOfEntries; Index++) {\r
1348 if (Entry->Type == EfiRuntimeServicesCode || Entry->Type == EfiRuntimeServicesData) {\r
1349 if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {\r
1350 Status = SmmSetMemoryAttributes (\r
1351 Entry->PhysicalStart,\r
1352 EFI_PAGES_TO_SIZE((UINTN)Entry->NumberOfPages),\r
1353 EFI_MEMORY_RP\r
1354 );\r
1355 DEBUG ((\r
1356 DEBUG_INFO,\r
1357 "UefiMemoryAttribute protection: 0x%lx - 0x%lx %r\n",\r
1358 Entry->PhysicalStart,\r
1359 Entry->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE((UINTN)Entry->NumberOfPages),\r
1360 Status\r
1361 ));\r
1362 }\r
1363 }\r
1364 Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mUefiMemoryAttributesTable->DescriptorSize);\r
1365 }\r
1366 }\r
1367 //\r
1368 // Do not free mUefiMemoryAttributesTable, it will be checked in IsSmmCommBufferForbiddenAddress().\r
1369 //\r
d2fc7711
JY
1370}\r
1371\r
1372/**\r
1373 Return if the Address is forbidden as SMM communication buffer.\r
1374\r
1375 @param[in] Address the address to be checked\r
1376\r
1377 @return TRUE The address is forbidden as SMM communication buffer.\r
1378 @return FALSE The address is allowed as SMM communication buffer.\r
1379**/\r
1380BOOLEAN\r
1381IsSmmCommBufferForbiddenAddress (\r
1382 IN UINT64 Address\r
1383 )\r
1384{\r
1385 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
1386 UINTN MemoryMapEntryCount;\r
1387 UINTN Index;\r
8a2e1a9d 1388 EFI_MEMORY_DESCRIPTOR *Entry;\r
d2fc7711 1389\r
ac6613db
JY
1390 if (mUefiMemoryMap != NULL) {\r
1391 MemoryMap = mUefiMemoryMap;\r
1392 MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;\r
1393 for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
1394 if (IsUefiPageNotPresent (MemoryMap)) {\r
1395 if ((Address >= MemoryMap->PhysicalStart) &&\r
1396 (Address < MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages)) ) {\r
1397 return TRUE;\r
1398 }\r
1399 }\r
1400 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mUefiDescriptorSize);\r
1401 }\r
403f5476
HW
1402 }\r
1403\r
ac6613db
JY
1404 if (mGcdMemSpace != NULL) {\r
1405 for (Index = 0; Index < mGcdMemNumberOfDesc; Index++) {\r
1406 if ((Address >= mGcdMemSpace[Index].BaseAddress) &&\r
1407 (Address < mGcdMemSpace[Index].BaseAddress + mGcdMemSpace[Index].Length) ) {\r
d2fc7711
JY
1408 return TRUE;\r
1409 }\r
1410 }\r
d2fc7711 1411 }\r
ac6613db 1412\r
8a2e1a9d
JY
1413 if (mUefiMemoryAttributesTable != NULL) {\r
1414 Entry = (EFI_MEMORY_DESCRIPTOR *)(mUefiMemoryAttributesTable + 1);\r
1415 for (Index = 0; Index < mUefiMemoryAttributesTable->NumberOfEntries; Index++) {\r
1416 if (Entry->Type == EfiRuntimeServicesCode || Entry->Type == EfiRuntimeServicesData) {\r
1417 if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {\r
1418 if ((Address >= Entry->PhysicalStart) &&\r
1419 (Address < Entry->PhysicalStart + LShiftU64 (Entry->NumberOfPages, EFI_PAGE_SHIFT))) {\r
1420 return TRUE;\r
1421 }\r
1422 Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mUefiMemoryAttributesTable->DescriptorSize);\r
1423 }\r
1424 }\r
1425 }\r
1426 }\r
d2fc7711
JY
1427 return FALSE;\r
1428}\r
827330cc
JW
1429\r
1430/**\r
1431 This function set given attributes of the memory region specified by\r
1432 BaseAddress and Length.\r
1433\r
1434 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.\r
1435 @param BaseAddress The physical address that is the start address of\r
1436 a memory region.\r
1437 @param Length The size in bytes of the memory region.\r
1438 @param Attributes The bit mask of attributes to set for the memory\r
1439 region.\r
1440\r
1441 @retval EFI_SUCCESS The attributes were set for the memory region.\r
1442 @retval EFI_INVALID_PARAMETER Length is zero.\r
1443 Attributes specified an illegal combination of\r
1444 attributes that cannot be set together.\r
1445 @retval EFI_UNSUPPORTED The processor does not support one or more\r
1446 bytes of the memory resource range specified\r
1447 by BaseAddress and Length.\r
aae02dcc 1448 The bit mask of attributes is not supported for\r
827330cc
JW
1449 the memory resource range specified by\r
1450 BaseAddress and Length.\r
1451\r
1452**/\r
1453EFI_STATUS\r
1454EFIAPI\r
1455EdkiiSmmSetMemoryAttributes (\r
1456 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This,\r
1457 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
1458 IN UINT64 Length,\r
1459 IN UINT64 Attributes\r
1460 )\r
1461{\r
1462 return SmmSetMemoryAttributes (BaseAddress, Length, Attributes);\r
1463}\r
1464\r
1465/**\r
1466 This function clears given attributes of the memory region specified by\r
1467 BaseAddress and Length.\r
1468\r
1469 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.\r
1470 @param BaseAddress The physical address that is the start address of\r
1471 a memory region.\r
1472 @param Length The size in bytes of the memory region.\r
aae02dcc 1473 @param Attributes The bit mask of attributes to clear for the memory\r
827330cc
JW
1474 region.\r
1475\r
aae02dcc 1476 @retval EFI_SUCCESS The attributes were cleared for the memory region.\r
827330cc
JW
1477 @retval EFI_INVALID_PARAMETER Length is zero.\r
1478 Attributes specified an illegal combination of\r
aae02dcc 1479 attributes that cannot be cleared together.\r
827330cc
JW
1480 @retval EFI_UNSUPPORTED The processor does not support one or more\r
1481 bytes of the memory resource range specified\r
1482 by BaseAddress and Length.\r
aae02dcc 1483 The bit mask of attributes is not supported for\r
827330cc
JW
1484 the memory resource range specified by\r
1485 BaseAddress and Length.\r
1486\r
1487**/\r
1488EFI_STATUS\r
1489EFIAPI\r
1490EdkiiSmmClearMemoryAttributes (\r
1491 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This,\r
1492 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
1493 IN UINT64 Length,\r
1494 IN UINT64 Attributes\r
1495 )\r
1496{\r
1497 return SmmClearMemoryAttributes (BaseAddress, Length, Attributes);\r
1498}\r
1499\r
1500/**\r
aae02dcc 1501 This function retrieves the attributes of the memory region specified by\r
827330cc
JW
1502 BaseAddress and Length. If different attributes are got from different part\r
1503 of the memory region, EFI_NO_MAPPING will be returned.\r
1504\r
1505 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.\r
1506 @param BaseAddress The physical address that is the start address of\r
1507 a memory region.\r
1508 @param Length The size in bytes of the memory region.\r
1509 @param Attributes Pointer to attributes returned.\r
1510\r
1511 @retval EFI_SUCCESS The attributes got for the memory region.\r
1512 @retval EFI_INVALID_PARAMETER Length is zero.\r
1513 Attributes is NULL.\r
1514 @retval EFI_NO_MAPPING Attributes are not consistent cross the memory\r
1515 region.\r
1516 @retval EFI_UNSUPPORTED The processor does not support one or more\r
1517 bytes of the memory resource range specified\r
1518 by BaseAddress and Length.\r
827330cc
JW
1519\r
1520**/\r
1521EFI_STATUS\r
1522EFIAPI\r
1523EdkiiSmmGetMemoryAttributes (\r
1524 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This,\r
1525 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
1526 IN UINT64 Length,\r
1527 OUT UINT64 *Attributes\r
1528 )\r
1529{\r
1530 EFI_PHYSICAL_ADDRESS Address;\r
1531 UINT64 *PageEntry;\r
1532 UINT64 MemAttr;\r
1533 PAGE_ATTRIBUTE PageAttr;\r
1534 INT64 Size;\r
1535\r
1536 if (Length < SIZE_4KB || Attributes == NULL) {\r
1537 return EFI_INVALID_PARAMETER;\r
1538 }\r
1539\r
1540 Size = (INT64)Length;\r
1541 MemAttr = (UINT64)-1;\r
1542\r
1543 do {\r
1544\r
1545 PageEntry = GetPageTableEntry (BaseAddress, &PageAttr);\r
1546 if (PageEntry == NULL || PageAttr == PageNone) {\r
1547 return EFI_UNSUPPORTED;\r
1548 }\r
1549\r
1550 //\r
1551 // If the memory range is cross page table boundary, make sure they\r
1552 // share the same attribute. Return EFI_NO_MAPPING if not.\r
1553 //\r
1554 *Attributes = GetAttributesFromPageEntry (PageEntry);\r
1555 if (MemAttr != (UINT64)-1 && *Attributes != MemAttr) {\r
1556 return EFI_NO_MAPPING;\r
1557 }\r
1558\r
1559 switch (PageAttr) {\r
1560 case Page4K:\r
1561 Address = *PageEntry & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64;\r
1562 Size -= (SIZE_4KB - (BaseAddress - Address));\r
1563 BaseAddress += (SIZE_4KB - (BaseAddress - Address));\r
1564 break;\r
1565\r
1566 case Page2M:\r
1567 Address = *PageEntry & ~mAddressEncMask & PAGING_2M_ADDRESS_MASK_64;\r
1568 Size -= SIZE_2MB - (BaseAddress - Address);\r
1569 BaseAddress += SIZE_2MB - (BaseAddress - Address);\r
1570 break;\r
1571\r
1572 case Page1G:\r
1573 Address = *PageEntry & ~mAddressEncMask & PAGING_1G_ADDRESS_MASK_64;\r
1574 Size -= SIZE_1GB - (BaseAddress - Address);\r
1575 BaseAddress += SIZE_1GB - (BaseAddress - Address);\r
1576 break;\r
1577\r
1578 default:\r
1579 return EFI_UNSUPPORTED;\r
1580 }\r
1581\r
1582 MemAttr = *Attributes;\r
1583\r
1584 } while (Size > 0);\r
1585\r
1586 return EFI_SUCCESS;\r
1587}\r
1588\r