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