3 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
8 #include "PiSmmCpuDxeSmm.h"
11 // attributes for reserved memory before it is promoted to system memory
13 #define EFI_MEMORY_PRESENT 0x0100000000000000ULL
14 #define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
15 #define EFI_MEMORY_TESTED 0x0400000000000000ULL
17 #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
18 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
20 EFI_MEMORY_DESCRIPTOR
*mUefiMemoryMap
;
21 UINTN mUefiMemoryMapSize
;
22 UINTN mUefiDescriptorSize
;
24 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*mGcdMemSpace
= NULL
;
25 UINTN mGcdMemNumberOfDesc
= 0;
27 EFI_MEMORY_ATTRIBUTES_TABLE
*mUefiMemoryAttributesTable
= NULL
;
29 PAGE_ATTRIBUTE_TABLE mPageAttributeTable
[] = {
30 { Page4K
, SIZE_4KB
, PAGING_4K_ADDRESS_MASK_64
},
31 { Page2M
, SIZE_2MB
, PAGING_2M_ADDRESS_MASK_64
},
32 { Page1G
, SIZE_1GB
, PAGING_1G_ADDRESS_MASK_64
},
35 BOOLEAN mIsShadowStack
= FALSE
;
36 BOOLEAN m5LevelPagingNeeded
= FALSE
;
39 Return length according to page attributes.
41 @param[in] PageAttributes The page attribute of the page entry.
43 @return The length of page entry.
46 PageAttributeToLength (
47 IN PAGE_ATTRIBUTE PageAttribute
52 for (Index
= 0; Index
< sizeof (mPageAttributeTable
)/sizeof (mPageAttributeTable
[0]); Index
++) {
53 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
54 return (UINTN
)mPageAttributeTable
[Index
].Length
;
62 Return address mask according to page attributes.
64 @param[in] PageAttributes The page attribute of the page entry.
66 @return The address mask of page entry.
70 IN PAGE_ATTRIBUTE PageAttribute
75 for (Index
= 0; Index
< sizeof (mPageAttributeTable
)/sizeof (mPageAttributeTable
[0]); Index
++) {
76 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
77 return (UINTN
)mPageAttributeTable
[Index
].AddressMask
;
85 Return page table entry to match the address.
87 @param[in] PageTableBase The page table base.
88 @param[in] Enable5LevelPaging If PML5 paging is enabled.
89 @param[in] Address The address to be checked.
90 @param[out] PageAttributes The page attribute of the page entry.
92 @return The page entry.
96 IN UINTN PageTableBase
,
97 IN BOOLEAN Enable5LevelPaging
,
98 IN PHYSICAL_ADDRESS Address
,
99 OUT PAGE_ATTRIBUTE
*PageAttribute
113 Index5
= ((UINTN
)RShiftU64 (Address
, 48)) & PAGING_PAE_INDEX_MASK
;
114 Index4
= ((UINTN
)RShiftU64 (Address
, 39)) & PAGING_PAE_INDEX_MASK
;
115 Index3
= ((UINTN
)Address
>> 30) & PAGING_PAE_INDEX_MASK
;
116 Index2
= ((UINTN
)Address
>> 21) & PAGING_PAE_INDEX_MASK
;
117 Index1
= ((UINTN
)Address
>> 12) & PAGING_PAE_INDEX_MASK
;
119 if (sizeof (UINTN
) == sizeof (UINT64
)) {
120 if (Enable5LevelPaging
) {
121 L5PageTable
= (UINT64
*)PageTableBase
;
122 if (L5PageTable
[Index5
] == 0) {
123 *PageAttribute
= PageNone
;
127 L4PageTable
= (UINT64
*)(UINTN
)(L5PageTable
[Index5
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
129 L4PageTable
= (UINT64
*)PageTableBase
;
132 if (L4PageTable
[Index4
] == 0) {
133 *PageAttribute
= PageNone
;
137 L3PageTable
= (UINT64
*)(UINTN
)(L4PageTable
[Index4
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
139 L3PageTable
= (UINT64
*)PageTableBase
;
142 if (L3PageTable
[Index3
] == 0) {
143 *PageAttribute
= PageNone
;
147 if ((L3PageTable
[Index3
] & IA32_PG_PS
) != 0) {
149 *PageAttribute
= Page1G
;
150 return &L3PageTable
[Index3
];
153 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
154 if (L2PageTable
[Index2
] == 0) {
155 *PageAttribute
= PageNone
;
159 if ((L2PageTable
[Index2
] & IA32_PG_PS
) != 0) {
161 *PageAttribute
= Page2M
;
162 return &L2PageTable
[Index2
];
166 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
167 if ((L1PageTable
[Index1
] == 0) && (Address
!= 0)) {
168 *PageAttribute
= PageNone
;
172 *PageAttribute
= Page4K
;
173 return &L1PageTable
[Index1
];
177 Return memory attributes of page entry.
179 @param[in] PageEntry The page entry.
181 @return Memory attributes of page entry.
184 GetAttributesFromPageEntry (
191 if ((*PageEntry
& IA32_PG_P
) == 0) {
192 Attributes
|= EFI_MEMORY_RP
;
195 if ((*PageEntry
& IA32_PG_RW
) == 0) {
196 Attributes
|= EFI_MEMORY_RO
;
199 if ((*PageEntry
& IA32_PG_NX
) != 0) {
200 Attributes
|= EFI_MEMORY_XP
;
207 Modify memory attributes of page entry.
209 @param[in] PageEntry The page entry.
210 @param[in] Attributes The bit mask of attributes to modify for the memory region.
211 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
212 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
215 ConvertPageEntryAttribute (
216 IN UINT64
*PageEntry
,
217 IN UINT64 Attributes
,
219 OUT BOOLEAN
*IsModified
222 UINT64 CurrentPageEntry
;
225 CurrentPageEntry
= *PageEntry
;
226 NewPageEntry
= CurrentPageEntry
;
227 if ((Attributes
& EFI_MEMORY_RP
) != 0) {
229 NewPageEntry
&= ~(UINT64
)IA32_PG_P
;
231 NewPageEntry
|= IA32_PG_P
;
235 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
237 NewPageEntry
&= ~(UINT64
)IA32_PG_RW
;
238 if (mIsShadowStack
) {
240 // ReadOnly page need set Dirty bit for shadow stack
241 NewPageEntry
|= IA32_PG_D
;
242 // Clear user bit for supervisor shadow stack
243 NewPageEntry
&= ~(UINT64
)IA32_PG_U
;
246 // Clear dirty bit for non shadow stack, to protect RO page.
247 NewPageEntry
&= ~(UINT64
)IA32_PG_D
;
250 NewPageEntry
|= IA32_PG_RW
;
254 if ((Attributes
& EFI_MEMORY_XP
) != 0) {
257 NewPageEntry
|= IA32_PG_NX
;
259 NewPageEntry
&= ~IA32_PG_NX
;
264 *PageEntry
= NewPageEntry
;
265 if (CurrentPageEntry
!= NewPageEntry
) {
267 DEBUG ((DEBUG_VERBOSE
, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry
));
268 DEBUG ((DEBUG_VERBOSE
, "->0x%lx\n", NewPageEntry
));
275 This function returns if there is need to split page entry.
277 @param[in] BaseAddress The base address to be checked.
278 @param[in] Length The length to be checked.
279 @param[in] PageEntry The page entry to be checked.
280 @param[in] PageAttribute The page attribute of the page entry.
282 @retval SplitAttributes on if there is need to split page entry.
286 IN PHYSICAL_ADDRESS BaseAddress
,
288 IN UINT64
*PageEntry
,
289 IN PAGE_ATTRIBUTE PageAttribute
292 UINT64 PageEntryLength
;
294 PageEntryLength
= PageAttributeToLength (PageAttribute
);
296 if (((BaseAddress
& (PageEntryLength
- 1)) == 0) && (Length
>= PageEntryLength
)) {
300 if (((BaseAddress
& PAGING_2M_MASK
) != 0) || (Length
< SIZE_2MB
)) {
308 This function splits one page entry to small page entries.
310 @param[in] PageEntry The page entry to be splitted.
311 @param[in] PageAttribute The page attribute of the page entry.
312 @param[in] SplitAttribute How to split the page entry.
314 @retval RETURN_SUCCESS The page entry is splitted.
315 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
316 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
320 IN UINT64
*PageEntry
,
321 IN PAGE_ATTRIBUTE PageAttribute
,
322 IN PAGE_ATTRIBUTE SplitAttribute
326 UINT64
*NewPageEntry
;
329 ASSERT (PageAttribute
== Page2M
|| PageAttribute
== Page1G
);
331 if (PageAttribute
== Page2M
) {
335 ASSERT (SplitAttribute
== Page4K
);
336 if (SplitAttribute
== Page4K
) {
337 NewPageEntry
= AllocatePageTableMemory (1);
338 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
339 if (NewPageEntry
== NULL
) {
340 return RETURN_OUT_OF_RESOURCES
;
343 BaseAddress
= *PageEntry
& PAGING_2M_ADDRESS_MASK_64
;
344 for (Index
= 0; Index
< SIZE_4KB
/ sizeof (UINT64
); Index
++) {
345 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_4KB
* Index
) | mAddressEncMask
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
348 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
349 return RETURN_SUCCESS
;
351 return RETURN_UNSUPPORTED
;
353 } else if (PageAttribute
== Page1G
) {
356 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
358 ASSERT (SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
);
359 if (((SplitAttribute
== Page2M
) || (SplitAttribute
== Page4K
))) {
360 NewPageEntry
= AllocatePageTableMemory (1);
361 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
362 if (NewPageEntry
== NULL
) {
363 return RETURN_OUT_OF_RESOURCES
;
366 BaseAddress
= *PageEntry
& PAGING_1G_ADDRESS_MASK_64
;
367 for (Index
= 0; Index
< SIZE_4KB
/ sizeof (UINT64
); Index
++) {
368 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_2MB
* Index
) | mAddressEncMask
| IA32_PG_PS
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
371 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
372 return RETURN_SUCCESS
;
374 return RETURN_UNSUPPORTED
;
377 return RETURN_UNSUPPORTED
;
382 This function modifies the page attributes for the memory region specified by BaseAddress and
383 Length from their current attributes to the attributes specified by Attributes.
385 Caller should make sure BaseAddress and Length is at page boundary.
387 @param[in] PageTableBase The page table base.
388 @param[in] EnablePML5Paging If PML5 paging is enabled.
389 @param[in] BaseAddress The physical address that is the start address of a memory region.
390 @param[in] Length The size in bytes of the memory region.
391 @param[in] Attributes The bit mask of attributes to modify for the memory region.
392 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
393 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
394 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
396 @retval RETURN_SUCCESS The attributes were modified for the memory region.
397 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
398 BaseAddress and Length cannot be modified.
399 @retval RETURN_INVALID_PARAMETER Length is zero.
400 Attributes specified an illegal combination of attributes that
401 cannot be set together.
402 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
403 the memory resource range.
404 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
405 resource range specified by BaseAddress and Length.
406 The bit mask of attributes is not support for the memory resource
407 range specified by BaseAddress and Length.
410 ConvertMemoryPageAttributes (
411 IN UINTN PageTableBase
,
412 IN BOOLEAN EnablePML5Paging
,
413 IN PHYSICAL_ADDRESS BaseAddress
,
415 IN UINT64 Attributes
,
417 OUT BOOLEAN
*IsSplitted OPTIONAL
,
418 OUT BOOLEAN
*IsModified OPTIONAL
422 PAGE_ATTRIBUTE PageAttribute
;
423 UINTN PageEntryLength
;
424 PAGE_ATTRIBUTE SplitAttribute
;
425 RETURN_STATUS Status
;
426 BOOLEAN IsEntryModified
;
427 EFI_PHYSICAL_ADDRESS MaximumSupportMemAddress
;
429 ASSERT (Attributes
!= 0);
430 ASSERT ((Attributes
& ~EFI_MEMORY_ATTRIBUTE_MASK
) == 0);
432 ASSERT ((BaseAddress
& (SIZE_4KB
- 1)) == 0);
433 ASSERT ((Length
& (SIZE_4KB
- 1)) == 0);
436 return RETURN_INVALID_PARAMETER
;
439 MaximumSupportMemAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(LShiftU64 (1, mPhysicalAddressBits
) - 1);
440 if (BaseAddress
> MaximumSupportMemAddress
) {
441 return RETURN_UNSUPPORTED
;
444 if (Length
> MaximumSupportMemAddress
) {
445 return RETURN_UNSUPPORTED
;
448 if ((Length
!= 0) && (BaseAddress
> MaximumSupportMemAddress
- (Length
- 1))) {
449 return RETURN_UNSUPPORTED
;
452 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
454 if (IsSplitted
!= NULL
) {
458 if (IsModified
!= NULL
) {
463 // Below logic is to check 2M/4K page to make sure we do not waste memory.
465 while (Length
!= 0) {
466 PageEntry
= GetPageTableEntry (PageTableBase
, EnablePML5Paging
, BaseAddress
, &PageAttribute
);
467 if (PageEntry
== NULL
) {
468 return RETURN_UNSUPPORTED
;
471 PageEntryLength
= PageAttributeToLength (PageAttribute
);
472 SplitAttribute
= NeedSplitPage (BaseAddress
, Length
, PageEntry
, PageAttribute
);
473 if (SplitAttribute
== PageNone
) {
474 ConvertPageEntryAttribute (PageEntry
, Attributes
, IsSet
, &IsEntryModified
);
475 if (IsEntryModified
) {
476 if (IsModified
!= NULL
) {
482 // Convert success, move to next
484 BaseAddress
+= PageEntryLength
;
485 Length
-= PageEntryLength
;
487 Status
= SplitPage (PageEntry
, PageAttribute
, SplitAttribute
);
488 if (RETURN_ERROR (Status
)) {
489 return RETURN_UNSUPPORTED
;
492 if (IsSplitted
!= NULL
) {
496 if (IsModified
!= NULL
) {
501 // Just split current page
502 // Convert success in next around
507 return RETURN_SUCCESS
;
511 FlushTlb on current processor.
513 @param[in,out] Buffer Pointer to private data buffer.
517 FlushTlbOnCurrentProcessor (
525 FlushTlb for all processors.
534 FlushTlbOnCurrentProcessor (NULL
);
536 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
537 if (Index
!= gSmst
->CurrentlyExecutingCpu
) {
538 // Force to start up AP in blocking mode,
539 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor
, Index
, NULL
);
540 // Do not check return status, because AP might not be present in some corner cases.
546 This function sets the attributes for the memory region specified by BaseAddress and
547 Length from their current attributes to the attributes specified by Attributes.
549 @param[in] PageTableBase The page table base.
550 @param[in] EnablePML5Paging If PML5 paging is enabled.
551 @param[in] BaseAddress The physical address that is the start address of a memory region.
552 @param[in] Length The size in bytes of the memory region.
553 @param[in] Attributes The bit mask of attributes to set for the memory region.
554 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
556 @retval EFI_SUCCESS The attributes were set for the memory region.
557 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
558 BaseAddress and Length cannot be modified.
559 @retval EFI_INVALID_PARAMETER Length is zero.
560 Attributes specified an illegal combination of attributes that
561 cannot be set together.
562 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
563 the memory resource range.
564 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
565 resource range specified by BaseAddress and Length.
566 The bit mask of attributes is not support for the memory resource
567 range specified by BaseAddress and Length.
571 SmmSetMemoryAttributesEx (
572 IN UINTN PageTableBase
,
573 IN BOOLEAN EnablePML5Paging
,
574 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
576 IN UINT64 Attributes
,
577 OUT BOOLEAN
*IsSplitted OPTIONAL
583 Status
= ConvertMemoryPageAttributes (PageTableBase
, EnablePML5Paging
, BaseAddress
, Length
, Attributes
, TRUE
, IsSplitted
, &IsModified
);
584 if (!EFI_ERROR (Status
)) {
587 // Flush TLB as last step
597 This function clears the attributes for the memory region specified by BaseAddress and
598 Length from their current attributes to the attributes specified by Attributes.
600 @param[in] PageTableBase The page table base.
601 @param[in] EnablePML5Paging If PML5 paging is enabled.
602 @param[in] BaseAddress The physical address that is the start address of a memory region.
603 @param[in] Length The size in bytes of the memory region.
604 @param[in] Attributes The bit mask of attributes to clear for the memory region.
605 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
607 @retval EFI_SUCCESS The attributes were cleared for the memory region.
608 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
609 BaseAddress and Length cannot be modified.
610 @retval EFI_INVALID_PARAMETER Length is zero.
611 Attributes specified an illegal combination of attributes that
612 cannot be cleared together.
613 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
614 the memory resource range.
615 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
616 resource range specified by BaseAddress and Length.
617 The bit mask of attributes is not supported for the memory resource
618 range specified by BaseAddress and Length.
622 SmmClearMemoryAttributesEx (
623 IN UINTN PageTableBase
,
624 IN BOOLEAN EnablePML5Paging
,
625 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
627 IN UINT64 Attributes
,
628 OUT BOOLEAN
*IsSplitted OPTIONAL
634 Status
= ConvertMemoryPageAttributes (PageTableBase
, EnablePML5Paging
, BaseAddress
, Length
, Attributes
, FALSE
, IsSplitted
, &IsModified
);
635 if (!EFI_ERROR (Status
)) {
638 // Flush TLB as last step
648 This function sets the attributes for the memory region specified by BaseAddress and
649 Length from their current attributes to the attributes specified by Attributes.
651 @param[in] BaseAddress The physical address that is the start address of a memory region.
652 @param[in] Length The size in bytes of the memory region.
653 @param[in] Attributes The bit mask of attributes to set for the memory region.
655 @retval EFI_SUCCESS The attributes were set for the memory region.
656 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
657 BaseAddress and Length cannot be modified.
658 @retval EFI_INVALID_PARAMETER Length is zero.
659 Attributes specified an illegal combination of attributes that
660 cannot be set together.
661 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
662 the memory resource range.
663 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
664 resource range specified by BaseAddress and Length.
665 The bit mask of attributes is not supported for the memory resource
666 range specified by BaseAddress and Length.
670 SmmSetMemoryAttributes (
671 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
678 BOOLEAN Enable5LevelPaging
;
680 PageTableBase
= AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64
;
681 Cr4
.UintN
= AsmReadCr4 ();
682 Enable5LevelPaging
= (BOOLEAN
)(Cr4
.Bits
.LA57
== 1);
683 return SmmSetMemoryAttributesEx (PageTableBase
, Enable5LevelPaging
, BaseAddress
, Length
, Attributes
, NULL
);
687 This function clears the attributes for the memory region specified by BaseAddress and
688 Length from their current attributes to the attributes specified by Attributes.
690 @param[in] BaseAddress The physical address that is the start address of a memory region.
691 @param[in] Length The size in bytes of the memory region.
692 @param[in] Attributes The bit mask of attributes to clear for the memory region.
694 @retval EFI_SUCCESS The attributes were cleared for the memory region.
695 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
696 BaseAddress and Length cannot be modified.
697 @retval EFI_INVALID_PARAMETER Length is zero.
698 Attributes specified an illegal combination of attributes that
699 cannot be cleared together.
700 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
701 the memory resource range.
702 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
703 resource range specified by BaseAddress and Length.
704 The bit mask of attributes is not supported for the memory resource
705 range specified by BaseAddress and Length.
709 SmmClearMemoryAttributes (
710 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
717 BOOLEAN Enable5LevelPaging
;
719 PageTableBase
= AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64
;
720 Cr4
.UintN
= AsmReadCr4 ();
721 Enable5LevelPaging
= (BOOLEAN
)(Cr4
.Bits
.LA57
== 1);
722 return SmmClearMemoryAttributesEx (PageTableBase
, Enable5LevelPaging
, BaseAddress
, Length
, Attributes
, NULL
);
726 Set ShadowStack memory.
728 @param[in] Cr3 The page table base address.
729 @param[in] BaseAddress The physical address that is the start address of a memory region.
730 @param[in] Length The size in bytes of the memory region.
732 @retval EFI_SUCCESS The shadow stack memory is set.
737 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
743 mIsShadowStack
= TRUE
;
744 Status
= SmmSetMemoryAttributesEx (Cr3
, m5LevelPagingNeeded
, BaseAddress
, Length
, EFI_MEMORY_RO
, NULL
);
745 mIsShadowStack
= FALSE
;
751 Set not present memory.
753 @param[in] Cr3 The page table base address.
754 @param[in] BaseAddress The physical address that is the start address of a memory region.
755 @param[in] Length The size in bytes of the memory region.
757 @retval EFI_SUCCESS The not present memory is set.
762 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
768 Status
= SmmSetMemoryAttributesEx (Cr3
, m5LevelPagingNeeded
, BaseAddress
, Length
, EFI_MEMORY_RP
, NULL
);
773 Retrieves a pointer to the system configuration table from the SMM System Table
774 based on a specified GUID.
776 @param[in] TableGuid The pointer to table's GUID type.
777 @param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.
779 @retval EFI_SUCCESS A configuration table matching TableGuid was found.
780 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
785 SmmGetSystemConfigurationTable (
786 IN EFI_GUID
*TableGuid
,
792 ASSERT (TableGuid
!= NULL
);
793 ASSERT (Table
!= NULL
);
796 for (Index
= 0; Index
< gSmst
->NumberOfTableEntries
; Index
++) {
797 if (CompareGuid (TableGuid
, &(gSmst
->SmmConfigurationTable
[Index
].VendorGuid
))) {
798 *Table
= gSmst
->SmmConfigurationTable
[Index
].VendorTable
;
803 return EFI_NOT_FOUND
;
807 This function sets SMM save state buffer to be RW and XP.
810 PatchSmmSaveStateMap (
819 TileCodeSize
= GetSmiHandlerSize ();
820 TileCodeSize
= ALIGN_VALUE (TileCodeSize
, SIZE_4KB
);
821 TileDataSize
= (SMRAM_SAVE_STATE_MAP_OFFSET
- SMM_PSD_OFFSET
) + sizeof (SMRAM_SAVE_STATE_MAP
);
822 TileDataSize
= ALIGN_VALUE (TileDataSize
, SIZE_4KB
);
823 TileSize
= TileDataSize
+ TileCodeSize
- 1;
824 TileSize
= 2 * GetPowerOfTwo32 ((UINT32
)TileSize
);
826 DEBUG ((DEBUG_INFO
, "PatchSmmSaveStateMap:\n"));
827 for (Index
= 0; Index
< mMaxNumberOfCpus
- 1; Index
++) {
831 SmmSetMemoryAttributes (
832 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
836 SmmClearMemoryAttributes (
837 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
845 SmmClearMemoryAttributes (
846 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
847 TileSize
- TileCodeSize
,
850 SmmSetMemoryAttributes (
851 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
852 TileSize
- TileCodeSize
,
860 SmmSetMemoryAttributes (
861 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
865 SmmClearMemoryAttributes (
866 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
874 SmmClearMemoryAttributes (
875 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
876 SIZE_32KB
- TileCodeSize
,
879 SmmSetMemoryAttributes (
880 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
881 SIZE_32KB
- TileCodeSize
,
887 This function sets GDT/IDT buffer to be RO and XP.
894 EFI_PHYSICAL_ADDRESS BaseAddress
;
900 DEBUG ((DEBUG_INFO
, "PatchGdtIdtMap - GDT:\n"));
902 BaseAddress
= mGdtBuffer
;
903 Size
= ALIGN_VALUE (mGdtBufferSize
, SIZE_4KB
);
905 // The range should have been set to RO
906 // if it is allocated with EfiRuntimeServicesCode.
908 SmmSetMemoryAttributes (
917 DEBUG ((DEBUG_INFO
, "PatchGdtIdtMap - IDT:\n"));
919 BaseAddress
= gcSmiIdtr
.Base
;
920 Size
= ALIGN_VALUE (gcSmiIdtr
.Limit
+ 1, SIZE_4KB
);
922 // The range should have been set to RO
923 // if it is allocated with EfiRuntimeServicesCode.
925 SmmSetMemoryAttributes (
933 This function sets memory attribute according to MemoryAttributesTable.
936 SetMemMapAttributes (
940 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
941 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
942 UINTN MemoryMapEntryCount
;
943 UINTN DescriptorSize
;
945 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE
*MemoryAttributesTable
;
947 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid
, (VOID
**)&MemoryAttributesTable
);
948 if (MemoryAttributesTable
== NULL
) {
949 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable - NULL\n"));
953 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable:\n"));
954 DEBUG ((DEBUG_INFO
, " Version - 0x%08x\n", MemoryAttributesTable
->Version
));
955 DEBUG ((DEBUG_INFO
, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable
->NumberOfEntries
));
956 DEBUG ((DEBUG_INFO
, " DescriptorSize - 0x%08x\n", MemoryAttributesTable
->DescriptorSize
));
958 MemoryMapEntryCount
= MemoryAttributesTable
->NumberOfEntries
;
959 DescriptorSize
= MemoryAttributesTable
->DescriptorSize
;
960 MemoryMapStart
= (EFI_MEMORY_DESCRIPTOR
*)(MemoryAttributesTable
+ 1);
961 MemoryMap
= MemoryMapStart
;
962 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
963 DEBUG ((DEBUG_INFO
, "Entry (0x%x)\n", MemoryMap
));
964 DEBUG ((DEBUG_INFO
, " Type - 0x%x\n", MemoryMap
->Type
));
965 DEBUG ((DEBUG_INFO
, " PhysicalStart - 0x%016lx\n", MemoryMap
->PhysicalStart
));
966 DEBUG ((DEBUG_INFO
, " VirtualStart - 0x%016lx\n", MemoryMap
->VirtualStart
));
967 DEBUG ((DEBUG_INFO
, " NumberOfPages - 0x%016lx\n", MemoryMap
->NumberOfPages
));
968 DEBUG ((DEBUG_INFO
, " Attribute - 0x%016lx\n", MemoryMap
->Attribute
));
969 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
);
972 MemoryMap
= MemoryMapStart
;
973 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
974 DEBUG ((DEBUG_VERBOSE
, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap
->PhysicalStart
, MemoryMap
->NumberOfPages
));
975 switch (MemoryMap
->Type
) {
976 case EfiRuntimeServicesCode
:
977 SmmSetMemoryAttributes (
978 MemoryMap
->PhysicalStart
,
979 EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
),
983 case EfiRuntimeServicesData
:
984 SmmSetMemoryAttributes (
985 MemoryMap
->PhysicalStart
,
986 EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
),
991 SmmSetMemoryAttributes (
992 MemoryMap
->PhysicalStart
,
993 EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
),
999 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, DescriptorSize
);
1002 PatchSmmSaveStateMap ();
1009 Sort memory map entries based upon PhysicalStart, from low to high.
1011 @param MemoryMap A pointer to the buffer in which firmware places
1012 the current memory map.
1013 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
1014 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1019 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1020 IN UINTN MemoryMapSize
,
1021 IN UINTN DescriptorSize
1024 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
1025 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
1026 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1027 EFI_MEMORY_DESCRIPTOR TempMemoryMap
;
1029 MemoryMapEntry
= MemoryMap
;
1030 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1031 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MemoryMap
+ MemoryMapSize
);
1032 while (MemoryMapEntry
< MemoryMapEnd
) {
1033 while (NextMemoryMapEntry
< MemoryMapEnd
) {
1034 if (MemoryMapEntry
->PhysicalStart
> NextMemoryMapEntry
->PhysicalStart
) {
1035 CopyMem (&TempMemoryMap
, MemoryMapEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1036 CopyMem (MemoryMapEntry
, NextMemoryMapEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1037 CopyMem (NextMemoryMapEntry
, &TempMemoryMap
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1040 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1043 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1044 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1049 Return if a UEFI memory page should be marked as not present in SMM page table.
1050 If the memory map entries type is
1051 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1052 EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.
1055 @param[in] MemoryMap A pointer to the memory descriptor.
1057 @return TRUE The memory described will be marked as not present in SMM page table.
1058 @return FALSE The memory described will not be marked as not present in SMM page table.
1061 IsUefiPageNotPresent (
1062 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
1065 switch (MemoryMap
->Type
) {
1068 case EfiBootServicesCode
:
1069 case EfiBootServicesData
:
1070 case EfiConventionalMemory
:
1071 case EfiUnusableMemory
:
1072 case EfiACPIReclaimMemory
:
1080 Merge continuous memory map entries whose type is
1081 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1082 EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by
1083 these entries will be set as NOT present in SMM page table.
1085 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
1086 the current memory map.
1087 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
1088 MemoryMap buffer. On input, this is the size of
1089 the current memory map. On output,
1090 it is the size of new memory map after merge.
1091 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1095 MergeMemoryMapForNotPresentEntry (
1096 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1097 IN OUT UINTN
*MemoryMapSize
,
1098 IN UINTN DescriptorSize
1101 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
1102 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1103 UINT64 MemoryBlockLength
;
1104 EFI_MEMORY_DESCRIPTOR
*NewMemoryMapEntry
;
1105 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
1107 MemoryMapEntry
= MemoryMap
;
1108 NewMemoryMapEntry
= MemoryMap
;
1109 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MemoryMap
+ *MemoryMapSize
);
1110 while ((UINTN
)MemoryMapEntry
< (UINTN
)MemoryMapEnd
) {
1111 CopyMem (NewMemoryMapEntry
, MemoryMapEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1112 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1115 MemoryBlockLength
= (UINT64
)(EFI_PAGES_TO_SIZE ((UINTN
)MemoryMapEntry
->NumberOfPages
));
1116 if (((UINTN
)NextMemoryMapEntry
< (UINTN
)MemoryMapEnd
) &&
1117 IsUefiPageNotPresent (MemoryMapEntry
) && IsUefiPageNotPresent (NextMemoryMapEntry
) &&
1118 ((MemoryMapEntry
->PhysicalStart
+ MemoryBlockLength
) == NextMemoryMapEntry
->PhysicalStart
))
1120 MemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
1121 if (NewMemoryMapEntry
!= MemoryMapEntry
) {
1122 NewMemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
1125 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1128 MemoryMapEntry
= PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1133 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1134 NewMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry
, DescriptorSize
);
1137 *MemoryMapSize
= (UINTN
)NewMemoryMapEntry
- (UINTN
)MemoryMap
;
1143 This function caches the GCD memory map information.
1150 UINTN NumberOfDescriptors
;
1151 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemSpaceMap
;
1155 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemSpaceMap
);
1156 if (EFI_ERROR (Status
)) {
1160 mGcdMemNumberOfDesc
= 0;
1161 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
1162 if ((MemSpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeReserved
) &&
1163 ((MemSpaceMap
[Index
].Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
1164 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
))
1167 mGcdMemNumberOfDesc
++;
1171 mGcdMemSpace
= AllocateZeroPool (mGcdMemNumberOfDesc
* sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR
));
1172 ASSERT (mGcdMemSpace
!= NULL
);
1173 if (mGcdMemSpace
== NULL
) {
1174 mGcdMemNumberOfDesc
= 0;
1175 gBS
->FreePool (MemSpaceMap
);
1179 mGcdMemNumberOfDesc
= 0;
1180 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
1181 if ((MemSpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeReserved
) &&
1182 ((MemSpaceMap
[Index
].Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
1183 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
))
1187 &mGcdMemSpace
[mGcdMemNumberOfDesc
],
1188 &MemSpaceMap
[Index
],
1189 sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR
)
1191 mGcdMemNumberOfDesc
++;
1195 gBS
->FreePool (MemSpaceMap
);
1199 Get UEFI MemoryAttributesTable.
1202 GetUefiMemoryAttributesTable (
1207 EFI_MEMORY_ATTRIBUTES_TABLE
*MemoryAttributesTable
;
1208 UINTN MemoryAttributesTableSize
;
1210 Status
= EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid
, (VOID
**)&MemoryAttributesTable
);
1211 if (!EFI_ERROR (Status
) && (MemoryAttributesTable
!= NULL
)) {
1212 MemoryAttributesTableSize
= sizeof (EFI_MEMORY_ATTRIBUTES_TABLE
) + MemoryAttributesTable
->DescriptorSize
* MemoryAttributesTable
->NumberOfEntries
;
1213 mUefiMemoryAttributesTable
= AllocateCopyPool (MemoryAttributesTableSize
, MemoryAttributesTable
);
1214 ASSERT (mUefiMemoryAttributesTable
!= NULL
);
1219 This function caches the UEFI memory map information.
1228 UINT32 DescriptorVersion
;
1229 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1230 UINTN UefiMemoryMapSize
;
1232 DEBUG ((DEBUG_INFO
, "GetUefiMemoryMap\n"));
1234 UefiMemoryMapSize
= 0;
1236 Status
= gBS
->GetMemoryMap (
1240 &mUefiDescriptorSize
,
1243 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1246 Status
= gBS
->AllocatePool (EfiBootServicesData
, UefiMemoryMapSize
, (VOID
**)&MemoryMap
);
1247 ASSERT (MemoryMap
!= NULL
);
1248 if (MemoryMap
== NULL
) {
1252 Status
= gBS
->GetMemoryMap (
1256 &mUefiDescriptorSize
,
1259 if (EFI_ERROR (Status
)) {
1260 gBS
->FreePool (MemoryMap
);
1263 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1265 if (MemoryMap
== NULL
) {
1269 SortMemoryMap (MemoryMap
, UefiMemoryMapSize
, mUefiDescriptorSize
);
1270 MergeMemoryMapForNotPresentEntry (MemoryMap
, &UefiMemoryMapSize
, mUefiDescriptorSize
);
1272 mUefiMemoryMapSize
= UefiMemoryMapSize
;
1273 mUefiMemoryMap
= AllocateCopyPool (UefiMemoryMapSize
, MemoryMap
);
1274 ASSERT (mUefiMemoryMap
!= NULL
);
1276 gBS
->FreePool (MemoryMap
);
1279 // Get additional information from GCD memory map.
1284 // Get UEFI memory attributes table.
1286 GetUefiMemoryAttributesTable ();
1290 This function sets UEFI memory attribute according to UEFI memory map.
1292 The normal memory region is marked as not present, such as
1293 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1294 EfiUnusableMemory, EfiACPIReclaimMemory.
1297 SetUefiMemMapAttributes (
1302 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1303 UINTN MemoryMapEntryCount
;
1305 EFI_MEMORY_DESCRIPTOR
*Entry
;
1307 DEBUG ((DEBUG_INFO
, "SetUefiMemMapAttributes\n"));
1309 if (mUefiMemoryMap
!= NULL
) {
1310 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1311 MemoryMap
= mUefiMemoryMap
;
1312 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1313 if (IsUefiPageNotPresent (MemoryMap
)) {
1314 Status
= SmmSetMemoryAttributes (
1315 MemoryMap
->PhysicalStart
,
1316 EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
),
1321 "UefiMemory protection: 0x%lx - 0x%lx %r\n",
1322 MemoryMap
->PhysicalStart
,
1323 MemoryMap
->PhysicalStart
+ (UINT64
)EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
),
1328 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, mUefiDescriptorSize
);
1333 // Do not free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
1337 // Set untested memory as not present.
1339 if (mGcdMemSpace
!= NULL
) {
1340 for (Index
= 0; Index
< mGcdMemNumberOfDesc
; Index
++) {
1341 Status
= SmmSetMemoryAttributes (
1342 mGcdMemSpace
[Index
].BaseAddress
,
1343 mGcdMemSpace
[Index
].Length
,
1348 "GcdMemory protection: 0x%lx - 0x%lx %r\n",
1349 mGcdMemSpace
[Index
].BaseAddress
,
1350 mGcdMemSpace
[Index
].BaseAddress
+ mGcdMemSpace
[Index
].Length
,
1357 // Do not free mGcdMemSpace, it will be checked in IsSmmCommBufferForbiddenAddress().
1361 // Set UEFI runtime memory with EFI_MEMORY_RO as not present.
1363 if (mUefiMemoryAttributesTable
!= NULL
) {
1364 Entry
= (EFI_MEMORY_DESCRIPTOR
*)(mUefiMemoryAttributesTable
+ 1);
1365 for (Index
= 0; Index
< mUefiMemoryAttributesTable
->NumberOfEntries
; Index
++) {
1366 if ((Entry
->Type
== EfiRuntimeServicesCode
) || (Entry
->Type
== EfiRuntimeServicesData
)) {
1367 if ((Entry
->Attribute
& EFI_MEMORY_RO
) != 0) {
1368 Status
= SmmSetMemoryAttributes (
1369 Entry
->PhysicalStart
,
1370 EFI_PAGES_TO_SIZE ((UINTN
)Entry
->NumberOfPages
),
1375 "UefiMemoryAttribute protection: 0x%lx - 0x%lx %r\n",
1376 Entry
->PhysicalStart
,
1377 Entry
->PhysicalStart
+ (UINT64
)EFI_PAGES_TO_SIZE ((UINTN
)Entry
->NumberOfPages
),
1383 Entry
= NEXT_MEMORY_DESCRIPTOR (Entry
, mUefiMemoryAttributesTable
->DescriptorSize
);
1388 // Do not free mUefiMemoryAttributesTable, it will be checked in IsSmmCommBufferForbiddenAddress().
1393 Return if the Address is forbidden as SMM communication buffer.
1395 @param[in] Address the address to be checked
1397 @return TRUE The address is forbidden as SMM communication buffer.
1398 @return FALSE The address is allowed as SMM communication buffer.
1401 IsSmmCommBufferForbiddenAddress (
1405 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1406 UINTN MemoryMapEntryCount
;
1408 EFI_MEMORY_DESCRIPTOR
*Entry
;
1410 if (mUefiMemoryMap
!= NULL
) {
1411 MemoryMap
= mUefiMemoryMap
;
1412 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1413 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1414 if (IsUefiPageNotPresent (MemoryMap
)) {
1415 if ((Address
>= MemoryMap
->PhysicalStart
) &&
1416 (Address
< MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE ((UINTN
)MemoryMap
->NumberOfPages
)))
1422 MemoryMap
= NEXT_MEMORY_DESCRIPTOR (MemoryMap
, mUefiDescriptorSize
);
1426 if (mGcdMemSpace
!= NULL
) {
1427 for (Index
= 0; Index
< mGcdMemNumberOfDesc
; Index
++) {
1428 if ((Address
>= mGcdMemSpace
[Index
].BaseAddress
) &&
1429 (Address
< mGcdMemSpace
[Index
].BaseAddress
+ mGcdMemSpace
[Index
].Length
))
1436 if (mUefiMemoryAttributesTable
!= NULL
) {
1437 Entry
= (EFI_MEMORY_DESCRIPTOR
*)(mUefiMemoryAttributesTable
+ 1);
1438 for (Index
= 0; Index
< mUefiMemoryAttributesTable
->NumberOfEntries
; Index
++) {
1439 if ((Entry
->Type
== EfiRuntimeServicesCode
) || (Entry
->Type
== EfiRuntimeServicesData
)) {
1440 if ((Entry
->Attribute
& EFI_MEMORY_RO
) != 0) {
1441 if ((Address
>= Entry
->PhysicalStart
) &&
1442 (Address
< Entry
->PhysicalStart
+ LShiftU64 (Entry
->NumberOfPages
, EFI_PAGE_SHIFT
)))
1447 Entry
= NEXT_MEMORY_DESCRIPTOR (Entry
, mUefiMemoryAttributesTable
->DescriptorSize
);
1457 This function set given attributes of the memory region specified by
1458 BaseAddress and Length.
1460 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1461 @param BaseAddress The physical address that is the start address of
1463 @param Length The size in bytes of the memory region.
1464 @param Attributes The bit mask of attributes to set for the memory
1467 @retval EFI_SUCCESS The attributes were set for the memory region.
1468 @retval EFI_INVALID_PARAMETER Length is zero.
1469 Attributes specified an illegal combination of
1470 attributes that cannot be set together.
1471 @retval EFI_UNSUPPORTED The processor does not support one or more
1472 bytes of the memory resource range specified
1473 by BaseAddress and Length.
1474 The bit mask of attributes is not supported for
1475 the memory resource range specified by
1476 BaseAddress and Length.
1481 EdkiiSmmSetMemoryAttributes (
1482 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1483 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1485 IN UINT64 Attributes
1488 return SmmSetMemoryAttributes (BaseAddress
, Length
, Attributes
);
1492 This function clears given attributes of the memory region specified by
1493 BaseAddress and Length.
1495 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1496 @param BaseAddress The physical address that is the start address of
1498 @param Length The size in bytes of the memory region.
1499 @param Attributes The bit mask of attributes to clear for the memory
1502 @retval EFI_SUCCESS The attributes were cleared for the memory region.
1503 @retval EFI_INVALID_PARAMETER Length is zero.
1504 Attributes specified an illegal combination of
1505 attributes that cannot be cleared together.
1506 @retval EFI_UNSUPPORTED The processor does not support one or more
1507 bytes of the memory resource range specified
1508 by BaseAddress and Length.
1509 The bit mask of attributes is not supported for
1510 the memory resource range specified by
1511 BaseAddress and Length.
1516 EdkiiSmmClearMemoryAttributes (
1517 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1518 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1520 IN UINT64 Attributes
1523 return SmmClearMemoryAttributes (BaseAddress
, Length
, Attributes
);
1527 This function retrieves the attributes of the memory region specified by
1528 BaseAddress and Length. If different attributes are got from different part
1529 of the memory region, EFI_NO_MAPPING will be returned.
1531 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1532 @param BaseAddress The physical address that is the start address of
1534 @param Length The size in bytes of the memory region.
1535 @param Attributes Pointer to attributes returned.
1537 @retval EFI_SUCCESS The attributes got for the memory region.
1538 @retval EFI_INVALID_PARAMETER Length is zero.
1540 @retval EFI_NO_MAPPING Attributes are not consistent cross the memory
1542 @retval EFI_UNSUPPORTED The processor does not support one or more
1543 bytes of the memory resource range specified
1544 by BaseAddress and Length.
1549 EdkiiSmmGetMemoryAttributes (
1550 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1551 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1553 OUT UINT64
*Attributes
1556 EFI_PHYSICAL_ADDRESS Address
;
1559 PAGE_ATTRIBUTE PageAttr
;
1561 UINTN PageTableBase
;
1562 BOOLEAN EnablePML5Paging
;
1565 if ((Length
< SIZE_4KB
) || (Attributes
== NULL
)) {
1566 return EFI_INVALID_PARAMETER
;
1569 Size
= (INT64
)Length
;
1570 MemAttr
= (UINT64
)-1;
1572 PageTableBase
= AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64
;
1573 Cr4
.UintN
= AsmReadCr4 ();
1574 EnablePML5Paging
= (BOOLEAN
)(Cr4
.Bits
.LA57
== 1);
1577 PageEntry
= GetPageTableEntry (PageTableBase
, EnablePML5Paging
, BaseAddress
, &PageAttr
);
1578 if ((PageEntry
== NULL
) || (PageAttr
== PageNone
)) {
1579 return EFI_UNSUPPORTED
;
1583 // If the memory range is cross page table boundary, make sure they
1584 // share the same attribute. Return EFI_NO_MAPPING if not.
1586 *Attributes
= GetAttributesFromPageEntry (PageEntry
);
1587 if ((MemAttr
!= (UINT64
)-1) && (*Attributes
!= MemAttr
)) {
1588 return EFI_NO_MAPPING
;
1593 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
;
1594 Size
-= (SIZE_4KB
- (BaseAddress
- Address
));
1595 BaseAddress
+= (SIZE_4KB
- (BaseAddress
- Address
));
1599 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_2M_ADDRESS_MASK_64
;
1600 Size
-= SIZE_2MB
- (BaseAddress
- Address
);
1601 BaseAddress
+= SIZE_2MB
- (BaseAddress
- Address
);
1605 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_1G_ADDRESS_MASK_64
;
1606 Size
-= SIZE_1GB
- (BaseAddress
- Address
);
1607 BaseAddress
+= SIZE_1GB
- (BaseAddress
- Address
);
1611 return EFI_UNSUPPORTED
;
1614 MemAttr
= *Attributes
;