]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
UefiCpuPkg/PiSmmCpu: Check XdSupport before set NX.
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / SmmCpuMemoryManagement.c
1 /** @file
2
3 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 **/
13
14 #include "PiSmmCpuDxeSmm.h"
15
16 #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
17 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
18
19 PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
20 {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},
21 {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},
22 {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},
23 };
24
25 /**
26 Return page table base.
27
28 @return page table base.
29 **/
30 UINTN
31 GetPageTableBase (
32 VOID
33 )
34 {
35 return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);
36 }
37
38 /**
39 Return length according to page attributes.
40
41 @param[in] PageAttributes The page attribute of the page entry.
42
43 @return The length of page entry.
44 **/
45 UINTN
46 PageAttributeToLength (
47 IN PAGE_ATTRIBUTE PageAttribute
48 )
49 {
50 UINTN Index;
51 for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
52 if (PageAttribute == mPageAttributeTable[Index].Attribute) {
53 return (UINTN)mPageAttributeTable[Index].Length;
54 }
55 }
56 return 0;
57 }
58
59 /**
60 Return address mask according to page attributes.
61
62 @param[in] PageAttributes The page attribute of the page entry.
63
64 @return The address mask of page entry.
65 **/
66 UINTN
67 PageAttributeToMask (
68 IN PAGE_ATTRIBUTE PageAttribute
69 )
70 {
71 UINTN Index;
72 for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
73 if (PageAttribute == mPageAttributeTable[Index].Attribute) {
74 return (UINTN)mPageAttributeTable[Index].AddressMask;
75 }
76 }
77 return 0;
78 }
79
80 /**
81 Return page table entry to match the address.
82
83 @param[in] Address The address to be checked.
84 @param[out] PageAttributes The page attribute of the page entry.
85
86 @return The page entry.
87 **/
88 VOID *
89 GetPageTableEntry (
90 IN PHYSICAL_ADDRESS Address,
91 OUT PAGE_ATTRIBUTE *PageAttribute
92 )
93 {
94 UINTN Index1;
95 UINTN Index2;
96 UINTN Index3;
97 UINTN Index4;
98 UINT64 *L1PageTable;
99 UINT64 *L2PageTable;
100 UINT64 *L3PageTable;
101 UINT64 *L4PageTable;
102
103 Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;
104 Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;
105 Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;
106 Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;
107
108 if (sizeof(UINTN) == sizeof(UINT64)) {
109 L4PageTable = (UINT64 *)GetPageTableBase ();
110 if (L4PageTable[Index4] == 0) {
111 *PageAttribute = PageNone;
112 return NULL;
113 }
114
115 L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);
116 } else {
117 L3PageTable = (UINT64 *)GetPageTableBase ();
118 }
119 if (L3PageTable[Index3] == 0) {
120 *PageAttribute = PageNone;
121 return NULL;
122 }
123 if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
124 // 1G
125 *PageAttribute = Page1G;
126 return &L3PageTable[Index3];
127 }
128
129 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
130 if (L2PageTable[Index2] == 0) {
131 *PageAttribute = PageNone;
132 return NULL;
133 }
134 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
135 // 2M
136 *PageAttribute = Page2M;
137 return &L2PageTable[Index2];
138 }
139
140 // 4k
141 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
142 if ((L1PageTable[Index1] == 0) && (Address != 0)) {
143 *PageAttribute = PageNone;
144 return NULL;
145 }
146 *PageAttribute = Page4K;
147 return &L1PageTable[Index1];
148 }
149
150 /**
151 Return memory attributes of page entry.
152
153 @param[in] PageEntry The page entry.
154
155 @return Memory attributes of page entry.
156 **/
157 UINT64
158 GetAttributesFromPageEntry (
159 IN UINT64 *PageEntry
160 )
161 {
162 UINT64 Attributes;
163 Attributes = 0;
164 if ((*PageEntry & IA32_PG_P) == 0) {
165 Attributes |= EFI_MEMORY_RP;
166 }
167 if ((*PageEntry & IA32_PG_RW) == 0) {
168 Attributes |= EFI_MEMORY_RO;
169 }
170 if ((*PageEntry & IA32_PG_NX) != 0) {
171 Attributes |= EFI_MEMORY_XP;
172 }
173 return Attributes;
174 }
175
176 /**
177 Modify memory attributes of page entry.
178
179 @param[in] PageEntry The page entry.
180 @param[in] Attributes The bit mask of attributes to modify for the memory region.
181 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
182 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
183 **/
184 VOID
185 ConvertPageEntryAttribute (
186 IN UINT64 *PageEntry,
187 IN UINT64 Attributes,
188 IN BOOLEAN IsSet,
189 OUT BOOLEAN *IsModified
190 )
191 {
192 UINT64 CurrentPageEntry;
193 UINT64 NewPageEntry;
194
195 CurrentPageEntry = *PageEntry;
196 NewPageEntry = CurrentPageEntry;
197 if ((Attributes & EFI_MEMORY_RP) != 0) {
198 if (IsSet) {
199 NewPageEntry &= ~(UINT64)IA32_PG_P;
200 } else {
201 NewPageEntry |= IA32_PG_P;
202 }
203 }
204 if ((Attributes & EFI_MEMORY_RO) != 0) {
205 if (IsSet) {
206 NewPageEntry &= ~(UINT64)IA32_PG_RW;
207 } else {
208 NewPageEntry |= IA32_PG_RW;
209 }
210 }
211 if ((Attributes & EFI_MEMORY_XP) != 0) {
212 if (mXdSupported) {
213 if (IsSet) {
214 NewPageEntry |= IA32_PG_NX;
215 } else {
216 NewPageEntry &= ~IA32_PG_NX;
217 }
218 }
219 }
220 *PageEntry = NewPageEntry;
221 if (CurrentPageEntry != NewPageEntry) {
222 *IsModified = TRUE;
223 DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));
224 DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));
225 } else {
226 *IsModified = FALSE;
227 }
228 }
229
230 /**
231 This function returns if there is need to split page entry.
232
233 @param[in] BaseAddress The base address to be checked.
234 @param[in] Length The length to be checked.
235 @param[in] PageEntry The page entry to be checked.
236 @param[in] PageAttribute The page attribute of the page entry.
237
238 @retval SplitAttributes on if there is need to split page entry.
239 **/
240 PAGE_ATTRIBUTE
241 NeedSplitPage (
242 IN PHYSICAL_ADDRESS BaseAddress,
243 IN UINT64 Length,
244 IN UINT64 *PageEntry,
245 IN PAGE_ATTRIBUTE PageAttribute
246 )
247 {
248 UINT64 PageEntryLength;
249
250 PageEntryLength = PageAttributeToLength (PageAttribute);
251
252 if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {
253 return PageNone;
254 }
255
256 if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {
257 return Page4K;
258 }
259
260 return Page2M;
261 }
262
263 /**
264 This function splits one page entry to small page entries.
265
266 @param[in] PageEntry The page entry to be splitted.
267 @param[in] PageAttribute The page attribute of the page entry.
268 @param[in] SplitAttribute How to split the page entry.
269
270 @retval RETURN_SUCCESS The page entry is splitted.
271 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
272 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
273 **/
274 RETURN_STATUS
275 SplitPage (
276 IN UINT64 *PageEntry,
277 IN PAGE_ATTRIBUTE PageAttribute,
278 IN PAGE_ATTRIBUTE SplitAttribute
279 )
280 {
281 UINT64 BaseAddress;
282 UINT64 *NewPageEntry;
283 UINTN Index;
284
285 ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);
286
287 if (PageAttribute == Page2M) {
288 //
289 // Split 2M to 4K
290 //
291 ASSERT (SplitAttribute == Page4K);
292 if (SplitAttribute == Page4K) {
293 NewPageEntry = AllocatePageTableMemory (1);
294 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
295 if (NewPageEntry == NULL) {
296 return RETURN_OUT_OF_RESOURCES;
297 }
298 BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;
299 for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
300 NewPageEntry[Index] = BaseAddress + SIZE_4KB * Index + ((*PageEntry) & PAGE_PROGATE_BITS);
301 }
302 (*PageEntry) = (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & PAGE_PROGATE_BITS);
303 return RETURN_SUCCESS;
304 } else {
305 return RETURN_UNSUPPORTED;
306 }
307 } else if (PageAttribute == Page1G) {
308 //
309 // Split 1G to 2M
310 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
311 //
312 ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);
313 if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {
314 NewPageEntry = AllocatePageTableMemory (1);
315 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
316 if (NewPageEntry == NULL) {
317 return RETURN_OUT_OF_RESOURCES;
318 }
319 BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;
320 for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
321 NewPageEntry[Index] = BaseAddress + SIZE_2MB * Index + IA32_PG_PS + ((*PageEntry) & PAGE_PROGATE_BITS);
322 }
323 (*PageEntry) = (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & PAGE_PROGATE_BITS);
324 return RETURN_SUCCESS;
325 } else {
326 return RETURN_UNSUPPORTED;
327 }
328 } else {
329 return RETURN_UNSUPPORTED;
330 }
331 }
332
333 /**
334 This function modifies the page attributes for the memory region specified by BaseAddress and
335 Length from their current attributes to the attributes specified by Attributes.
336
337 Caller should make sure BaseAddress and Length is at page boundary.
338
339 @param[in] BaseAddress The physical address that is the start address of a memory region.
340 @param[in] Length The size in bytes of the memory region.
341 @param[in] Attributes The bit mask of attributes to modify for the memory region.
342 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
343 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
344 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
345
346 @retval RETURN_SUCCESS The attributes were modified for the memory region.
347 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
348 BaseAddress and Length cannot be modified.
349 @retval RETURN_INVALID_PARAMETER Length is zero.
350 Attributes specified an illegal combination of attributes that
351 cannot be set together.
352 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
353 the memory resource range.
354 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
355 resource range specified by BaseAddress and Length.
356 The bit mask of attributes is not support for the memory resource
357 range specified by BaseAddress and Length.
358 **/
359 RETURN_STATUS
360 EFIAPI
361 ConvertMemoryPageAttributes (
362 IN PHYSICAL_ADDRESS BaseAddress,
363 IN UINT64 Length,
364 IN UINT64 Attributes,
365 IN BOOLEAN IsSet,
366 OUT BOOLEAN *IsSplitted, OPTIONAL
367 OUT BOOLEAN *IsModified OPTIONAL
368 )
369 {
370 UINT64 *PageEntry;
371 PAGE_ATTRIBUTE PageAttribute;
372 UINTN PageEntryLength;
373 PAGE_ATTRIBUTE SplitAttribute;
374 RETURN_STATUS Status;
375 BOOLEAN IsEntryModified;
376
377 ASSERT (Attributes != 0);
378 ASSERT ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP)) == 0);
379
380 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
381 ASSERT ((Length & (SIZE_4KB - 1)) == 0);
382
383 if (Length == 0) {
384 return RETURN_INVALID_PARAMETER;
385 }
386
387 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
388
389 if (IsSplitted != NULL) {
390 *IsSplitted = FALSE;
391 }
392 if (IsModified != NULL) {
393 *IsModified = FALSE;
394 }
395
396 //
397 // Below logic is to check 2M/4K page to make sure we donot waist memory.
398 //
399 while (Length != 0) {
400 PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);
401 if (PageEntry == NULL) {
402 return RETURN_UNSUPPORTED;
403 }
404 PageEntryLength = PageAttributeToLength (PageAttribute);
405 SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute);
406 if (SplitAttribute == PageNone) {
407 ConvertPageEntryAttribute (PageEntry, Attributes, IsSet, &IsEntryModified);
408 if (IsEntryModified) {
409 if (IsModified != NULL) {
410 *IsModified = TRUE;
411 }
412 }
413 //
414 // Convert success, move to next
415 //
416 BaseAddress += PageEntryLength;
417 Length -= PageEntryLength;
418 } else {
419 Status = SplitPage (PageEntry, PageAttribute, SplitAttribute);
420 if (RETURN_ERROR (Status)) {
421 return RETURN_UNSUPPORTED;
422 }
423 if (IsSplitted != NULL) {
424 *IsSplitted = TRUE;
425 }
426 if (IsModified != NULL) {
427 *IsModified = TRUE;
428 }
429 //
430 // Just split current page
431 // Convert success in next around
432 //
433 }
434 }
435
436 return RETURN_SUCCESS;
437 }
438
439 /**
440 FlushTlb on current processor.
441
442 @param[in,out] Buffer Pointer to private data buffer.
443 **/
444 VOID
445 EFIAPI
446 FlushTlbOnCurrentProcessor (
447 IN OUT VOID *Buffer
448 )
449 {
450 CpuFlushTlb ();
451 }
452
453 /**
454 FlushTlb for all processors.
455 **/
456 VOID
457 FlushTlbForAll (
458 VOID
459 )
460 {
461 UINTN Index;
462
463 FlushTlbOnCurrentProcessor (NULL);
464
465 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
466 if (Index != gSmst->CurrentlyExecutingCpu) {
467 // Force to start up AP in blocking mode,
468 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor, Index, NULL);
469 // Do not check return status, because AP might not be present in some corner cases.
470 }
471 }
472 }
473
474 /**
475 This function sets the attributes for the memory region specified by BaseAddress and
476 Length from their current attributes to the attributes specified by Attributes.
477
478 @param[in] BaseAddress The physical address that is the start address of a memory region.
479 @param[in] Length The size in bytes of the memory region.
480 @param[in] Attributes The bit mask of attributes to set for the memory region.
481 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
482
483 @retval EFI_SUCCESS The attributes were set for the memory region.
484 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
485 BaseAddress and Length cannot be modified.
486 @retval EFI_INVALID_PARAMETER Length is zero.
487 Attributes specified an illegal combination of attributes that
488 cannot be set together.
489 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
490 the memory resource range.
491 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
492 resource range specified by BaseAddress and Length.
493 The bit mask of attributes is not support for the memory resource
494 range specified by BaseAddress and Length.
495
496 **/
497 EFI_STATUS
498 EFIAPI
499 SmmSetMemoryAttributesEx (
500 IN EFI_PHYSICAL_ADDRESS BaseAddress,
501 IN UINT64 Length,
502 IN UINT64 Attributes,
503 OUT BOOLEAN *IsSplitted OPTIONAL
504 )
505 {
506 EFI_STATUS Status;
507 BOOLEAN IsModified;
508
509 Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, TRUE, IsSplitted, &IsModified);
510 if (!EFI_ERROR(Status)) {
511 if (IsModified) {
512 //
513 // Flush TLB as last step
514 //
515 FlushTlbForAll();
516 }
517 }
518
519 return Status;
520 }
521
522 /**
523 This function clears the attributes for the memory region specified by BaseAddress and
524 Length from their current attributes to the attributes specified by Attributes.
525
526 @param[in] BaseAddress The physical address that is the start address of a memory region.
527 @param[in] Length The size in bytes of the memory region.
528 @param[in] Attributes The bit mask of attributes to clear for the memory region.
529 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
530
531 @retval EFI_SUCCESS The attributes were cleared for the memory region.
532 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
533 BaseAddress and Length cannot be modified.
534 @retval EFI_INVALID_PARAMETER Length is zero.
535 Attributes specified an illegal combination of attributes that
536 cannot be set together.
537 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
538 the memory resource range.
539 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
540 resource range specified by BaseAddress and Length.
541 The bit mask of attributes is not support for the memory resource
542 range specified by BaseAddress and Length.
543
544 **/
545 EFI_STATUS
546 EFIAPI
547 SmmClearMemoryAttributesEx (
548 IN EFI_PHYSICAL_ADDRESS BaseAddress,
549 IN UINT64 Length,
550 IN UINT64 Attributes,
551 OUT BOOLEAN *IsSplitted OPTIONAL
552 )
553 {
554 EFI_STATUS Status;
555 BOOLEAN IsModified;
556
557 Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, FALSE, IsSplitted, &IsModified);
558 if (!EFI_ERROR(Status)) {
559 if (IsModified) {
560 //
561 // Flush TLB as last step
562 //
563 FlushTlbForAll();
564 }
565 }
566
567 return Status;
568 }
569
570 /**
571 This function sets the attributes for the memory region specified by BaseAddress and
572 Length from their current attributes to the attributes specified by Attributes.
573
574 @param[in] BaseAddress The physical address that is the start address of a memory region.
575 @param[in] Length The size in bytes of the memory region.
576 @param[in] Attributes The bit mask of attributes to set for the memory region.
577
578 @retval EFI_SUCCESS The attributes were set for the memory region.
579 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
580 BaseAddress and Length cannot be modified.
581 @retval EFI_INVALID_PARAMETER Length is zero.
582 Attributes specified an illegal combination of attributes that
583 cannot be set together.
584 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
585 the memory resource range.
586 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
587 resource range specified by BaseAddress and Length.
588 The bit mask of attributes is not support for the memory resource
589 range specified by BaseAddress and Length.
590
591 **/
592 EFI_STATUS
593 EFIAPI
594 SmmSetMemoryAttributes (
595 IN EFI_PHYSICAL_ADDRESS BaseAddress,
596 IN UINT64 Length,
597 IN UINT64 Attributes
598 )
599 {
600 return SmmSetMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
601 }
602
603 /**
604 This function clears the attributes for the memory region specified by BaseAddress and
605 Length from their current attributes to the attributes specified by Attributes.
606
607 @param[in] BaseAddress The physical address that is the start address of a memory region.
608 @param[in] Length The size in bytes of the memory region.
609 @param[in] Attributes The bit mask of attributes to clear for the memory region.
610
611 @retval EFI_SUCCESS The attributes were cleared for the memory region.
612 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
613 BaseAddress and Length cannot be modified.
614 @retval EFI_INVALID_PARAMETER Length is zero.
615 Attributes specified an illegal combination of attributes that
616 cannot be set together.
617 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
618 the memory resource range.
619 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
620 resource range specified by BaseAddress and Length.
621 The bit mask of attributes is not support for the memory resource
622 range specified by BaseAddress and Length.
623
624 **/
625 EFI_STATUS
626 EFIAPI
627 SmmClearMemoryAttributes (
628 IN EFI_PHYSICAL_ADDRESS BaseAddress,
629 IN UINT64 Length,
630 IN UINT64 Attributes
631 )
632 {
633 return SmmClearMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
634 }
635
636
637
638 /**
639 Retrieves a pointer to the system configuration table from the SMM System Table
640 based on a specified GUID.
641
642 @param[in] TableGuid The pointer to table's GUID type.
643 @param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.
644
645 @retval EFI_SUCCESS A configuration table matching TableGuid was found.
646 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
647
648 **/
649 EFI_STATUS
650 EFIAPI
651 SmmGetSystemConfigurationTable (
652 IN EFI_GUID *TableGuid,
653 OUT VOID **Table
654 )
655 {
656 UINTN Index;
657
658 ASSERT (TableGuid != NULL);
659 ASSERT (Table != NULL);
660
661 *Table = NULL;
662 for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {
663 if (CompareGuid (TableGuid, &(gSmst->SmmConfigurationTable[Index].VendorGuid))) {
664 *Table = gSmst->SmmConfigurationTable[Index].VendorTable;
665 return EFI_SUCCESS;
666 }
667 }
668
669 return EFI_NOT_FOUND;
670 }
671
672 /**
673 This function sets SMM save state buffer to be RW and XP.
674 **/
675 VOID
676 PatchSmmSaveStateMap (
677 VOID
678 )
679 {
680 UINTN Index;
681 UINTN TileCodeSize;
682 UINTN TileDataSize;
683 UINTN TileSize;
684
685 TileCodeSize = GetSmiHandlerSize ();
686 TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);
687 TileDataSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR);
688 TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);
689 TileSize = TileDataSize + TileCodeSize - 1;
690 TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);
691
692 DEBUG ((DEBUG_INFO, "PatchSmmSaveStateMap:\n"));
693 for (Index = 0; Index < mMaxNumberOfCpus - 1; Index++) {
694 //
695 // Code
696 //
697 SmmSetMemoryAttributes (
698 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,
699 TileCodeSize,
700 EFI_MEMORY_RO
701 );
702 SmmClearMemoryAttributes (
703 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,
704 TileCodeSize,
705 EFI_MEMORY_XP
706 );
707
708 //
709 // Data
710 //
711 SmmClearMemoryAttributes (
712 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,
713 TileSize - TileCodeSize,
714 EFI_MEMORY_RO
715 );
716 SmmSetMemoryAttributes (
717 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,
718 TileSize - TileCodeSize,
719 EFI_MEMORY_XP
720 );
721 }
722
723 //
724 // Code
725 //
726 SmmSetMemoryAttributes (
727 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,
728 TileCodeSize,
729 EFI_MEMORY_RO
730 );
731 SmmClearMemoryAttributes (
732 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,
733 TileCodeSize,
734 EFI_MEMORY_XP
735 );
736
737 //
738 // Data
739 //
740 SmmClearMemoryAttributes (
741 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,
742 SIZE_32KB - TileCodeSize,
743 EFI_MEMORY_RO
744 );
745 SmmSetMemoryAttributes (
746 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,
747 SIZE_32KB - TileCodeSize,
748 EFI_MEMORY_XP
749 );
750 }
751
752 /**
753 This function sets GDT/IDT buffer to be RO and XP.
754 **/
755 VOID
756 PatchGdtIdtMap (
757 VOID
758 )
759 {
760 EFI_PHYSICAL_ADDRESS BaseAddress;
761 UINTN Size;
762
763 //
764 // GDT
765 //
766 DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
767
768 BaseAddress = mGdtBuffer;
769 Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
770 SmmSetMemoryAttributes (
771 BaseAddress,
772 Size,
773 EFI_MEMORY_RO
774 );
775 SmmSetMemoryAttributes (
776 BaseAddress,
777 Size,
778 EFI_MEMORY_XP
779 );
780
781 //
782 // IDT
783 //
784 DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
785
786 BaseAddress = gcSmiIdtr.Base;
787 Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
788 SmmSetMemoryAttributes (
789 BaseAddress,
790 Size,
791 EFI_MEMORY_RO
792 );
793 SmmSetMemoryAttributes (
794 BaseAddress,
795 Size,
796 EFI_MEMORY_XP
797 );
798 }
799
800 /**
801 This function sets memory attribute according to MemoryAttributesTable.
802 **/
803 VOID
804 SetMemMapAttributes (
805 VOID
806 )
807 {
808 EFI_MEMORY_DESCRIPTOR *MemoryMap;
809 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
810 UINTN MemoryMapEntryCount;
811 UINTN DescriptorSize;
812 UINTN Index;
813 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
814
815 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
816 if (MemoryAttributesTable == NULL) {
817 DEBUG ((DEBUG_INFO, "MemoryAttributesTable - NULL\n"));
818 return ;
819 }
820
821 DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n"));
822 DEBUG ((DEBUG_INFO, " Version - 0x%08x\n", MemoryAttributesTable->Version));
823 DEBUG ((DEBUG_INFO, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
824 DEBUG ((DEBUG_INFO, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
825
826 MemoryMapEntryCount = MemoryAttributesTable->NumberOfEntries;
827 DescriptorSize = MemoryAttributesTable->DescriptorSize;
828 MemoryMapStart = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
829 MemoryMap = MemoryMapStart;
830 for (Index = 0; Index < MemoryMapEntryCount; Index++) {
831 DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryMap));
832 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", MemoryMap->Type));
833 DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", MemoryMap->PhysicalStart));
834 DEBUG ((DEBUG_INFO, " VirtualStart - 0x%016lx\n", MemoryMap->VirtualStart));
835 DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%016lx\n", MemoryMap->NumberOfPages));
836 DEBUG ((DEBUG_INFO, " Attribute - 0x%016lx\n", MemoryMap->Attribute));
837 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
838 }
839
840 MemoryMap = MemoryMapStart;
841 for (Index = 0; Index < MemoryMapEntryCount; Index++) {
842 DEBUG ((DEBUG_VERBOSE, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap->PhysicalStart, MemoryMap->NumberOfPages));
843 switch (MemoryMap->Type) {
844 case EfiRuntimeServicesCode:
845 SmmSetMemoryAttributes (
846 MemoryMap->PhysicalStart,
847 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
848 EFI_MEMORY_RO
849 );
850 break;
851 case EfiRuntimeServicesData:
852 SmmSetMemoryAttributes (
853 MemoryMap->PhysicalStart,
854 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
855 EFI_MEMORY_XP
856 );
857 break;
858 default:
859 SmmSetMemoryAttributes (
860 MemoryMap->PhysicalStart,
861 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
862 EFI_MEMORY_XP
863 );
864 break;
865 }
866 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
867 }
868
869 PatchSmmSaveStateMap ();
870 PatchGdtIdtMap ();
871
872 return ;
873 }