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