]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
OvmfPkg/OvmfXen: Build platform info HOB in XenPlatformPei
[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
7b475490
DT
35BOOLEAN mIsShadowStack = FALSE;\r
36BOOLEAN m5LevelPagingNeeded = FALSE;\r
3eb69b08 37\r
717fb604
JY
38/**\r
39 Return length according to page attributes.\r
40\r
41 @param[in] PageAttributes The page attribute of the page entry.\r
42\r
43 @return The length of page entry.\r
44**/\r
45UINTN\r
46PageAttributeToLength (\r
47 IN PAGE_ATTRIBUTE PageAttribute\r
48 )\r
49{\r
50 UINTN Index;\r
053e878b
MK
51\r
52 for (Index = 0; Index < sizeof (mPageAttributeTable)/sizeof (mPageAttributeTable[0]); Index++) {\r
717fb604
JY
53 if (PageAttribute == mPageAttributeTable[Index].Attribute) {\r
54 return (UINTN)mPageAttributeTable[Index].Length;\r
55 }\r
56 }\r
053e878b 57\r
717fb604
JY
58 return 0;\r
59}\r
60\r
61/**\r
62 Return address mask according to page attributes.\r
63\r
64 @param[in] PageAttributes The page attribute of the page entry.\r
65\r
66 @return The address mask of page entry.\r
67**/\r
68UINTN\r
69PageAttributeToMask (\r
70 IN PAGE_ATTRIBUTE PageAttribute\r
71 )\r
72{\r
73 UINTN Index;\r
053e878b
MK
74\r
75 for (Index = 0; Index < sizeof (mPageAttributeTable)/sizeof (mPageAttributeTable[0]); Index++) {\r
717fb604
JY
76 if (PageAttribute == mPageAttributeTable[Index].Attribute) {\r
77 return (UINTN)mPageAttributeTable[Index].AddressMask;\r
78 }\r
79 }\r
053e878b 80\r
717fb604
JY
81 return 0;\r
82}\r
83\r
84/**\r
85 Return page table entry to match the address.\r
86\r
7b475490
DT
87 @param[in] PageTableBase The page table base.\r
88 @param[in] Enable5LevelPaging If PML5 paging is enabled.\r
89 @param[in] Address The address to be checked.\r
90 @param[out] PageAttributes The page attribute of the page entry.\r
717fb604
JY
91\r
92 @return The page entry.\r
93**/\r
94VOID *\r
95GetPageTableEntry (\r
7b475490
DT
96 IN UINTN PageTableBase,\r
97 IN BOOLEAN Enable5LevelPaging,\r
053e878b
MK
98 IN PHYSICAL_ADDRESS Address,\r
99 OUT PAGE_ATTRIBUTE *PageAttribute\r
717fb604
JY
100 )\r
101{\r
7b475490
DT
102 UINTN Index1;\r
103 UINTN Index2;\r
104 UINTN Index3;\r
105 UINTN Index4;\r
106 UINTN Index5;\r
107 UINT64 *L1PageTable;\r
108 UINT64 *L2PageTable;\r
109 UINT64 *L3PageTable;\r
110 UINT64 *L4PageTable;\r
111 UINT64 *L5PageTable;\r
404250c8 112\r
4eee0cc7 113 Index5 = ((UINTN)RShiftU64 (Address, 48)) & PAGING_PAE_INDEX_MASK;\r
717fb604
JY
114 Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;\r
115 Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;\r
116 Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;\r
117 Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;\r
118\r
053e878b 119 if (sizeof (UINTN) == sizeof (UINT64)) {\r
4eee0cc7 120 if (Enable5LevelPaging) {\r
404250c8 121 L5PageTable = (UINT64 *)PageTableBase;\r
4eee0cc7
RN
122 if (L5PageTable[Index5] == 0) {\r
123 *PageAttribute = PageNone;\r
124 return NULL;\r
125 }\r
126\r
127 L4PageTable = (UINT64 *)(UINTN)(L5PageTable[Index5] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
128 } else {\r
404250c8 129 L4PageTable = (UINT64 *)PageTableBase;\r
4eee0cc7 130 }\r
053e878b 131\r
717fb604
JY
132 if (L4PageTable[Index4] == 0) {\r
133 *PageAttribute = PageNone;\r
134 return NULL;\r
135 }\r
136\r
241f9149 137 L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604 138 } else {\r
404250c8 139 L3PageTable = (UINT64 *)PageTableBase;\r
717fb604 140 }\r
053e878b 141\r
717fb604
JY
142 if (L3PageTable[Index3] == 0) {\r
143 *PageAttribute = PageNone;\r
144 return NULL;\r
145 }\r
053e878b 146\r
717fb604
JY
147 if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {\r
148 // 1G\r
149 *PageAttribute = Page1G;\r
150 return &L3PageTable[Index3];\r
151 }\r
152\r
241f9149 153 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
154 if (L2PageTable[Index2] == 0) {\r
155 *PageAttribute = PageNone;\r
156 return NULL;\r
157 }\r
053e878b 158\r
717fb604
JY
159 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
160 // 2M\r
161 *PageAttribute = Page2M;\r
162 return &L2PageTable[Index2];\r
163 }\r
164\r
165 // 4k\r
241f9149 166 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
167 if ((L1PageTable[Index1] == 0) && (Address != 0)) {\r
168 *PageAttribute = PageNone;\r
169 return NULL;\r
170 }\r
053e878b 171\r
717fb604
JY
172 *PageAttribute = Page4K;\r
173 return &L1PageTable[Index1];\r
174}\r
175\r
176/**\r
177 Return memory attributes of page entry.\r
178\r
179 @param[in] PageEntry The page entry.\r
180\r
181 @return Memory attributes of page entry.\r
182**/\r
183UINT64\r
184GetAttributesFromPageEntry (\r
053e878b 185 IN UINT64 *PageEntry\r
717fb604
JY
186 )\r
187{\r
188 UINT64 Attributes;\r
053e878b 189\r
717fb604
JY
190 Attributes = 0;\r
191 if ((*PageEntry & IA32_PG_P) == 0) {\r
192 Attributes |= EFI_MEMORY_RP;\r
193 }\r
053e878b 194\r
717fb604
JY
195 if ((*PageEntry & IA32_PG_RW) == 0) {\r
196 Attributes |= EFI_MEMORY_RO;\r
197 }\r
053e878b 198\r
717fb604
JY
199 if ((*PageEntry & IA32_PG_NX) != 0) {\r
200 Attributes |= EFI_MEMORY_XP;\r
201 }\r
053e878b 202\r
717fb604
JY
203 return Attributes;\r
204}\r
205\r
206/**\r
207 Modify memory attributes of page entry.\r
208\r
209 @param[in] PageEntry The page entry.\r
210 @param[in] Attributes The bit mask of attributes to modify for the memory region.\r
211 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.\r
212 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.\r
213**/\r
214VOID\r
215ConvertPageEntryAttribute (\r
053e878b
MK
216 IN UINT64 *PageEntry,\r
217 IN UINT64 Attributes,\r
218 IN BOOLEAN IsSet,\r
219 OUT BOOLEAN *IsModified\r
717fb604
JY
220 )\r
221{\r
222 UINT64 CurrentPageEntry;\r
223 UINT64 NewPageEntry;\r
224\r
225 CurrentPageEntry = *PageEntry;\r
053e878b 226 NewPageEntry = CurrentPageEntry;\r
717fb604
JY
227 if ((Attributes & EFI_MEMORY_RP) != 0) {\r
228 if (IsSet) {\r
229 NewPageEntry &= ~(UINT64)IA32_PG_P;\r
230 } else {\r
231 NewPageEntry |= IA32_PG_P;\r
232 }\r
233 }\r
053e878b 234\r
717fb604
JY
235 if ((Attributes & EFI_MEMORY_RO) != 0) {\r
236 if (IsSet) {\r
237 NewPageEntry &= ~(UINT64)IA32_PG_RW;\r
83d58711 238 if (mIsShadowStack) {\r
3eb69b08
JY
239 // Environment setup\r
240 // ReadOnly page need set Dirty bit for shadow stack\r
241 NewPageEntry |= IA32_PG_D;\r
242 // Clear user bit for supervisor shadow stack\r
243 NewPageEntry &= ~(UINT64)IA32_PG_U;\r
244 } else {\r
245 // Runtime update\r
246 // Clear dirty bit for non shadow stack, to protect RO page.\r
247 NewPageEntry &= ~(UINT64)IA32_PG_D;\r
248 }\r
717fb604
JY
249 } else {\r
250 NewPageEntry |= IA32_PG_RW;\r
251 }\r
252 }\r
053e878b 253\r
717fb604 254 if ((Attributes & EFI_MEMORY_XP) != 0) {\r
750ec4ca
JY
255 if (mXdSupported) {\r
256 if (IsSet) {\r
257 NewPageEntry |= IA32_PG_NX;\r
258 } else {\r
259 NewPageEntry &= ~IA32_PG_NX;\r
260 }\r
717fb604
JY
261 }\r
262 }\r
053e878b 263\r
717fb604
JY
264 *PageEntry = NewPageEntry;\r
265 if (CurrentPageEntry != NewPageEntry) {\r
266 *IsModified = TRUE;\r
267 DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));\r
268 DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));\r
269 } else {\r
270 *IsModified = FALSE;\r
271 }\r
272}\r
273\r
274/**\r
275 This function returns if there is need to split page entry.\r
276\r
277 @param[in] BaseAddress The base address to be checked.\r
278 @param[in] Length The length to be checked.\r
279 @param[in] PageEntry The page entry to be checked.\r
280 @param[in] PageAttribute The page attribute of the page entry.\r
281\r
282 @retval SplitAttributes on if there is need to split page entry.\r
283**/\r
284PAGE_ATTRIBUTE\r
285NeedSplitPage (\r
053e878b
MK
286 IN PHYSICAL_ADDRESS BaseAddress,\r
287 IN UINT64 Length,\r
288 IN UINT64 *PageEntry,\r
289 IN PAGE_ATTRIBUTE PageAttribute\r
717fb604
JY
290 )\r
291{\r
053e878b 292 UINT64 PageEntryLength;\r
717fb604
JY
293\r
294 PageEntryLength = PageAttributeToLength (PageAttribute);\r
295\r
296 if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {\r
297 return PageNone;\r
298 }\r
299\r
300 if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {\r
301 return Page4K;\r
302 }\r
303\r
304 return Page2M;\r
305}\r
306\r
307/**\r
308 This function splits one page entry to small page entries.\r
309\r
310 @param[in] PageEntry The page entry to be splitted.\r
311 @param[in] PageAttribute The page attribute of the page entry.\r
312 @param[in] SplitAttribute How to split the page entry.\r
313\r
314 @retval RETURN_SUCCESS The page entry is splitted.\r
315 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.\r
316 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.\r
317**/\r
318RETURN_STATUS\r
319SplitPage (\r
053e878b
MK
320 IN UINT64 *PageEntry,\r
321 IN PAGE_ATTRIBUTE PageAttribute,\r
322 IN PAGE_ATTRIBUTE SplitAttribute\r
717fb604
JY
323 )\r
324{\r
053e878b
MK
325 UINT64 BaseAddress;\r
326 UINT64 *NewPageEntry;\r
327 UINTN Index;\r
717fb604
JY
328\r
329 ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);\r
330\r
331 if (PageAttribute == Page2M) {\r
332 //\r
333 // Split 2M to 4K\r
334 //\r
335 ASSERT (SplitAttribute == Page4K);\r
336 if (SplitAttribute == Page4K) {\r
337 NewPageEntry = AllocatePageTableMemory (1);\r
338 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
339 if (NewPageEntry == NULL) {\r
340 return RETURN_OUT_OF_RESOURCES;\r
341 }\r
053e878b 342\r
717fb604 343 BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;\r
053e878b 344 for (Index = 0; Index < SIZE_4KB / sizeof (UINT64); Index++) {\r
241f9149 345 NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | mAddressEncMask | ((*PageEntry) & PAGE_PROGATE_BITS);\r
717fb604 346 }\r
053e878b 347\r
241f9149 348 (*PageEntry) = (UINT64)(UINTN)NewPageEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
717fb604
JY
349 return RETURN_SUCCESS;\r
350 } else {\r
351 return RETURN_UNSUPPORTED;\r
352 }\r
353 } else if (PageAttribute == Page1G) {\r
354 //\r
355 // Split 1G to 2M\r
356 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.\r
357 //\r
358 ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);\r
053e878b 359 if (((SplitAttribute == Page2M) || (SplitAttribute == Page4K))) {\r
717fb604
JY
360 NewPageEntry = AllocatePageTableMemory (1);\r
361 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
362 if (NewPageEntry == NULL) {\r
363 return RETURN_OUT_OF_RESOURCES;\r
364 }\r
053e878b 365\r
717fb604 366 BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;\r
053e878b 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
053e878b 370\r
241f9149 371 (*PageEntry) = (UINT64)(UINTN)NewPageEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
717fb604
JY
372 return RETURN_SUCCESS;\r
373 } else {\r
374 return RETURN_UNSUPPORTED;\r
375 }\r
376 } else {\r
377 return RETURN_UNSUPPORTED;\r
378 }\r
379}\r
380\r
381/**\r
382 This function modifies the page attributes for the memory region specified by BaseAddress and\r
383 Length from their current attributes to the attributes specified by Attributes.\r
384\r
385 Caller should make sure BaseAddress and Length is at page boundary.\r
386\r
7b475490
DT
387 @param[in] PageTableBase The page table base.\r
388 @param[in] EnablePML5Paging If PML5 paging is enabled.\r
717fb604
JY
389 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
390 @param[in] Length The size in bytes of the memory region.\r
391 @param[in] Attributes The bit mask of attributes to modify for the memory region.\r
392 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.\r
393 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.\r
394 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.\r
395\r
396 @retval RETURN_SUCCESS The attributes were modified for the memory region.\r
397 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
398 BaseAddress and Length cannot be modified.\r
399 @retval RETURN_INVALID_PARAMETER Length is zero.\r
400 Attributes specified an illegal combination of attributes that\r
401 cannot be set together.\r
402 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
403 the memory resource range.\r
404 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory\r
405 resource range specified by BaseAddress and Length.\r
406 The bit mask of attributes is not support for the memory resource\r
407 range specified by BaseAddress and Length.\r
408**/\r
409RETURN_STATUS\r
717fb604 410ConvertMemoryPageAttributes (\r
7b475490
DT
411 IN UINTN PageTableBase,\r
412 IN BOOLEAN EnablePML5Paging,\r
053e878b
MK
413 IN PHYSICAL_ADDRESS BaseAddress,\r
414 IN UINT64 Length,\r
415 IN UINT64 Attributes,\r
416 IN BOOLEAN IsSet,\r
417 OUT BOOLEAN *IsSplitted OPTIONAL,\r
418 OUT BOOLEAN *IsModified OPTIONAL\r
717fb604
JY
419 )\r
420{\r
053e878b
MK
421 UINT64 *PageEntry;\r
422 PAGE_ATTRIBUTE PageAttribute;\r
423 UINTN PageEntryLength;\r
424 PAGE_ATTRIBUTE SplitAttribute;\r
425 RETURN_STATUS Status;\r
426 BOOLEAN IsEntryModified;\r
427 EFI_PHYSICAL_ADDRESS MaximumSupportMemAddress;\r
717fb604
JY
428\r
429 ASSERT (Attributes != 0);\r
e77966b3 430 ASSERT ((Attributes & ~EFI_MEMORY_ATTRIBUTE_MASK) == 0);\r
717fb604
JY
431\r
432 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);\r
433 ASSERT ((Length & (SIZE_4KB - 1)) == 0);\r
434\r
435 if (Length == 0) {\r
436 return RETURN_INVALID_PARAMETER;\r
437 }\r
438\r
714c2603
SZ
439 MaximumSupportMemAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, mPhysicalAddressBits) - 1);\r
440 if (BaseAddress > MaximumSupportMemAddress) {\r
441 return RETURN_UNSUPPORTED;\r
442 }\r
053e878b 443\r
714c2603
SZ
444 if (Length > MaximumSupportMemAddress) {\r
445 return RETURN_UNSUPPORTED;\r
446 }\r
053e878b 447\r
714c2603
SZ
448 if ((Length != 0) && (BaseAddress > MaximumSupportMemAddress - (Length - 1))) {\r
449 return RETURN_UNSUPPORTED;\r
450 }\r
451\r
053e878b 452 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));\r
717fb604
JY
453\r
454 if (IsSplitted != NULL) {\r
455 *IsSplitted = FALSE;\r
456 }\r
053e878b 457\r
717fb604
JY
458 if (IsModified != NULL) {\r
459 *IsModified = FALSE;\r
460 }\r
461\r
462 //\r
ef62da4f 463 // Below logic is to check 2M/4K page to make sure we do not waste memory.\r
717fb604
JY
464 //\r
465 while (Length != 0) {\r
7b475490 466 PageEntry = GetPageTableEntry (PageTableBase, EnablePML5Paging, BaseAddress, &PageAttribute);\r
717fb604
JY
467 if (PageEntry == NULL) {\r
468 return RETURN_UNSUPPORTED;\r
469 }\r
053e878b 470\r
717fb604 471 PageEntryLength = PageAttributeToLength (PageAttribute);\r
053e878b 472 SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute);\r
717fb604
JY
473 if (SplitAttribute == PageNone) {\r
474 ConvertPageEntryAttribute (PageEntry, Attributes, IsSet, &IsEntryModified);\r
475 if (IsEntryModified) {\r
476 if (IsModified != NULL) {\r
477 *IsModified = TRUE;\r
478 }\r
479 }\r
053e878b 480\r
717fb604
JY
481 //\r
482 // Convert success, move to next\r
483 //\r
484 BaseAddress += PageEntryLength;\r
053e878b 485 Length -= PageEntryLength;\r
717fb604
JY
486 } else {\r
487 Status = SplitPage (PageEntry, PageAttribute, SplitAttribute);\r
488 if (RETURN_ERROR (Status)) {\r
489 return RETURN_UNSUPPORTED;\r
490 }\r
053e878b 491\r
717fb604
JY
492 if (IsSplitted != NULL) {\r
493 *IsSplitted = TRUE;\r
494 }\r
053e878b 495\r
717fb604
JY
496 if (IsModified != NULL) {\r
497 *IsModified = TRUE;\r
498 }\r
053e878b 499\r
717fb604
JY
500 //\r
501 // Just split current page\r
502 // Convert success in next around\r
503 //\r
504 }\r
505 }\r
506\r
507 return RETURN_SUCCESS;\r
508}\r
509\r
510/**\r
511 FlushTlb on current processor.\r
512\r
513 @param[in,out] Buffer Pointer to private data buffer.\r
514**/\r
515VOID\r
516EFIAPI\r
517FlushTlbOnCurrentProcessor (\r
518 IN OUT VOID *Buffer\r
519 )\r
520{\r
521 CpuFlushTlb ();\r
522}\r
523\r
524/**\r
525 FlushTlb for all processors.\r
526**/\r
527VOID\r
528FlushTlbForAll (\r
529 VOID\r
530 )\r
531{\r
053e878b 532 UINTN Index;\r
717fb604
JY
533\r
534 FlushTlbOnCurrentProcessor (NULL);\r
535\r
536 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {\r
537 if (Index != gSmst->CurrentlyExecutingCpu) {\r
538 // Force to start up AP in blocking mode,\r
539 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor, Index, NULL);\r
540 // Do not check return status, because AP might not be present in some corner cases.\r
541 }\r
542 }\r
543}\r
544\r
545/**\r
546 This function sets the attributes for the memory region specified by BaseAddress and\r
547 Length from their current attributes to the attributes specified by Attributes.\r
548\r
7b475490
DT
549 @param[in] PageTableBase The page table base.\r
550 @param[in] EnablePML5Paging If PML5 paging is enabled.\r
717fb604
JY
551 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
552 @param[in] Length The size in bytes of the memory region.\r
553 @param[in] Attributes The bit mask of attributes to set for the memory region.\r
554 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.\r
555\r
556 @retval EFI_SUCCESS The attributes were set for the memory region.\r
557 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
558 BaseAddress and Length cannot be modified.\r
559 @retval EFI_INVALID_PARAMETER Length is zero.\r
560 Attributes specified an illegal combination of attributes that\r
561 cannot be set together.\r
562 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
563 the memory resource range.\r
564 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
565 resource range specified by BaseAddress and Length.\r
566 The bit mask of attributes is not support for the memory resource\r
567 range specified by BaseAddress and Length.\r
568\r
569**/\r
570EFI_STATUS\r
717fb604 571SmmSetMemoryAttributesEx (\r
7b475490
DT
572 IN UINTN PageTableBase,\r
573 IN BOOLEAN EnablePML5Paging,\r
053e878b
MK
574 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
575 IN UINT64 Length,\r
576 IN UINT64 Attributes,\r
577 OUT BOOLEAN *IsSplitted OPTIONAL\r
717fb604
JY
578 )\r
579{\r
580 EFI_STATUS Status;\r
581 BOOLEAN IsModified;\r
582\r
7b475490 583 Status = ConvertMemoryPageAttributes (PageTableBase, EnablePML5Paging, BaseAddress, Length, Attributes, TRUE, IsSplitted, &IsModified);\r
053e878b 584 if (!EFI_ERROR (Status)) {\r
717fb604
JY
585 if (IsModified) {\r
586 //\r
587 // Flush TLB as last step\r
588 //\r
053e878b 589 FlushTlbForAll ();\r
717fb604
JY
590 }\r
591 }\r
592\r
593 return Status;\r
594}\r
595\r
596/**\r
597 This function clears the attributes for the memory region specified by BaseAddress and\r
598 Length from their current attributes to the attributes specified by Attributes.\r
599\r
7b475490
DT
600 @param[in] PageTableBase The page table base.\r
601 @param[in] EnablePML5Paging If PML5 paging is enabled.\r
717fb604
JY
602 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
603 @param[in] Length The size in bytes of the memory region.\r
604 @param[in] Attributes The bit mask of attributes to clear for the memory region.\r
605 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.\r
606\r
607 @retval EFI_SUCCESS The attributes were cleared for the memory region.\r
608 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
609 BaseAddress and Length cannot be modified.\r
610 @retval EFI_INVALID_PARAMETER Length is zero.\r
611 Attributes specified an illegal combination of attributes that\r
aae02dcc 612 cannot be cleared together.\r
717fb604
JY
613 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
614 the memory resource range.\r
615 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
616 resource range specified by BaseAddress and Length.\r
aae02dcc 617 The bit mask of attributes is not supported for the memory resource\r
717fb604
JY
618 range specified by BaseAddress and Length.\r
619\r
620**/\r
621EFI_STATUS\r
717fb604 622SmmClearMemoryAttributesEx (\r
7b475490
DT
623 IN UINTN PageTableBase,\r
624 IN BOOLEAN EnablePML5Paging,\r
053e878b
MK
625 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
626 IN UINT64 Length,\r
627 IN UINT64 Attributes,\r
628 OUT BOOLEAN *IsSplitted OPTIONAL\r
717fb604
JY
629 )\r
630{\r
631 EFI_STATUS Status;\r
632 BOOLEAN IsModified;\r
633\r
7b475490 634 Status = ConvertMemoryPageAttributes (PageTableBase, EnablePML5Paging, BaseAddress, Length, Attributes, FALSE, IsSplitted, &IsModified);\r
053e878b 635 if (!EFI_ERROR (Status)) {\r
717fb604
JY
636 if (IsModified) {\r
637 //\r
638 // Flush TLB as last step\r
639 //\r
053e878b 640 FlushTlbForAll ();\r
717fb604
JY
641 }\r
642 }\r
643\r
644 return Status;\r
645}\r
646\r
647/**\r
648 This function sets the attributes for the memory region specified by BaseAddress and\r
649 Length from their current attributes to the attributes specified by Attributes.\r
650\r
651 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
652 @param[in] Length The size in bytes of the memory region.\r
653 @param[in] Attributes The bit mask of attributes to set for the memory region.\r
654\r
655 @retval EFI_SUCCESS The attributes were set for the memory region.\r
656 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
657 BaseAddress and Length cannot be modified.\r
658 @retval EFI_INVALID_PARAMETER Length is zero.\r
659 Attributes specified an illegal combination of attributes that\r
660 cannot be set together.\r
661 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
662 the memory resource range.\r
663 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
664 resource range specified by BaseAddress and Length.\r
aae02dcc 665 The bit mask of attributes is not supported for the memory resource\r
717fb604
JY
666 range specified by BaseAddress and Length.\r
667\r
668**/\r
669EFI_STATUS\r
717fb604 670SmmSetMemoryAttributes (\r
053e878b
MK
671 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
672 IN UINT64 Length,\r
673 IN UINT64 Attributes\r
717fb604
JY
674 )\r
675{\r
7b475490
DT
676 IA32_CR4 Cr4;\r
677 UINTN PageTableBase;\r
678 BOOLEAN Enable5LevelPaging;\r
679\r
680 PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;\r
681 Cr4.UintN = AsmReadCr4 ();\r
682 Enable5LevelPaging = (BOOLEAN)(Cr4.Bits.LA57 == 1);\r
683 return SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, BaseAddress, Length, Attributes, NULL);\r
717fb604
JY
684}\r
685\r
686/**\r
687 This function clears the attributes for the memory region specified by BaseAddress and\r
688 Length from their current attributes to the attributes specified by Attributes.\r
689\r
690 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
691 @param[in] Length The size in bytes of the memory region.\r
692 @param[in] Attributes The bit mask of attributes to clear for the memory region.\r
693\r
694 @retval EFI_SUCCESS The attributes were cleared for the memory region.\r
695 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
696 BaseAddress and Length cannot be modified.\r
697 @retval EFI_INVALID_PARAMETER Length is zero.\r
698 Attributes specified an illegal combination of attributes that\r
aae02dcc 699 cannot be cleared together.\r
717fb604
JY
700 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
701 the memory resource range.\r
702 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
703 resource range specified by BaseAddress and Length.\r
aae02dcc 704 The bit mask of attributes is not supported for the memory resource\r
717fb604
JY
705 range specified by BaseAddress and Length.\r
706\r
707**/\r
708EFI_STATUS\r
717fb604 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
7b475490
DT
715 IA32_CR4 Cr4;\r
716 UINTN PageTableBase;\r
717 BOOLEAN Enable5LevelPaging;\r
718\r
719 PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;\r
720 Cr4.UintN = AsmReadCr4 ();\r
721 Enable5LevelPaging = (BOOLEAN)(Cr4.Bits.LA57 == 1);\r
722 return SmmClearMemoryAttributesEx (PageTableBase, Enable5LevelPaging, BaseAddress, Length, Attributes, NULL);\r
717fb604
JY
723}\r
724\r
3eb69b08
JY
725/**\r
726 Set ShadowStack memory.\r
727\r
728 @param[in] Cr3 The page table base address.\r
729 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
730 @param[in] Length The size in bytes of the memory region.\r
731\r
732 @retval EFI_SUCCESS The shadow stack memory is set.\r
733**/\r
734EFI_STATUS\r
735SetShadowStack (\r
053e878b
MK
736 IN UINTN Cr3,\r
737 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
738 IN UINT64 Length\r
3eb69b08
JY
739 )\r
740{\r
741 EFI_STATUS Status;\r
742\r
83d58711 743 mIsShadowStack = TRUE;\r
7b475490 744 Status = SmmSetMemoryAttributesEx (Cr3, m5LevelPagingNeeded, BaseAddress, Length, EFI_MEMORY_RO, NULL);\r
83d58711 745 mIsShadowStack = FALSE;\r
3eb69b08
JY
746\r
747 return Status;\r
748}\r
749\r
750/**\r
751 Set not present memory.\r
752\r
753 @param[in] Cr3 The page table base address.\r
754 @param[in] BaseAddress The physical address that is the start address of a memory region.\r
755 @param[in] Length The size in bytes of the memory region.\r
717fb604 756\r
3eb69b08
JY
757 @retval EFI_SUCCESS The not present memory is set.\r
758**/\r
759EFI_STATUS\r
760SetNotPresentPage (\r
053e878b
MK
761 IN UINTN Cr3,\r
762 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
763 IN UINT64 Length\r
3eb69b08
JY
764 )\r
765{\r
766 EFI_STATUS Status;\r
767\r
7b475490 768 Status = SmmSetMemoryAttributesEx (Cr3, m5LevelPagingNeeded, BaseAddress, Length, EFI_MEMORY_RP, NULL);\r
3eb69b08
JY
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
7b475490
DT
1561 UINTN PageTableBase;\r
1562 BOOLEAN EnablePML5Paging;\r
1563 IA32_CR4 Cr4;\r
827330cc 1564\r
053e878b 1565 if ((Length < SIZE_4KB) || (Attributes == NULL)) {\r
827330cc
JW
1566 return EFI_INVALID_PARAMETER;\r
1567 }\r
1568\r
053e878b 1569 Size = (INT64)Length;\r
827330cc
JW
1570 MemAttr = (UINT64)-1;\r
1571\r
7b475490
DT
1572 PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;\r
1573 Cr4.UintN = AsmReadCr4 ();\r
1574 EnablePML5Paging = (BOOLEAN)(Cr4.Bits.LA57 == 1);\r
1575\r
827330cc 1576 do {\r
7b475490 1577 PageEntry = GetPageTableEntry (PageTableBase, EnablePML5Paging, BaseAddress, &PageAttr);\r
053e878b 1578 if ((PageEntry == NULL) || (PageAttr == PageNone)) {\r
827330cc
JW
1579 return EFI_UNSUPPORTED;\r
1580 }\r
1581\r
1582 //\r
1583 // If the memory range is cross page table boundary, make sure they\r
1584 // share the same attribute. Return EFI_NO_MAPPING if not.\r
1585 //\r
1586 *Attributes = GetAttributesFromPageEntry (PageEntry);\r
053e878b 1587 if ((MemAttr != (UINT64)-1) && (*Attributes != MemAttr)) {\r
827330cc
JW
1588 return EFI_NO_MAPPING;\r
1589 }\r
1590\r
1591 switch (PageAttr) {\r
053e878b
MK
1592 case Page4K:\r
1593 Address = *PageEntry & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64;\r
1594 Size -= (SIZE_4KB - (BaseAddress - Address));\r
1595 BaseAddress += (SIZE_4KB - (BaseAddress - Address));\r
1596 break;\r
827330cc 1597\r
053e878b
MK
1598 case Page2M:\r
1599 Address = *PageEntry & ~mAddressEncMask & PAGING_2M_ADDRESS_MASK_64;\r
1600 Size -= SIZE_2MB - (BaseAddress - Address);\r
1601 BaseAddress += SIZE_2MB - (BaseAddress - Address);\r
1602 break;\r
1603\r
1604 case Page1G:\r
1605 Address = *PageEntry & ~mAddressEncMask & PAGING_1G_ADDRESS_MASK_64;\r
1606 Size -= SIZE_1GB - (BaseAddress - Address);\r
1607 BaseAddress += SIZE_1GB - (BaseAddress - Address);\r
1608 break;\r
1609\r
1610 default:\r
1611 return EFI_UNSUPPORTED;\r
827330cc
JW
1612 }\r
1613\r
1614 MemAttr = *Attributes;\r
827330cc
JW
1615 } while (Size > 0);\r
1616\r
1617 return EFI_SUCCESS;\r
1618}\r