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