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