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